2019-10-04 15:19:40 +02:00
|
|
|
/**
|
|
|
|
|
|
|
|
Temporary BS and RT overrides for boot.efi support.
|
|
|
|
Unlike RtShims they do not affect the kernel.
|
|
|
|
|
|
|
|
by dmazar
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <IndustryStandard/AppleHibernate.h>
|
|
|
|
|
|
|
|
#include <Library/BaseLib.h>
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
2019-10-04 22:32:02 +02:00
|
|
|
#include <Library/DebugLib.h>
|
2019-10-04 15:19:40 +02:00
|
|
|
#include <Library/OcMiscLib.h>
|
|
|
|
#include <Library/UefiLib.h>
|
|
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
|
|
|
|
#include <Protocol/LoadedImage.h>
|
|
|
|
|
|
|
|
#include "Config.h"
|
|
|
|
#include "ServiceOverrides.h"
|
|
|
|
#include "BootArgs.h"
|
|
|
|
#include "BootFixes.h"
|
|
|
|
#include "CustomSlide.h"
|
|
|
|
#include "MemoryMap.h"
|
|
|
|
#include "RtShims.h"
|
|
|
|
#include "UmmMalloc/UmmMalloc.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
// Placeholders for storing original Boot and RT Services functions
|
|
|
|
//
|
|
|
|
STATIC EFI_ALLOCATE_PAGES mStoredAllocatePages;
|
|
|
|
STATIC EFI_ALLOCATE_POOL mStoredAllocatePool;
|
|
|
|
STATIC EFI_FREE_POOL mStoredFreePool;
|
|
|
|
STATIC EFI_GET_MEMORY_MAP mStoredGetMemoryMap;
|
|
|
|
STATIC EFI_EXIT_BOOT_SERVICES mStoredExitBootServices;
|
|
|
|
STATIC EFI_SET_VIRTUAL_ADDRESS_MAP mStoredSetVirtualAddressMap;
|
|
|
|
STATIC EFI_IMAGE_START mStoredStartImage;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Original runtime services hash we restore at address virtualisation
|
|
|
|
//
|
|
|
|
STATIC UINT32 mRtPreOverridesCRC32;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Location of memory allocated by boot.efi for hibernate image
|
|
|
|
//
|
|
|
|
STATIC EFI_PHYSICAL_ADDRESS mHibernateImageAddress;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Saved exit boot services arguments
|
|
|
|
//
|
|
|
|
STATIC EFI_HANDLE mExitBSImageHandle;
|
|
|
|
STATIC UINTN mExitBSMapKey;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Dynamic memory allocation filtering status
|
|
|
|
//
|
|
|
|
STATIC BOOLEAN mFilterDynamicPoolAllocations;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Minimum and maximum addresses allocated by AlocatePages
|
|
|
|
//
|
|
|
|
STATIC EFI_PHYSICAL_ADDRESS mMinAllocatedAddr;
|
|
|
|
STATIC EFI_PHYSICAL_ADDRESS mMaxAllocatedAddr;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Amount of nested boot.efi detected
|
|
|
|
//
|
|
|
|
UINTN gMacOSBootNestedCount;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Last descriptor size obtained from GetMemoryMap
|
|
|
|
//
|
|
|
|
UINTN gMemoryMapDescriptorSize = sizeof(EFI_MEMORY_DESCRIPTOR);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InstallBsOverrides (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
#if APTIOFIX_CUSTOM_POOL_ALLOCATOR == 1
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PHYSICAL_ADDRESS UmmHeap = BASE_4GB;
|
|
|
|
UINTN PageNum = EFI_SIZE_TO_PAGES (APTIOFIX_CUSTOM_POOL_ALLOCATOR_SIZE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// We do not uninstall our custom allocator to avoid memory corruption issues
|
|
|
|
// when shimming AMI code. This check ensures that we do not install it twice.
|
|
|
|
// See UninstallBsOverrides for more details.
|
|
|
|
//
|
|
|
|
if (!UmmInitialized ()) {
|
|
|
|
//
|
|
|
|
// Enforce memory pool creation when -aptiodump argument is used, but let it slip otherwise.
|
|
|
|
//
|
|
|
|
Status = AllocatePagesFromTop (EfiBootServicesData, PageNum, &UmmHeap, !gDumpMemArgPresent);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
gBS->SetMem ((VOID *)UmmHeap, APTIOFIX_CUSTOM_POOL_ALLOCATOR_SIZE, 0);
|
|
|
|
UmmSetHeap ((VOID *)UmmHeap);
|
|
|
|
|
|
|
|
mStoredAllocatePool = gBS->AllocatePool;
|
|
|
|
mStoredFreePool = gBS->FreePool;
|
|
|
|
|
|
|
|
gBS->AllocatePool = MOAllocatePool;
|
|
|
|
gBS->FreePool = MOFreePool;
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// This is undesired, but technically less fatal than attempting to reduce the number
|
|
|
|
// of slides available when no memory map dumping is necessary, for example.
|
|
|
|
//
|
2019-10-04 22:32:02 +02:00
|
|
|
Print (L"AMF: Not using custom memory pool - %r\n", Status);
|
2019-10-04 15:19:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mStoredAllocatePages = gBS->AllocatePages;
|
|
|
|
mStoredGetMemoryMap = gBS->GetMemoryMap;
|
|
|
|
mStoredExitBootServices = gBS->ExitBootServices;
|
|
|
|
mStoredStartImage = gBS->StartImage;
|
|
|
|
|
|
|
|
gBS->AllocatePages = MOAllocatePages;
|
|
|
|
gBS->GetMemoryMap = MOGetMemoryMap;
|
|
|
|
gBS->ExitBootServices = MOExitBootServices;
|
|
|
|
gBS->StartImage = MOStartImage;
|
|
|
|
|
|
|
|
gBS->Hdr.CRC32 = 0;
|
|
|
|
gBS->CalculateCrc32 (gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InstallRtOverrides (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
mRtPreOverridesCRC32 = gRT->Hdr.CRC32;
|
|
|
|
|
|
|
|
mStoredSetVirtualAddressMap = gRT->SetVirtualAddressMap;
|
|
|
|
|
|
|
|
gRT->SetVirtualAddressMap = MOSetVirtualAddressMap;
|
|
|
|
|
|
|
|
gRT->Hdr.CRC32 = 0;
|
|
|
|
gBS->CalculateCrc32 (gRT, gRT->Hdr.HeaderSize, &gRT->Hdr.CRC32);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
UninstallRtOverrides (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
gRT->SetVirtualAddressMap = mStoredSetVirtualAddressMap;
|
|
|
|
|
|
|
|
gRT->Hdr.CRC32 = mRtPreOverridesCRC32;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
DisableDynamicPoolAllocations (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
mFilterDynamicPoolAllocations = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
EnableDynamicPoolAllocations (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
mFilterDynamicPoolAllocations = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->StartImage override:
|
|
|
|
* Called to start an efi image.
|
|
|
|
*
|
|
|
|
* If this is boot.efi, then run it with our overrides.
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOStartImage (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
OUT UINTN *ExitDataSize,
|
|
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_LOADED_IMAGE_PROTOCOL *AppleLoadedImage = NULL;
|
|
|
|
UINTN ValueSize = 0;
|
|
|
|
VOID *Gop;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "StartImage (%lx)\n", ImageHandle));
|
|
|
|
|
|
|
|
AppleLoadedImage = GetAppleBootLoadedImage (ImageHandle);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Clear monitoring vars
|
|
|
|
//
|
|
|
|
mMinAllocatedAddr = 0;
|
|
|
|
mMaxAllocatedAddr = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Request boot variable redirection if enabled.
|
|
|
|
//
|
|
|
|
SetBootVariableRedirect (TRUE);
|
|
|
|
|
|
|
|
if (AppleLoadedImage) {
|
|
|
|
//
|
|
|
|
// Report about macOS being loaded.
|
|
|
|
//
|
|
|
|
gMacOSBootNestedCount++;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Latest Windows brings Virtualization-based security and monitors
|
|
|
|
// CR0 by launching itself under a hypevisor. Since we need WP disable
|
|
|
|
// on macOS to let NVRAM work, and for the time being no other OS
|
|
|
|
// requires it, here we decide to use it for macOS exclusively.
|
|
|
|
//
|
|
|
|
SetWriteUnprotectorMode (TRUE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Boot.efi requires EfiGraphicsOutputProtocol on ConOutHandle, but it is not present
|
|
|
|
// there on Aptio 2.0. EfiGraphicsOutputProtocol exists on some other handle.
|
|
|
|
// If this is the case, we'll intercept that call and return EfiGraphicsOutputProtocol
|
|
|
|
// from that other handle.
|
|
|
|
//
|
|
|
|
Gop = NULL;
|
|
|
|
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, &Gop);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&gST->ConsoleOutHandle,
|
|
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
|
|
Gop,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is reverse engineered from boot.efi.
|
|
|
|
// To cancel hibernate wake it is enough to delete the variables.
|
|
|
|
// Starting with 10.13.6 boot-switch-vars is no longer supported.
|
|
|
|
//
|
|
|
|
ValueSize = 0;
|
2019-10-04 22:32:02 +02:00
|
|
|
if (gRT->GetVariable (L"boot-signature", &gEfiAppleBootGuid, NULL, &ValueSize, NULL) == EFI_BUFFER_TOO_SMALL) {
|
2019-10-04 15:19:40 +02:00
|
|
|
ValueSize = 0;
|
2019-10-04 22:32:02 +02:00
|
|
|
if (gRT->GetVariable (L"boot-image-key", &gEfiAppleBootGuid, NULL, &ValueSize, NULL) == EFI_BUFFER_TOO_SMALL) {
|
2019-10-04 15:19:40 +02:00
|
|
|
gHibernateWake = TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ValueSize = 0;
|
2019-10-04 22:32:02 +02:00
|
|
|
if (gRT->GetVariable (L"boot-switch-vars", &gEfiAppleBootGuid, NULL, &ValueSize, NULL) == EFI_BUFFER_TOO_SMALL) {
|
2019-10-04 15:19:40 +02:00
|
|
|
gHibernateWake = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Save current 64bit state - will be restored later in callback from kernel jump
|
|
|
|
// and relocate JumpToKernel32 code to higher mem (for copying kernel back to
|
|
|
|
// proper place and jumping back to it)
|
|
|
|
//
|
|
|
|
Status = PrepareJumpFromKernel ();
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// Force boot.efi to use our copy of system table
|
|
|
|
//
|
|
|
|
AppleLoadedImage->SystemTable = (EFI_SYSTEM_TABLE *)(UINTN)gSysTableRtArea;
|
|
|
|
|
|
|
|
#if APTIOFIX_ALLOW_ASLR_IN_SAFE_MODE == 1
|
|
|
|
UnlockSlideSupportForSafeMode ((UINT8 *)AppleLoadedImage->ImageBase, AppleLoadedImage->ImageSize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Read options
|
|
|
|
//
|
|
|
|
ReadBooterArguments ((CHAR16*)AppleLoadedImage->LoadOptions, AppleLoadedImage->LoadOptionsSize/sizeof (CHAR16));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Status = mStoredStartImage (ImageHandle, ExitDataSize, ExitData);
|
|
|
|
|
|
|
|
if (AppleLoadedImage) {
|
|
|
|
//
|
|
|
|
// We failed but other operating systems should be loadable.
|
|
|
|
//
|
|
|
|
gMacOSBootNestedCount--;
|
|
|
|
SetWriteUnprotectorMode (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Disable redirect on failure, this is cleaner design-wise.
|
|
|
|
//
|
|
|
|
SetBootVariableRedirect (FALSE);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->AllocatePages override:
|
|
|
|
* Returns pages from free memory block to boot.efi for kernel boot image.
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOAllocatePages (
|
|
|
|
IN EFI_ALLOCATE_TYPE Type,
|
|
|
|
IN EFI_MEMORY_TYPE MemoryType,
|
|
|
|
IN UINTN NumberOfPages,
|
|
|
|
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PHYSICAL_ADDRESS UpperAddr;
|
|
|
|
|
|
|
|
if (gMacOSBootNestedCount > 0 && Type == AllocateAddress && MemoryType == EfiLoaderData) {
|
|
|
|
//
|
|
|
|
// Called from boot.efi
|
|
|
|
//
|
|
|
|
UpperAddr = *Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Store min and max mem - can be used later to determine start and end of kernel boot image
|
|
|
|
//
|
|
|
|
if (mMinAllocatedAddr == 0 || *Memory < mMinAllocatedAddr)
|
|
|
|
mMinAllocatedAddr = *Memory;
|
|
|
|
if (UpperAddr > mMaxAllocatedAddr)
|
|
|
|
mMaxAllocatedAddr = UpperAddr;
|
|
|
|
|
|
|
|
Status = mStoredAllocatePages (Type, MemoryType, NumberOfPages, Memory);
|
|
|
|
} else if (gMacOSBootNestedCount > 0 && gHibernateWake && Type == AllocateAnyPages && MemoryType == EfiLoaderData) {
|
|
|
|
//
|
|
|
|
// Called from boot.efi during hibernate wake,
|
|
|
|
// first such allocation is for hibernate image
|
|
|
|
//
|
|
|
|
Status = mStoredAllocatePages (Type, MemoryType, NumberOfPages, Memory);
|
|
|
|
if (mHibernateImageAddress == 0 && Status == EFI_SUCCESS) {
|
|
|
|
mHibernateImageAddress = *Memory;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Generic page allocation
|
|
|
|
//
|
|
|
|
Status = mStoredAllocatePages (Type, MemoryType, NumberOfPages, Memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->AllocatePool override:
|
|
|
|
* Allows us to use a custom allocator that uses a preallocated memory pool
|
2019-10-04 22:32:02 +02:00
|
|
|
* for certain types of memory. See details in Print function.
|
2019-10-04 15:19:40 +02:00
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOAllocatePool (
|
|
|
|
IN EFI_MEMORY_TYPE Type,
|
|
|
|
IN UINTN Size,
|
|
|
|
OUT VOID **Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// The code below allows us to more safely invoke Boot Services to perform onscreen
|
|
|
|
// printing when no memory map modifications (pool memory allocation) is allowed.
|
|
|
|
// While it is imperfect design-wise, it works very well on many ASUS Skylake boards
|
|
|
|
// when performing memory map dumps via -aptiodump.
|
|
|
|
//
|
|
|
|
if (gMacOSBootNestedCount > 0 && Type == EfiBootServicesData && mFilterDynamicPoolAllocations) {
|
|
|
|
*Buffer = UmmMalloc ((UINT32)Size);
|
|
|
|
if (*Buffer)
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Dynamic pool allocations filtering should technically only be used when booting is more
|
|
|
|
// important than not allocating the requested memory and failing to do something.
|
|
|
|
// However, since we skip other types of allocations anyway, not falling back here to using
|
|
|
|
// the default allocator may have its own consequences on other boards.
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
return mStoredAllocatePool (Type, Size, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->FreePool override:
|
|
|
|
* Allows us to use a custom allocator for certain types of memory.
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOFreePool (
|
|
|
|
IN VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// By default it will return FALSE if Buffer was not allocated by us.
|
|
|
|
//
|
|
|
|
if (UmmFree (Buffer))
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
|
|
|
return mStoredFreePool (Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->GetMemoryMap override:
|
|
|
|
* Returns shrinked memory map. XNU can handle up to PMAP_MEMORY_REGIONS_SIZE (128) entries.
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOGetMemoryMap (
|
|
|
|
IN OUT UINTN *MemoryMapSize,
|
|
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
|
|
OUT UINTN *MapKey,
|
|
|
|
OUT UINTN *DescriptorSize,
|
|
|
|
OUT UINT32 *DescriptorVersion
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = mStoredGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
|
|
|
|
|
|
|
|
if (gMacOSBootNestedCount > 0 && Status == EFI_SUCCESS) {
|
|
|
|
if (gDumpMemArgPresent) {
|
|
|
|
PrintMemMap (L"GetMemoryMap", *MemoryMapSize, *DescriptorSize, MemoryMap, gRtShims, gSysTableRtArea);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if APTIOFIX_PROTECT_CSM_REGION == 1
|
|
|
|
ProtectCsmRegion (*MemoryMapSize, MemoryMap, *DescriptorSize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ShrinkMemMap (MemoryMapSize, MemoryMap, *DescriptorSize);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Remember some descriptor size, since we will not have it later
|
|
|
|
// during hibernate wake to be able to iterate memory map.
|
|
|
|
//
|
|
|
|
gMemoryMapDescriptorSize = *DescriptorSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
OrgGetMemoryMap (
|
|
|
|
IN OUT UINTN *MemoryMapSize,
|
|
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
|
|
OUT UINTN *MapKey,
|
|
|
|
OUT UINTN *DescriptorSize,
|
|
|
|
OUT UINT32 *DescriptorVersion
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return (mStoredGetMemoryMap ? mStoredGetMemoryMap : gBS->GetMemoryMap) (
|
|
|
|
MemoryMapSize,
|
|
|
|
MemoryMap,
|
|
|
|
MapKey,
|
|
|
|
DescriptorSize,
|
|
|
|
DescriptorVersion
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gBS->ExitBootServices override:
|
|
|
|
* Patches kernel entry point with jump to our KernelEntryPatchJumpBack().
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOExitBootServices (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN UINTN MapKey
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN SlideAddr = 0;
|
|
|
|
VOID *MachOImage = NULL;
|
|
|
|
IOHibernateImageHeader *ImageHeader = NULL;
|
|
|
|
|
|
|
|
//
|
|
|
|
// For non-macOS operating systems return directly.
|
|
|
|
//
|
|
|
|
if (gMacOSBootNestedCount == 0) {
|
|
|
|
return mStoredExitBootServices (ImageHandle, MapKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// We need hibernate image address for wake
|
|
|
|
//
|
|
|
|
if (gHibernateWake && mHibernateImageAddress == 0) {
|
2019-10-04 22:32:02 +02:00
|
|
|
Print (L"AMF: Failed to find hibernate image address\n");
|
2019-10-04 15:19:40 +02:00
|
|
|
gBS->Stall (SECONDS_TO_MICROSECONDS (5));
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// We can just return EFI_SUCCESS and continue using Print for debug
|
|
|
|
//
|
|
|
|
if (gDumpMemArgPresent) {
|
|
|
|
mExitBSImageHandle = ImageHandle;
|
|
|
|
mExitBSMapKey = MapKey;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
} else {
|
|
|
|
Status = ForceExitBootServices (mStoredExitBootServices, ImageHandle, MapKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status))
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
if (!gHibernateWake) {
|
|
|
|
SlideAddr = mMinAllocatedAddr - 0x100000;
|
|
|
|
MachOImage = (VOID*)(UINTN)(SlideAddr + SLIDE_GRANULARITY);
|
|
|
|
KernelEntryFromMachOPatchJump (MachOImage, SlideAddr);
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
ImageHeader = (IOHibernateImageHeader *)(UINTN)mHibernateImageAddress;
|
|
|
|
KernelEntryPatchJump (
|
|
|
|
((UINT32)(UINTN)&(ImageHeader->fileExtentMap[0])) + ImageHeader->fileExtentMapSize + ImageHeader->restore1CodeOffset
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper function to call ExitBootServices that can handle outdated MapKey issues. */
|
|
|
|
EFI_STATUS
|
|
|
|
ForceExitBootServices (
|
|
|
|
IN EFI_EXIT_BOOT_SERVICES ExitBs,
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN UINTN MapKey
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
|
|
|
UINTN MemoryMapSize;
|
|
|
|
UINTN DescriptorSize;
|
|
|
|
UINT32 DescriptorVersion;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Firstly try the easy way
|
|
|
|
//
|
|
|
|
Status = ExitBs (ImageHandle, MapKey);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// Just report error as var in nvram to be visible from macOS with "nvram -p"
|
|
|
|
//
|
|
|
|
gRT->SetVariable (L"aptiomemfix-exitbs",
|
2019-10-04 22:32:02 +02:00
|
|
|
&gEfiAppleBootGuid,
|
2019-10-04 15:19:40 +02:00
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
|
|
4,
|
|
|
|
"fail"
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// It is too late to free memory map here, but it does not matter, because boot.efi has an old one
|
|
|
|
// and will freely use the memory.
|
|
|
|
// It is technically forbidden to allocate pool memory here, but we should not hit this code
|
|
|
|
// in the first place, and for older firmwares, where it was necessary (?), it worked just fine.
|
|
|
|
//
|
|
|
|
Status = GetMemoryMapAlloc (NULL, &MemoryMapSize, &MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
|
|
//
|
|
|
|
// We have the latest memory map and its key, try again!
|
|
|
|
//
|
|
|
|
Status = ExitBs (ImageHandle, MapKey);
|
|
|
|
if (EFI_ERROR (Status))
|
2019-10-04 22:32:02 +02:00
|
|
|
Print (L"AMF: ExitBootServices failed twice - %r\n", Status);
|
2019-10-04 15:19:40 +02:00
|
|
|
} else {
|
2019-10-04 22:32:02 +02:00
|
|
|
Print (L"AMF: Failed to get MapKey for ExitBootServices - %r\n", Status);
|
2019-10-04 15:19:40 +02:00
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
2019-10-04 22:32:02 +02:00
|
|
|
Print (L"Waiting 10 secs...\n");
|
2019-10-04 15:19:40 +02:00
|
|
|
gBS->Stall (SECONDS_TO_MICROSECONDS (10));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** gRT->SetVirtualAddressMap override:
|
|
|
|
* Fixes virtualizing of RT services.
|
|
|
|
*/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MOSetVirtualAddressMap (
|
|
|
|
IN UINTN MemoryMapSize,
|
|
|
|
IN UINTN DescriptorSize,
|
|
|
|
IN UINT32 DescriptorVersion,
|
|
|
|
IN EFI_MEMORY_DESCRIPTOR *VirtualMap
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 EfiSystemTable;
|
|
|
|
|
|
|
|
//
|
|
|
|
// We do not need to recover BS, since they will be invalid.
|
|
|
|
//
|
|
|
|
UninstallRtOverrides ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Apply the necessary changes for macOS support
|
|
|
|
//
|
|
|
|
if (gMacOSBootNestedCount > 0) {
|
|
|
|
if (gDumpMemArgPresent) {
|
|
|
|
PrintMemMap (L"SetVirtualAddressMap", MemoryMapSize, DescriptorSize, VirtualMap, gRtShims, gSysTableRtArea);
|
|
|
|
//
|
|
|
|
// To print as much information as possible we delay ExitBootServices.
|
|
|
|
// Most likely this will fail, but let's still try!
|
|
|
|
//
|
|
|
|
ForceExitBootServices (mStoredExitBootServices, mExitBSImageHandle, mExitBSMapKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Protect RT areas from relocation by marking then MemMapIO
|
|
|
|
//
|
|
|
|
ProtectRtMemoryFromRelocation (MemoryMapSize, DescriptorSize, DescriptorVersion, VirtualMap, gSysTableRtArea);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Remember physical sys table addr
|
|
|
|
//
|
|
|
|
EfiSystemTable = (UINT32)(UINTN)gST;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Virtualize RT services with all needed fixes
|
|
|
|
//
|
|
|
|
Status = ExecSetVirtualAddressesToMemMap (MemoryMapSize, DescriptorSize, DescriptorVersion, VirtualMap);
|
|
|
|
|
|
|
|
CopyEfiSysTableToRtArea (&EfiSystemTable);
|
|
|
|
} else {
|
|
|
|
Status = gRT->SetVirtualAddressMap (MemoryMapSize, DescriptorSize, DescriptorVersion, VirtualMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Correct shim pointers right away
|
|
|
|
//
|
|
|
|
VirtualizeRtShims (MemoryMapSize, DescriptorSize, VirtualMap);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|