OcAppleBootCompatLib: Initial working prototype

This commit is contained in:
vit9696 2019-08-05 17:11:24 +03:00
parent 2e496a992d
commit 9027bd6be1
5 changed files with 140 additions and 39 deletions

View File

@ -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;

View File

@ -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>

View File

@ -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.
//

View File

@ -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;

View File

@ -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