mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcAppleBootCompatLib: Initial set of fixes
This commit is contained in:
parent
7eca596604
commit
2e6030e5a3
@ -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
|
||||
);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
|
||||
[Protocols]
|
||||
gOcAppleBootCompatProtocolGuid ## PRODUCES
|
||||
gOcFirmwareRuntimeProtocolGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -651,7 +651,7 @@ OcIsAppleHibernateWake (
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
|
||||
@ -20,21 +20,23 @@
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcMemoryLib.h>
|
||||
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user