diff --git a/Include/Library/OcMemoryLib.h b/Include/Library/OcMemoryLib.h index 13eabbc1..8b6d1acb 100644 --- a/Include/Library/OcMemoryLib.h +++ b/Include/Library/OcMemoryLib.h @@ -141,12 +141,12 @@ AllocatePagesFromTop ( /** Return pointer to PML4 table in PageTable and PWT and PCD flags in Flags. - @param[out] PageTable Current page table address. @param[out] Flags Current page table PWT and PCT flags. + + @retval Current page table address. **/ -VOID +PAGE_MAP_AND_DIRECTORY_POINTER * GetCurrentPageTable ( - OUT PAGE_MAP_AND_DIRECTORY_POINTER **PageTable, OUT UINTN *Flags OPTIONAL ); diff --git a/Library/OcAppleBootCompatLib/BootCompatInternal.h b/Library/OcAppleBootCompatLib/BootCompatInternal.h index 971c4c46..d5332bfe 100644 --- a/Library/OcAppleBootCompatLib/BootCompatInternal.h +++ b/Library/OcAppleBootCompatLib/BootCompatInternal.h @@ -40,10 +40,14 @@ #define RT_DESC_ENTRY_NUM ((UINTN) 64) /** - Base kernel address. + Kernel __HIB segment virtual address. **/ -#define BASE_KERNEL_ADDR ((UINTN)0x100000) +#define KERNEL_HIB_VADDR ((UINTN)0xFFFFFF8000100000ULL) +/** + Kernel __TEXT segment virtual address. +**/ +#define KERNEL_TEXT_VADDR ((UINTN)0xFFFFFF8000200000ULL) /** Slide offset per slide entry **/ @@ -54,6 +58,20 @@ **/ #define TOTAL_SLIDE_NUM 256 +/** + Get last descriptor address. + It is assumed that the descriptor contains pages. +**/ +#define LAST_DESCRIPTOR_ADDR(Desc) \ + ((Desc)->PhysicalStart + (EFI_PAGES_TO_SIZE ((UINTN) (Desc)->NumberOfPages) - 1)) + +/** + Check if area is within the specified descriptor. + It is assumed that the descriptor contains pages and AreaSize is not 0. +**/ +#define AREA_WITHIN_DESCRIPTOR(Desc, Area, AreaSize) \ + ((Area) >= (Desc)->PhysicalStart && ((Area) + ((AreaSize) - 1)) <= LAST_DESCRIPTOR_ADDR (Desc)) + /** Preserved relocation entry. **/ @@ -183,6 +201,10 @@ typedef struct KERNEL_SUPPORT_STATE_ { /// EFI_PHYSICAL_ADDRESS SysTableRtArea; /// + /// Custom kernel UEFI System Table size in bytes. + /// + UINTN SysTableRtAreaSize; + /// /// Virtual memory mapper context. /// OC_VMEM_CONTEXT VmContext; diff --git a/Library/OcAppleBootCompatLib/KernelSupport.c b/Library/OcAppleBootCompatLib/KernelSupport.c index 87b92782..85e87a89 100644 --- a/Library/OcAppleBootCompatLib/KernelSupport.c +++ b/Library/OcAppleBootCompatLib/KernelSupport.c @@ -46,7 +46,8 @@ ProtectRtMemoryFromRelocation ( IN UINTN MemoryMapSize, IN UINTN DescriptorSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, - IN EFI_PHYSICAL_ADDRESS SysTableArea + IN EFI_PHYSICAL_ADDRESS SysTableArea, + IN UINTN SysTableAreaSize ) { // @@ -87,19 +88,16 @@ ProtectRtMemoryFromRelocation ( EFI_MEMORY_DESCRIPTOR *Desc; RT_RELOC_PROTECT_INFO *RelocInfo; + Desc = MemoryMap; RtReloc->NumEntries = 0; RelocInfo = &RtReloc->RelocInfo[0]; NumEntries = MemoryMapSize / DescriptorSize; for (Index = 0; Index < NumEntries; ++Index) { - if ((Desc->Attribute & EFI_MEMORY_RUNTIME) == 0 - || Desc->NumberOfPages == 0) { - continue; - } - - if (Desc->Type == EfiRuntimeServicesCode - || (Desc->Type == EfiRuntimeServicesData - && Desc->PhysicalStart != SysTableArea)) { + if ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0 + && Desc->NumberOfPages > 0 + && (Desc->Type == EfiRuntimeServicesCode || Desc->Type == EfiRuntimeServicesData) + && !AREA_WITHIN_DESCRIPTOR (Desc, SysTableArea, SysTableAreaSize)) { if (RtReloc->NumEntries == ARRAY_SIZE (RtReloc->RelocInfo)) { RUNTIME_DEBUG (( @@ -112,7 +110,7 @@ ProtectRtMemoryFromRelocation ( } RelocInfo->PhysicalStart = Desc->PhysicalStart; - RelocInfo->PhysicalEnd = Desc->PhysicalStart + (EFI_PAGES_TO_SIZE (Desc->NumberOfPages) - 1); + RelocInfo->PhysicalEnd = LAST_DESCRIPTOR_ADDR (Desc); RelocInfo->Type = Desc->Type; Desc->Type = EfiMemoryMappedIO; ++RelocInfo; @@ -170,7 +168,6 @@ PerformRtMemoryVirtualMapping ( EFI_MEMORY_DESCRIPTOR *VirtualDesc; EFI_STATUS Status; PAGE_MAP_AND_DIRECTORY_POINTER *PageTable; - UINTN Flags; Desc = MemoryMap; NumEntries = MemoryMapSize / DescriptorSize; @@ -179,27 +176,27 @@ PerformRtMemoryVirtualMapping ( KernelState->VmMapDescSize = DescriptorSize; // - // Get current VM page table + // Get current VM page table. // - GetCurrentPageTable (&PageTable, &Flags); + PageTable = GetCurrentPageTable (NULL); for (Index = 0; Index < NumEntries; ++Index) { // - // Some UEFIs end up with "reserved" area with EFI_MEMORY_RUNTIME flag set when Intel HD3000 or HD4000 is used. - // For example, on GA-H81N-D2H there is a single 1 GB descriptor: + // Legacy note. Some UEFIs end up with "reserved" area with EFI_MEMORY_RUNTIME flag set when + // Intel HD3000 or HD4000 is used. For example, on GA-H81N-D2H there is a single 1 GB descriptor: // 000000009F800000-00000000DF9FFFFF 0000000000040200 8000000000000000 // - // All known boot.efi starting from at least 10.5.8 properly handle this flag and do not assign virtual addresses - // to reserved descriptors. - // However, the issue was with AptioFix itself, which did not check for EfiReservedMemoryType and replaced - // it by EfiMemoryMappedIO to prevent boot.efi relocations. + // All known boot.efi starting from at least 10.5.8 properly handle this flag and do not assign + // virtual addresses to reserved descriptors. However, our legacy code had a bug, and did not + // check for EfiReservedMemoryType. Therefore it replaced such entries by EfiMemoryMappedIO + // to "prevent" boot.efi relocations. // // The relevant discussion and the original fix can be found here: // http://web.archive.org/web/20141111124211/http://www.projectosx.com:80/forum/lofiversion/index.php/t2428-450.html // https://sourceforge.net/p/cloverefiboot/code/605/ // - // Since it is not the bug in boot.efi, AptioMemoryFix only needs to properly handle EfiReservedMemoryType with - // EFI_MEMORY_RUNTIME attribute set, and there is no reason to mess with the memory map passed to boot.efi. + // The correct approach is to properly handle EfiReservedMemoryType with EFI_MEMORY_RUNTIME + // attribute set, and not mess with the memory map passed to boot.efi. As done here. // if (Desc->Type != EfiReservedMemoryType && (Desc->Attribute & EFI_MEMORY_RUNTIME) != 0) { // @@ -279,16 +276,14 @@ RestoreProtectedRtMemoryTypes ( EFI_PHYSICAL_ADDRESS PhysicalStart; EFI_PHYSICAL_ADDRESS PhysicalEnd; EFI_MEMORY_DESCRIPTOR *Desc; - BOOLEAN Found; NumEntriesLeft = RtReloc->NumEntries; NumEntries = MemoryMapSize / DescriptorSize; Desc = MemoryMap; for (Index = 0; Index < NumEntries && NumEntriesLeft > 0; ++Index) { - Found = FALSE; PhysicalStart = Desc->PhysicalStart; - PhysicalEnd = PhysicalStart + (EFI_PAGES_TO_SIZE (Desc->NumberOfPages) - 1); + PhysicalEnd = LAST_DESCRIPTOR_ADDR (Desc); for (Index2 = 0; Index2 < RtReloc->NumEntries; ++Index2) { // @@ -299,14 +294,11 @@ RestoreProtectedRtMemoryTypes ( if (PhysicalStart <= RtReloc->RelocInfo[Index2].PhysicalEnd && RtReloc->RelocInfo[Index2].PhysicalStart <= PhysicalEnd) { Desc->Type = RtReloc->RelocInfo[Index2].Type; - Found = TRUE; + --NumEntriesLeft; + break; } } - if (Found) { - --NumEntriesLeft; - } - Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize); } @@ -415,14 +407,14 @@ AppleMapPrepareForHibernateWake ( // if (BootCompat->KernelState.VmMapDescSize == 0) { - RUNTIME_DEBUG (("OCABC: Saved descriptor size cannot be 0\n")); - BootCompat->KernelState.VmMapDescSize = sizeof (EFI_MEMORY_DESCRIPTOR); + RUNTIME_DEBUG ((DEBUG_ERROR, "OCABC: Saved descriptor size cannot be 0\n")); + return; } RestoreProtectedRtMemoryTypes ( &BootCompat->RtReloc, Handoff->bytecount, - MIN (BootCompat->KernelState.VmMapDescSize, sizeof (EFI_MEMORY_DESCRIPTOR)), + BootCompat->KernelState.VmMapDescSize, (EFI_MEMORY_DESCRIPTOR *)(UINTN) Handoff->data ); } @@ -470,15 +462,16 @@ AppleMapPrepareBooterState ( ); // - // Allocate 1 RT data page for copy of UEFI system table for kernel. + // Allocate RT data pages for copy of UEFI system table for kernel. // This one also has to be 32-bit due to XNU BootArgs structure. // The reason for this allocation to be required is because XNU uses static // mapping for directly passed pointers (see ProtectRtMemoryFromRelocation). // - BootCompat->KernelState.SysTableRtArea = BASE_4GB; + BootCompat->KernelState.SysTableRtArea = BASE_4GB; + BootCompat->KernelState.SysTableRtAreaSize = gST->Hdr.HeaderSize; Status = AllocatePagesFromTop ( EfiRuntimeServicesData, - 1, + EFI_SIZE_TO_PAGES (gST->Hdr.HeaderSize), &BootCompat->KernelState.SysTableRtArea, GetMemoryMap, NULL @@ -496,17 +489,10 @@ AppleMapPrepareBooterState ( // // Copy UEFI system table to the new location. // - if (gST->Hdr.HeaderSize > EFI_PAGE_SIZE) { - DEBUG (( - DEBUG_ERROR, - "OCABC: EFI_SYSTEM_TABLE is too large - %u bytes\n", - (UINT32) gST->Hdr.HeaderSize - )); - } CopyMem ( (VOID *)(UINTN) BootCompat->KernelState.SysTableRtArea, gST, - MIN (gST->Hdr.HeaderSize, EFI_PAGE_SIZE) + gST->Hdr.HeaderSize ); } @@ -524,43 +510,51 @@ AppleMapPrepareKernelJump ( IN BOOLEAN AppleHibernateWake ) { - UINT8 *KernelEntry; - UINTN SlideAddr; - VOID *MachOImage; + UINTN KernelEntryVaddr; + UINT32 KernelEntry; IOHibernateImageHeader *ImageHeader; if (!AppleHibernateWake) { // - // Read kernel entry from Mach-O load command and patch it with jump. + // ImageAddress points to the first kernel segment, __HIB. + // Kernel image header is located in __TEXT, which follows __HIB. // - SlideAddr = ImageAddress - BASE_KERNEL_ADDR; - MachOImage = (VOID*) (SlideAddr + SLIDE_GRANULARITY); - KernelEntry = (UINT8*) MachoRuntimeGetEntryAddress (MachOImage); - if (KernelEntry != 0) { - KernelEntry += SlideAddr; + ImageAddress += KERNEL_TEXT_VADDR - KERNEL_HIB_VADDR; + + // + // Cut higher virtual address bits. + // + KernelEntryVaddr = MachoRuntimeGetEntryAddress ( + (VOID*) ImageAddress + ); + if (KernelEntryVaddr == 0) { + RUNTIME_DEBUG ((DEBUG_ERROR, "Kernel entry point was not found!")); + return; } + + // + // Perform virtual to physical address conversion by subtracting __TEXT base + // and adding current physical kernel location. + // + KernelEntry = (UINT32) (KernelEntryVaddr - KERNEL_TEXT_VADDR + ImageAddress); } else { // // Read kernel entry from hibernation image and patch it with jump. // At this stage HIB section is not yet copied from sleep image to it's // proper memory destination. so we'll patch entry point in sleep image. + // Note the virtual -> physical conversion through truncation. // ImageHeader = (IOHibernateImageHeader *) ImageAddress; - KernelEntry = (UINT8 *) &ImageHeader->fileExtentMap[0] + KernelEntry = ((UINT32)(UINTN) &ImageHeader->fileExtentMap[0]) + ImageHeader->fileExtentMapSize + ImageHeader->restore1CodeOffset; } - if (KernelEntry == 0) { - RUNTIME_DEBUG ((DEBUG_ERROR, "KernelEntry must be found!")); - return; - } - // // Save original kernel entry code. // CopyMem ( &BootCompat->KernelState.KernelOrg[0], - KernelEntry, + (VOID *)(UINTN) KernelEntry, sizeof (BootCompat->KernelState.KernelOrg) ); @@ -568,7 +562,7 @@ AppleMapPrepareKernelJump ( // Copy kernel jump code to kernel entry address. // CopyMem ( - KernelEntry, + (VOID *)(UINTN) KernelEntry, &BootCompat->KernelState.KernelJump, sizeof (BootCompat->KernelState.KernelJump) ); @@ -593,7 +587,8 @@ AppleMapPrepareVmState ( MemoryMapSize, DescriptorSize, MemoryMap, - BootCompat->KernelState.SysTableRtArea + BootCompat->KernelState.SysTableRtArea, + BootCompat->KernelState.SysTableRtAreaSize ); // diff --git a/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c b/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c index 697e1565..4dba0a4b 100644 --- a/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c +++ b/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c @@ -99,16 +99,23 @@ OcAbcInitialize ( IN OC_ABC_SETTINGS *Settings ) { - EFI_STATUS Status; + EFI_STATUS Status; + BOOT_COMPAT_CONTEXT *BootCompat; Status = InstallAbcProtocol (); if (EFI_ERROR (Status)) { return Status; } - InstallServiceOverrides ( - GetBootCompatContext () + BootCompat = GetBootCompatContext (); + + CopyMem ( + &BootCompat->Settings, + Settings, + sizeof (BootCompat->Settings) ); + InstallServiceOverrides (BootCompat); + return EFI_SUCCESS; } diff --git a/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf b/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf index 2a96218b..7dcd539f 100644 --- a/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf +++ b/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf @@ -50,6 +50,7 @@ [Protocols] gOcAppleBootCompatProtocolGuid ## PRODUCES + gOcFirmwareRuntimeProtocolGuid ## SOMETIMES_CONSUMES [LibraryClasses] BaseLib diff --git a/Library/OcAppleBootCompatLib/X64/ContextSwitch.h b/Library/OcAppleBootCompatLib/X64/ContextSwitch.h index 64ed335b..c1588359 100644 --- a/Library/OcAppleBootCompatLib/X64/ContextSwitch.h +++ b/Library/OcAppleBootCompatLib/X64/ContextSwitch.h @@ -20,13 +20,15 @@ // Keep these definitions in sync with ContextSwitch.nasm! // +#pragma pack(push, 1) + /** Assembly support state. This state is used as an intermediate structure to hold UEFI environment context and kernel environment context for switching between 32-bit and 64-bit modes during booting as normal XNU boot still happens in 32-bit. **/ -typedef struct ASM_SUPPORT_STATE_ { +typedef PACKED struct ASM_SUPPORT_STATE_ { UINT64 SavedGDTR; UINT16 SavedGDTRLimit; UINT64 SavedIDTR; @@ -60,12 +62,14 @@ typedef struct ASM_SUPPORT_STATE_ { code to UEFI code through AsmAppleMapPlatformPrepareKernelState intermediate handler. **/ -typedef struct ASM_KERNEL_JUMP_ { +typedef PACKED struct ASM_KERNEL_JUMP_ { UINT8 MovInst; UINT32 Addr; UINT16 CallInst; } ASM_KERNEL_JUMP; +#pragma pack(pop) + VOID EFIAPI AsmAppleMapPlatformSaveState ( diff --git a/Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm b/Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm index c2e89606..b75b4584 100755 --- a/Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm +++ b/Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm @@ -88,8 +88,8 @@ SECTION .text ; ); ;------------------------------------------------------------------------------ align 8 -global ASM_PFX(AsmAppleMapSaveState) -ASM_PFX(AsmAppleMapSaveState): +global ASM_PFX(AsmAppleMapPlatformSaveState) +ASM_PFX(AsmAppleMapPlatformSaveState): BITS 64 sgdt [rcx + ASM_SUPPORT_STATE.SavedGDTR] sidt [rcx + ASM_SUPPORT_STATE.SavedIDTR] diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index ecc10e72..fbca1b64 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -651,7 +651,7 @@ OcIsAppleHibernateWake ( } } - return TRUE; + return FALSE; } EFI_STATUS diff --git a/Library/OcMemoryLib/VirtualMemory.c b/Library/OcMemoryLib/VirtualMemory.c index a6642d29..439de33e 100755 --- a/Library/OcMemoryLib/VirtualMemory.c +++ b/Library/OcMemoryLib/VirtualMemory.c @@ -20,21 +20,23 @@ #include #include -VOID +PAGE_MAP_AND_DIRECTORY_POINTER * GetCurrentPageTable ( - OUT PAGE_MAP_AND_DIRECTORY_POINTER **PageTable, OUT UINTN *Flags OPTIONAL ) { - UINTN CR3; + PAGE_MAP_AND_DIRECTORY_POINTER *PageTable; + UINTN CR3; CR3 = AsmReadCr3 (); - *PageTable = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN) (CR3 & CR3_ADDR_MASK); + PageTable = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN) (CR3 & CR3_ADDR_MASK); if (Flags != NULL) { *Flags = CR3 & (CR3_FLAG_PWT | CR3_FLAG_PCD); } + + return PageTable; } EFI_STATUS @@ -56,7 +58,7 @@ GetPhysicalAddress ( PAGE_TABLE_1G_ENTRY *PTE1G; if (PageTable == NULL) { - GetCurrentPageTable (&PageTable, NULL); + PageTable = GetCurrentPageTable (NULL); } VA.Uint64 = (UINT64) VirtualAddr; @@ -206,7 +208,7 @@ VmMapVirtualPage ( UINTN Index; if (PageTable == NULL) { - GetCurrentPageTable (&PageTable, NULL); + PageTable = GetCurrentPageTable (NULL); } VA.Uint64 = (UINT64) VirtualAddr; @@ -381,7 +383,7 @@ VmMapVirtualPages ( EFI_STATUS Status; if (PageTable == NULL) { - GetCurrentPageTable (&PageTable, NULL); + PageTable = GetCurrentPageTable (NULL); } Status = EFI_SUCCESS;