mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2026-02-01 15:59:39 +00:00
OcAppleBootCompatLib: Initial working prototype
This commit is contained in:
parent
2e496a992d
commit
9027bd6be1
@ -155,10 +155,6 @@ typedef struct SERVICES_OVERRIDE_STATE_ {
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS MinAllocatedAddr;
|
||||
///
|
||||
/// Maximum address allocated by AlocatePages.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS MaxAllocatedAddr;
|
||||
///
|
||||
/// Apple hibernate image address allocated by AlocatePages.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS HibernateImageAddress;
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
#include "BootCompatInternal.h"
|
||||
|
||||
#include <Guid/OcVariables.h>
|
||||
#include <IndustryStandard/AppleHibernate.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <Library/OcMemoryLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Protocol/OcFirmwareRuntime.h>
|
||||
@ -104,6 +105,63 @@ ForceExitBootServices (
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Protect CSM region in memory map from relocation.
|
||||
|
||||
@param[in,out] MemoryMapSize Memory map size in bytes, updated on shrink.
|
||||
@param[in,out] MemoryMap Memory map to shrink.
|
||||
@param[in] DescriptorSize Memory map descriptor size in bytes.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
ProtectCsmRegion (
|
||||
IN UINTN MemoryMapSize,
|
||||
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
||||
IN UINTN DescriptorSize
|
||||
)
|
||||
{
|
||||
UINTN NumEntries;
|
||||
UINTN Index;
|
||||
EFI_MEMORY_DESCRIPTOR *Desc;
|
||||
UINTN PhysicalEnd;
|
||||
|
||||
//
|
||||
// AMI CSM module allocates up to two regions for legacy video output.
|
||||
// 1. For PMM and EBDA areas.
|
||||
// On Ivy Bridge and below it ends at 0xA0000-0x1000-0x1 and has EfiBootServicesCode type.
|
||||
// On Haswell and above it is allocated below 0xA0000 address with the same type.
|
||||
// 2. For Intel RC S3 reserved area, fixed from 0x9F000 to 0x9FFFF.
|
||||
// On Sandy Bridge and below it is not present in memory map.
|
||||
// On Ivy Bridge and newer it is present as EfiRuntimeServicesData.
|
||||
// Starting from at least SkyLake it is present as EfiReservedMemoryType.
|
||||
//
|
||||
// Prior to AptioMemoryFix EfiRuntimeServicesData could have been relocated by boot.efi,
|
||||
// and the 2nd region could have been overwritten by the kernel. Now it is no longer the
|
||||
// case, and only the 1st region may need special handling.
|
||||
// For the 1st region there appear to be (unconfirmed) reports that it may still be accessed
|
||||
// after waking from sleep. This does not seem to be valid according to AMI code, but we still
|
||||
// protect it in case such systems really exist.
|
||||
//
|
||||
// Initially researched and fixed on GIGABYTE boards by Slice.
|
||||
//
|
||||
|
||||
Desc = MemoryMap;
|
||||
NumEntries = MemoryMapSize / DescriptorSize;
|
||||
|
||||
for (Index = 0; Index < NumEntries; ++Index) {
|
||||
if (Desc->NumberOfPages > 0 && Desc->Type == EfiBootServicesData) {
|
||||
PhysicalEnd = LAST_DESCRIPTOR_ADDR (Desc) + 1;
|
||||
|
||||
if (PhysicalEnd >= 0x9E000 && PhysicalEnd < 0xA0000) {
|
||||
Desc->Type = EfiACPIMemoryNVS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Boot Services StartImage override. Called to start an efi image.
|
||||
If this is boot.efi, then our overrides are enabled.
|
||||
@ -128,7 +186,6 @@ OcStartImage (
|
||||
// Clear monitoring vars
|
||||
//
|
||||
BootCompat->ServiceState.MinAllocatedAddr = 0;
|
||||
BootCompat->ServiceState.MaxAllocatedAddr = 0;
|
||||
|
||||
if (AppleLoadedImage != NULL) {
|
||||
//
|
||||
@ -191,7 +248,6 @@ OcAllocatePages (
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS UpperAddr;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
@ -206,22 +262,13 @@ OcAllocatePages (
|
||||
if (!EFI_ERROR (Status) && BootCompat->ServiceState.AppleBootNestedCount > 0) {
|
||||
if (Type == AllocateAddress && MemoryType == EfiLoaderData) {
|
||||
//
|
||||
// Called from boot.efi
|
||||
//
|
||||
UpperAddr = *Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
|
||||
|
||||
//
|
||||
// Store min and max mem: they can be used later to determine
|
||||
// start and end of kernel boot or hibernation images.
|
||||
// Called from boot.efi.
|
||||
// Store minimally allocated address to find kernel image start.
|
||||
//
|
||||
if (BootCompat->ServiceState.MinAllocatedAddr == 0
|
||||
|| *Memory < BootCompat->ServiceState.MinAllocatedAddr) {
|
||||
BootCompat->ServiceState.MinAllocatedAddr = *Memory;
|
||||
}
|
||||
|
||||
if (UpperAddr > BootCompat->ServiceState.MaxAllocatedAddr) {
|
||||
BootCompat->ServiceState.MaxAllocatedAddr = UpperAddr;
|
||||
}
|
||||
} else if (BootCompat->ServiceState.AppleHibernateWake
|
||||
&& Type == AllocateAnyPages && MemoryType == EfiLoaderData
|
||||
&& BootCompat->ServiceState.HibernateImageAddress == 0) {
|
||||
@ -271,12 +318,11 @@ OcGetMemoryMap (
|
||||
|
||||
if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
|
||||
if (BootCompat->Settings.ProtectCsmRegion) {
|
||||
// FIXME: Implement.
|
||||
//ProtectCsmRegion (
|
||||
// *MemoryMapSize,
|
||||
// MemoryMap,
|
||||
// *DescriptorSize
|
||||
// );
|
||||
ProtectCsmRegion (
|
||||
*MemoryMapSize,
|
||||
MemoryMap,
|
||||
*DescriptorSize
|
||||
);
|
||||
}
|
||||
|
||||
if (BootCompat->Settings.ShrinkMemoryMap) {
|
||||
@ -504,9 +550,12 @@ InstallServiceOverrides (
|
||||
EFI_STATUS Status;
|
||||
VOID *Registration;
|
||||
UEFI_SERVICES_POINTERS *ServicePtrs;
|
||||
EFI_TPL OriginalTpl;
|
||||
|
||||
ServicePtrs = &BootCompat->ServicePtrs;
|
||||
|
||||
OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
||||
|
||||
ServicePtrs->AllocatePages = gBS->AllocatePages;
|
||||
ServicePtrs->GetMemoryMap = gBS->GetMemoryMap;
|
||||
ServicePtrs->ExitBootServices = gBS->ExitBootServices;
|
||||
@ -525,6 +574,8 @@ InstallServiceOverrides (
|
||||
gRT->Hdr.CRC32 = 0;
|
||||
gRT->Hdr.CRC32 = CalculateCrc32 (gRT, gRT->Hdr.HeaderSize);
|
||||
|
||||
gBS->RestoreTPL (OriginalTpl);
|
||||
|
||||
//
|
||||
// Allocate memory pool if needed.
|
||||
//
|
||||
|
||||
@ -39,7 +39,6 @@ typedef PACKED struct ASM_SUPPORT_STATE_ {
|
||||
UINT16 SavedES;
|
||||
UINT16 SavedFS;
|
||||
UINT16 SavedGS;
|
||||
UINT16 SavedSS;
|
||||
|
||||
UINT64 SavedGDTR32;
|
||||
UINT16 SavedGDTR32Limit;
|
||||
@ -50,8 +49,6 @@ typedef PACKED struct ASM_SUPPORT_STATE_ {
|
||||
UINT16 SavedES32;
|
||||
UINT16 SavedFS32;
|
||||
UINT16 SavedGS32;
|
||||
UINT16 SavedSS32;
|
||||
UINT32 SavedESP32;
|
||||
|
||||
VOID *KernelEntry;
|
||||
} ASM_SUPPORT_STATE;
|
||||
|
||||
@ -37,7 +37,6 @@ struc ASM_SUPPORT_STATE
|
||||
.SavedES resw 1
|
||||
.SavedFS resw 1
|
||||
.SavedGS resw 1
|
||||
.SavedSS resw 1
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; 32-bit state
|
||||
@ -52,8 +51,6 @@ struc ASM_SUPPORT_STATE
|
||||
.SavedES32 resw 1
|
||||
.SavedFS32 resw 1
|
||||
.SavedGS32 resw 1
|
||||
.SavedSS32 resw 1
|
||||
.SavedESP32 resd 1
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Kernel entry address.
|
||||
@ -100,9 +97,71 @@ BITS 64
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedES], es
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedFS], fs
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedGS], gs
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedSS], ss
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Apple kernel starts through call gate, an assembly structure allocated in
|
||||
; 32-bit high memory, that transitions to 32-bit mode and then calls the kernel
|
||||
; with 32-bit GDT and UEFI stack.
|
||||
;
|
||||
; KernelCallGate:
|
||||
; lea rax, StartKernelIn32Bit
|
||||
; mov cs:gKernelBooter32, eax
|
||||
; lea rax, gKernelGdtTable
|
||||
; mov cs:gKernelGdtBase, rax
|
||||
; lgdt fword ptr cs:gKernelGdtLimit
|
||||
; mov ax, 10h
|
||||
; mov ds, ax
|
||||
; mov es, ax
|
||||
; mov gs, ax
|
||||
; mov fs, ax
|
||||
; lea rax, gKernelBooter32
|
||||
; jmp fword ptr [rax]
|
||||
;
|
||||
; StartKernelIn32Bit:
|
||||
; mov rax, cr0
|
||||
; btr eax, 1Fh
|
||||
; mov cr0, rax
|
||||
; mov ebx, ecx ; ebx = boot-args
|
||||
; mov edi, edx
|
||||
; ; Disable long mode
|
||||
; mov ecx, 0C0000080h ; EFER MSR number.
|
||||
; rdmsr
|
||||
; btr eax, 8 ; Set LME=0.
|
||||
; wrmsr
|
||||
; jmp short SwitchTo32Bit
|
||||
;
|
||||
; SwitchTo32Bit:
|
||||
; mov eax, ebx
|
||||
; jmp rdi ; Jump to kernel
|
||||
; hlt
|
||||
; ret
|
||||
;
|
||||
; gKernelBooter32:
|
||||
; dd 0
|
||||
; dw 8 ; New CS value
|
||||
; gKernelGdtLimit: ; IA32_DESCRIPTOR
|
||||
; dw 18h
|
||||
; gKernelGdtBase:
|
||||
; dq 0
|
||||
; gKernelGdtTable: ; Array of IA32_GDT.
|
||||
; dw 0 ; [0] = LimitLow
|
||||
; dw 0 ; [0] = BaseLow
|
||||
; db 0 ; [0] = BaseMid
|
||||
; dw 0 ; [0] = Flags
|
||||
; db 0 ; [0] = BaseHigh
|
||||
; dw 0FFFFh ; [1] = LimitLow
|
||||
; dw 0 ; [1] = BaseLow
|
||||
; db 0 ; [1] = BaseMid
|
||||
; dw 0CF9Eh ; [1] - Flags
|
||||
; db 0 ; [1] = BaseHigh
|
||||
; dw 0FFFFh ; [2] = LimitLow
|
||||
; dw 0 ; [2] = BaseLow
|
||||
; db 0 ; [2] = BaseMid
|
||||
; dw 0CF92h ; [2] = Flags
|
||||
; db 0 ; [2] = BaseHigh
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Long (far) return.
|
||||
; retfq (lretq) - 64-bit encoding 48 CB
|
||||
@ -178,12 +237,10 @@ ASM_PFX(gOcAbcAsmStateAddr32):
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedES32], es
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedFS32], fs
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedGS32], gs
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedSS32], ss
|
||||
mov dword [ebx + ASM_SUPPORT_STATE.SavedESP32], esp
|
||||
|
||||
;
|
||||
; Transition to 64-bit mode...
|
||||
; FIXME: we should ensure interrupts are disabled here.
|
||||
; boot.efi disables interrupts for us, so we are safe.
|
||||
;
|
||||
|
||||
; Load saved UEFI GDT and IDT.
|
||||
@ -232,10 +289,9 @@ BITS 64
|
||||
mov fs, ax
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedGS]
|
||||
mov gs, ax
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedSS]
|
||||
mov ss, ax
|
||||
|
||||
; Assume the stack is useasble but potentially misaligned.
|
||||
; boot.efi preserves ss selector from UEFI GDT to just use UEFI stack (and memory) as is.
|
||||
; For this reason just assume the stack is useable but align it for definite 64-bit compat.
|
||||
and rsp, 0FFFFFFFFFFFFFFF0h
|
||||
|
||||
; Call AppleMapPrepareKernelState (rcx = rax = bootArgs, rdx = 0 = 32 bit kernel jump).
|
||||
@ -287,6 +343,8 @@ AsmJumpFromKernel32Compatibility:
|
||||
;
|
||||
|
||||
; Reload saved 32 bit state data.
|
||||
; Since boot.efi relies on segment registers shadow part and preserves ss value,
|
||||
; which contains previously read GDT data, we are not allowed to later update it.
|
||||
lidt [ebx + ASM_SUPPORT_STATE.SavedIDTR32]
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedDS32]
|
||||
mov ds, ax
|
||||
@ -296,9 +354,6 @@ AsmJumpFromKernel32Compatibility:
|
||||
mov fs, ax
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedGS32]
|
||||
mov gs, ax
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedSS32]
|
||||
mov ss, ax ; disables interrupts for 1 instruction to load esp
|
||||
mov esp, dword [ebx + ASM_SUPPORT_STATE.SavedESP32]
|
||||
|
||||
; Jump back to the kernel passing boot arguments in eax.
|
||||
mov eax, edi
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user