mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-27 12:15:19 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
640 lines
21 KiB
C
640 lines
21 KiB
C
/**
|
|
|
|
UEFI driver for enabling loading of OSX by using memory relocation.
|
|
|
|
by dmazar
|
|
|
|
**/
|
|
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/CpuLib.h>
|
|
|
|
#include <Guid/GlobalVariable.h>
|
|
|
|
#include <Protocol/LoadedImage.h>
|
|
|
|
#include "BootFixes.h"
|
|
#include "DecodedKernelCheck.h"
|
|
#include "BootArgs.h"
|
|
#include "AsmFuncs.h"
|
|
#include "VMem.h"
|
|
#include "Lib.h"
|
|
#include "Hibernate.h"
|
|
#include "NVRAMDebug.h"
|
|
|
|
|
|
// DBG_TO: 0=no debug, 1=serial, 2=console
|
|
// serial requires
|
|
// [PcdsFixedAtBuild]
|
|
// gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x07
|
|
// gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0xFFFFFFFF
|
|
// in package DSC file
|
|
#define DBG_TO 0
|
|
|
|
#if DBG_TO == 2
|
|
#define DBG(...) AsciiPrint(__VA_ARGS__);
|
|
#elif DBG_TO == 1
|
|
#define DBG(...) DebugPrint(1, __VA_ARGS__);
|
|
#else
|
|
#define DBG(...)
|
|
#endif
|
|
|
|
#include "../Version.h"
|
|
CONST CHAR8* CloverRevision = REVISION_STR;
|
|
STATIC UINTN Counter = 0;
|
|
|
|
|
|
// defines the size of block that will be allocated for kernel image relocation,
|
|
// without RT and MMIO regions
|
|
// rehabman - Increase the size for ElCapitan to 128Mb 0x8000
|
|
// stinga11 - 0x6000
|
|
#define KERNEL_BLOCK_NO_RT_SIZE_PAGES 0x8000
|
|
|
|
// TRUE if we are doing hibernate wake
|
|
BOOLEAN gHibernateWake = FALSE;
|
|
|
|
|
|
// placeholders for storing original Boot Services functions
|
|
EFI_ALLOCATE_PAGES gStoredAllocatePages = NULL;
|
|
EFI_GET_MEMORY_MAP gStoredGetMemoryMap = NULL;
|
|
EFI_EXIT_BOOT_SERVICES gStoredExitBootServices = NULL;
|
|
EFI_IMAGE_START gStartImage = NULL;
|
|
EFI_HANDLE_PROTOCOL gHandleProtocol = NULL;
|
|
|
|
|
|
// monitoring AlocatePages
|
|
EFI_PHYSICAL_ADDRESS gMinAllocatedAddr = 0;
|
|
EFI_PHYSICAL_ADDRESS gMaxAllocatedAddr = 0;
|
|
|
|
// relocation base address
|
|
EFI_PHYSICAL_ADDRESS gRelocBase = 0;
|
|
// relocation block size in pages
|
|
UINTN gRelocSizePages = 0;
|
|
|
|
// location of memory allocated by boot.efi for hibernate image
|
|
EFI_PHYSICAL_ADDRESS gHibernateImageAddress = 0;
|
|
|
|
// last memory map obtained by boot.efi
|
|
UINTN gLastMemoryMapSize = 0;
|
|
EFI_MEMORY_DESCRIPTOR *gLastMemoryMap = NULL;
|
|
UINTN gLastDescriptorSize = 0;
|
|
UINT32 gLastDescriptorVersion = 0;
|
|
|
|
/** Helper function that calls GetMemoryMap() and returns new MapKey.
|
|
* Uses gStoredGetMemoryMap, so can be called only after gStoredGetMemoryMap is set.
|
|
*/
|
|
EFI_STATUS
|
|
GetMemoryMapKey(OUT UINTN *MapKey)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN MemoryMapSize;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
|
UINTN DescriptorSize;
|
|
UINT32 DescriptorVersion;
|
|
|
|
Status = GetMemoryMapAlloc(gStoredGetMemoryMap, &MemoryMapSize, &MemoryMap, MapKey, &DescriptorSize, &DescriptorVersion);
|
|
return Status;
|
|
}
|
|
|
|
/** Helper function that calculates number of RT and MMIO pages from mem map. */
|
|
EFI_STATUS
|
|
GetNumberOfRTPages(OUT UINTN *NumPages)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN MemoryMapSize;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
|
UINTN MapKey;
|
|
UINTN DescriptorSize;
|
|
UINT32 DescriptorVersion;
|
|
UINTN NumEntries;
|
|
UINTN Index;
|
|
EFI_MEMORY_DESCRIPTOR *Desc;
|
|
|
|
Status = GetMemoryMapAlloc(gBS->GetMemoryMap, &MemoryMapSize, &MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Apply some fixes
|
|
//
|
|
FixMemMap(MemoryMapSize, MemoryMap, DescriptorSize, DescriptorVersion);
|
|
|
|
//
|
|
// Sum RT and MMIO areas - all that have runtime attribute
|
|
//
|
|
|
|
*NumPages = 0;
|
|
Desc = MemoryMap;
|
|
NumEntries = MemoryMapSize / DescriptorSize;
|
|
|
|
for (Index = 0; Index < NumEntries; Index++) {
|
|
if ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0) {
|
|
*NumPages += Desc->NumberOfPages;
|
|
}
|
|
Desc = NEXT_MEMORY_DESCRIPTOR(Desc, DescriptorSize);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/** Calculate the size of reloc block.
|
|
* gRelocSizePages = KERNEL_BLOCK_NO_RT_SIZE_PAGES + RT&MMIO pages
|
|
*/
|
|
EFI_STATUS
|
|
CalculateRelocBlockSize(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN NumPagesRT;
|
|
|
|
|
|
// Sum pages needed for RT and MMIO areas
|
|
Status = GetNumberOfRTPages(&NumPagesRT);
|
|
if (EFI_ERROR(Status)) {
|
|
DBGnvr("GetNumberOfRTPages: %r\n", Status);
|
|
DBG("OsxAptioFixDrv: CalculateRelocBlockSize(): GetNumberOfRTPages: %r\n", Status);
|
|
Print(L"OsxAptioFixDrv: CalculateRelocBlockSize(): GetNumberOfRTPages: %r\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
gRelocSizePages = KERNEL_BLOCK_NO_RT_SIZE_PAGES + NumPagesRT;
|
|
DBGnvr("Reloc block: %x pages (%d MB) = kernel %x (%d MB) + RT&MMIO %x (%d MB)\n",
|
|
gRelocSizePages, EFI_PAGES_TO_SIZE(gRelocSizePages) >> 20,
|
|
KERNEL_BLOCK_NO_RT_SIZE_PAGES, EFI_PAGES_TO_SIZE(KERNEL_BLOCK_NO_RT_SIZE_PAGES) >> 20,
|
|
NumPagesRT, EFI_PAGES_TO_SIZE(NumPagesRT) >> 20
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Allocate free block on top of mem for kernel image relocation (will be returned to boot.efi for kernel boot image). */
|
|
EFI_STATUS
|
|
AllocateRelocBlock()
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS Addr;
|
|
|
|
|
|
// calculate the needed size for reloc block
|
|
CalculateRelocBlockSize();
|
|
|
|
gRelocBase = 0;
|
|
Addr = 0x100000000; // max address
|
|
Status = AllocatePagesFromTop(EfiBootServicesData, gRelocSizePages, &Addr);
|
|
if (Status != EFI_SUCCESS) {
|
|
DBG("OsxAptioFixDrv: AllocateRelocBlock(): can not allocate relocation block (0x%x pages below 0x%lx): %r\n",
|
|
gRelocSizePages, Addr, Status);
|
|
Print(L"OsxAptioFixDrv: AllocateRelocBlock(): can not allocate relocation block (0x%x pages below 0x%lx): %r\n",
|
|
gRelocSizePages, Addr, Status);
|
|
} else {
|
|
gRelocBase = Addr;
|
|
DBG("OsxAptioFixDrv: AllocateRelocBlock(): gRelocBase set to %lx - %lx\n", gRelocBase, gRelocBase + EFI_PAGES_TO_SIZE(gRelocSizePages) - 1);
|
|
DBGnvr("gRelocBase set to %lx - %lx\n", gRelocBase, gRelocBase + EFI_PAGES_TO_SIZE(gRelocSizePages) - 1);
|
|
}
|
|
|
|
// set reloc addr in runtime vars for boot manager
|
|
//Print(L"OsxAptioFixDrv: AllocateRelocBlock(): gRelocBase set to %lx - %lx\n", gRelocBase, gRelocBase + EFI_PAGES_TO_SIZE(gRelocSizePages) - 1);
|
|
/*Status = */gRT->SetVariable(L"OsxAptioFixDrv-RelocBase", &gEfiAppleBootGuid,
|
|
/* EFI_VARIABLE_NON_VOLATILE |*/ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof(gRelocBase) ,&gRelocBase);
|
|
return Status;
|
|
}
|
|
|
|
/** Releases relocation block. */
|
|
EFI_STATUS
|
|
FreeRelocBlock()
|
|
{
|
|
|
|
return gBS->FreePages(gRelocBase, gRelocSizePages);
|
|
}
|
|
|
|
|
|
|
|
/** gBS->HandleProtocol override:
|
|
* 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.
|
|
*/
|
|
EFI_STATUS EFIAPI
|
|
MOHandleProtocol(
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_GUID *Protocol,
|
|
OUT VOID **Interface
|
|
)
|
|
{
|
|
EFI_STATUS res;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
|
|
// special handling if gEfiGraphicsOutputProtocolGuid is requested by boot.efi
|
|
if (CompareGuid(Protocol, &gEfiGraphicsOutputProtocolGuid)) {
|
|
res = gHandleProtocol(Handle, Protocol, Interface);
|
|
if (res != EFI_SUCCESS) {
|
|
// let's find it on some other handle
|
|
res = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID**)&GraphicsOutput);
|
|
if (res == EFI_SUCCESS) {
|
|
// return it
|
|
*Interface = GraphicsOutput;
|
|
// DBG("->HandleProtocol(%p, %s, %p) = %r (returning from other handle)\n", Handle, GuidStr(Protocol), *Interface, res);
|
|
DBGnvr("->HandleProtocol(%p, %s, %p) = %r (from other handle)\n", Handle, GuidStr(Protocol), *Interface, res);
|
|
return res;
|
|
}
|
|
}
|
|
DBGnvr("->HandleProtocol(%p, %s, %p) = %r\n", Handle, GuidStr(Protocol), *Interface, res);
|
|
} else {
|
|
res = gHandleProtocol(Handle, Protocol, Interface);
|
|
}
|
|
// DBG("->HandleProtocol(%p, %s, %p) = %r\n", Handle, GuidStr(Protocol), *Interface, res);
|
|
return res;
|
|
}
|
|
|
|
/** 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;
|
|
// EFI_PHYSICAL_ADDRESS MemoryIn;
|
|
// BOOLEAN FromRelocBlock = FALSE;
|
|
|
|
|
|
// MemoryIn = *Memory;
|
|
|
|
if (Type == AllocateAddress && MemoryType == EfiLoaderData) {
|
|
// called from boot.efi
|
|
|
|
UpperAddr = *Memory + EFI_PAGES_TO_SIZE(NumberOfPages);
|
|
|
|
// check if the requested mem can be served from reloc block
|
|
// the upper address is compared to the size of the relocation block to achieve Address + gRelocBase for all
|
|
// allocations, so that the entire block can be copied to the proper location on kernel entry
|
|
// Comparing only the number of pages will not only give wrong results as gRelocSizePages is not decreased,
|
|
// but also implies memory is 'stacked', which it is not.
|
|
if (UpperAddr >= EFI_PAGES_TO_SIZE(gRelocSizePages)) {
|
|
// no - exceeds our block - signal error
|
|
Print(L"OsxAptioFixDrv: Error - requested memory exceeds our allocated relocation block\n");
|
|
Print(L"Requested mem: %lx - %lx, Pages: %x, Size: %lx\n",
|
|
*Memory, UpperAddr - 1,
|
|
NumberOfPages, EFI_PAGES_TO_SIZE(NumberOfPages)
|
|
);
|
|
Print(L"Reloc block: %lx - %lx, Pages: %x, Size: %lx\n",
|
|
gRelocBase, gRelocBase + EFI_PAGES_TO_SIZE(gRelocSizePages) - 1,
|
|
gRelocSizePages, EFI_PAGES_TO_SIZE(gRelocSizePages)
|
|
);
|
|
Print(L"Reloc block can handle mem requests: %lx - %lx\n",
|
|
0, EFI_PAGES_TO_SIZE(gRelocSizePages) - 1
|
|
);
|
|
Print(L"Exiting in 30 secs ...\n");
|
|
gBS->Stall(30 * 1000000);
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
// store min and max mem - can be used later to determine start and end of kernel boot image
|
|
if (gMinAllocatedAddr == 0 || *Memory < gMinAllocatedAddr) gMinAllocatedAddr = *Memory;
|
|
if (UpperAddr > gMaxAllocatedAddr) gMaxAllocatedAddr = UpperAddr;
|
|
|
|
// give it from our allocated block
|
|
*Memory += gRelocBase;
|
|
//Status = gStoredAllocatePages(Type, MemoryType, NumberOfPages, Memory);
|
|
// FromRelocBlock = TRUE;
|
|
Status = EFI_SUCCESS;
|
|
|
|
} else {
|
|
// default page allocation
|
|
Status = gStoredAllocatePages(Type, MemoryType, NumberOfPages, Memory);
|
|
}
|
|
|
|
//DBG("AllocatePages(%s, %s, %x, %lx/%lx) = %r %c\n",
|
|
// EfiAllocateTypeDesc[Type], EfiMemoryTypeDesc[MemoryType], NumberOfPages, MemoryIn, *Memory, Status, FromRelocBlock ? L'+' : L' ');
|
|
return Status;
|
|
}
|
|
|
|
|
|
/** gBS->GetMemoryMap override:
|
|
* Returns shrinked memory map. I think kernel can handle up to 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 = gStoredGetMemoryMap(MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
|
|
//PrintMemMap(*MemoryMapSize, MemoryMap, *DescriptorSize, *DescriptorVersion);
|
|
DBGnvr("GetMemoryMap: %p = %r\n", MemoryMap, Status);
|
|
if (Status == EFI_SUCCESS) {
|
|
FixMemMap(*MemoryMapSize, MemoryMap, *DescriptorSize, *DescriptorVersion);
|
|
//ShrinkMemMap(MemoryMapSize, MemoryMap, *DescriptorSize, *DescriptorVersion);
|
|
//PrintMemMap(*MemoryMapSize, MemoryMap, *DescriptorSize, *DescriptorVersion);
|
|
|
|
// remember last/final memmap
|
|
gLastMemoryMapSize = *MemoryMapSize;
|
|
gLastMemoryMap = MemoryMap;
|
|
gLastDescriptorSize = *DescriptorSize;
|
|
gLastDescriptorVersion = *DescriptorVersion;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/** 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 NewMapKey;
|
|
UINTN SlideAddr = 0;
|
|
VOID *MachOImage = NULL;
|
|
|
|
// for tests: we can just return EFI_SUCCESS and continue using Print for debug.
|
|
// Status = EFI_SUCCESS;
|
|
//Print(L"ExitBootServices()\n");
|
|
Status = gStoredExitBootServices(ImageHandle, MapKey);
|
|
DBGnvr("ExitBootServices: = %r\n", Status);
|
|
if (EFI_ERROR (Status)) {
|
|
// just report error as var in nvram to be visible from OSX with "nvrap -p"
|
|
gRT->SetVariable(L"OsxAptioFixDrv-ErrorExitingBootServices",
|
|
&gEfiAppleBootGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
3,
|
|
"Yes"
|
|
);
|
|
|
|
Status = GetMemoryMapKey(&NewMapKey);
|
|
DBGnvr("ExitBootServices: GetMemoryMapKey = %r\n", Status);
|
|
if (Status == EFI_SUCCESS) {
|
|
// we have latest mem map and NewMapKey
|
|
// we'll try again ExitBootServices with NewMapKey
|
|
Status = gStoredExitBootServices(ImageHandle, NewMapKey);
|
|
DBGnvr("ExitBootServices: 2nd try = %r\n", Status);
|
|
if (EFI_ERROR (Status)) {
|
|
// Error!
|
|
Print(L"OsxAptioFixDrv: Error ExitBootServices() 2nd try = Status: %r\n", Status);
|
|
}
|
|
} else {
|
|
Print(L"OsxAptioFixDrv: Error ExitBootServices(), GetMemoryMapKey() = Status: %r\n", Status);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
Print(L"... waiting 10 secs ...\n");
|
|
gBS->Stall(10*1000000);
|
|
return Status;
|
|
}
|
|
|
|
DBG("ExitBootServices: gMinAllocatedAddr: %lx, gMaxAllocatedAddr: %lx\n", gMinAllocatedAddr, gMaxAllocatedAddr);
|
|
MachOImage = (VOID*)(UINTN)(gRelocBase + 0x200000);
|
|
KernelEntryFromMachOPatchJump(MachOImage, SlideAddr);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/** Callback called when boot.efi jumps to kernel. */
|
|
UINTN
|
|
EFIAPI
|
|
KernelEntryPatchJumpBack(UINTN bootArgs, BOOLEAN ModeX64)
|
|
{
|
|
|
|
DBGnvr("\nBACK FROM KERNEL: BootArgs = %x, KernelEntry: %x, Kernel called in %s bit mode\n", bootArgs, AsmKernelEntry, (ModeX64 ? L"64" : L"32"));
|
|
|
|
bootArgs = FixBootingWithRelocBlock(bootArgs, ModeX64);
|
|
|
|
DBGnvr("BACK TO KERNEL: BootArgs = %x, KImgStartReloc = %x, KImgStart = %x, KImgSize = %x\n",
|
|
bootArgs, AsmKernelImageStartReloc, AsmKernelImageStart, AsmKernelImageSize);
|
|
|
|
// debug for jumping back to kernel
|
|
// put HLT to kernel entry point to stop there
|
|
//SetMem((VOID*)(UINTN)(AsmKernelEntry + gRelocBase), 1, 0xF4);
|
|
// put 0 to kernel entry point to restart
|
|
//SetMem64((VOID*)(UINTN)(AsmKernelEntry + gRelocBase), 1, 0);
|
|
|
|
return bootArgs;
|
|
}
|
|
|
|
|
|
|
|
/** SWITCH_STACK_ENTRY_POINT implementation:
|
|
* Allocates kernel image reloc block, installs UEFI overrides and starts given image.
|
|
* If image returns, then deinstalls overrides and releases kernel image reloc block.
|
|
*
|
|
* If started with ImgContext->JumpBuffer, then it will return with LongJump().
|
|
*/
|
|
EFI_STATUS
|
|
RunImageWithOverrides(IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
// save current 64bit state - will be restored later in callback from kernel jump
|
|
// and relocate MyAsmCopyAndJumpToKernel32 code to higher mem (for copying kernel back to
|
|
// proper place and jumping back to it)
|
|
Status = PrepareJumpFromKernel();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// init VMem memory pool - will be used after ExitBootServices
|
|
Status = VmAllocateMemoryPool();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// allocate block for kernel image relocation
|
|
Status = AllocateRelocBlock();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// clear monitoring vars
|
|
gMinAllocatedAddr = 0;
|
|
gMaxAllocatedAddr = 0;
|
|
|
|
// save original BS functions
|
|
gStoredAllocatePages = gBS->AllocatePages;
|
|
gStoredGetMemoryMap = gBS->GetMemoryMap;
|
|
gStoredExitBootServices = gBS->ExitBootServices;
|
|
gHandleProtocol = gBS->HandleProtocol;
|
|
|
|
// install our overrides
|
|
gBS->AllocatePages = MOAllocatePages;
|
|
gBS->GetMemoryMap = MOGetMemoryMap;
|
|
gBS->ExitBootServices = MOExitBootServices;
|
|
gBS->HandleProtocol = MOHandleProtocol;
|
|
|
|
gBS->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32(gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
|
|
|
|
// run image
|
|
Status = gStartImage(ImageHandle, ExitDataSize, ExitData);
|
|
|
|
// if we get here then boot.efi did not start kernel
|
|
// and we'll try to do some cleanup ...
|
|
|
|
// return back originals
|
|
gBS->AllocatePages = gStoredAllocatePages;
|
|
gBS->GetMemoryMap = gStoredGetMemoryMap;
|
|
gBS->ExitBootServices = gStoredExitBootServices;
|
|
gBS->HandleProtocol = gHandleProtocol;
|
|
|
|
gBS->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32(gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
|
|
|
|
// release reloc block
|
|
FreeRelocBlock();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** 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 *Image;
|
|
CHAR16 *FilePathText = NULL;
|
|
UINTN Size = 0;
|
|
VOID *Value = NULL;
|
|
UINTN Size2 = 0;
|
|
CHAR16 *StartFlag = NULL;
|
|
|
|
DBG("StartImage(%lx)\n", ImageHandle);
|
|
|
|
// find out image name from EfiLoadedImageProtocol
|
|
Status = gBS->OpenProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &Image, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
if (Status != EFI_SUCCESS) {
|
|
DBG("ERROR: MOStartImage: OpenProtocol(gEfiLoadedImageProtocolGuid) = %r\n", Status);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
FilePathText = FileDevicePathToText(Image->FilePath);
|
|
if (FilePathText != NULL) {
|
|
DBG("FilePath: %s\n", FilePathText);
|
|
}
|
|
DBG("ImageBase: %p - %lx (%lx)\n", Image->ImageBase, (UINT64)Image->ImageBase + Image->ImageSize, Image->ImageSize);
|
|
Status = gBS->CloseProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, gImageHandle, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG("CloseProtocol error: %r\n", Status);
|
|
}
|
|
|
|
//the presence of the variable means HibernateWake
|
|
//if the wake is canceled then the variable must be deleted
|
|
Status = gRT->GetVariable(L"boot-switch-vars", &gEfiAppleBootGuid, NULL, &Size, NULL);
|
|
gHibernateWake = (Status == EFI_BUFFER_TOO_SMALL);
|
|
|
|
if (StrStriBasic(FilePathText,L"boot.efi") /*|| StrStriBasic(FilePathText,L"booter")*/) {
|
|
Status = GetVariable2 (L"aptiofixflag", &gEfiAppleBootGuid, &Value, &Size2);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = gRT->SetVariable(L"recovery-boot-mode", &gEfiAppleBootGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
Size2, Value);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" Something goes wrong while setting recovery-boot-mode\n");
|
|
}
|
|
Status = gRT->SetVariable (L"aptiofixflag", &gEfiAppleBootGuid, 0, 0, NULL);
|
|
FreePool(Value);
|
|
}
|
|
|
|
Size2 =0;
|
|
//Check recovery-boot-mode present for nested boot.efi
|
|
Status = GetVariable2 (L"recovery-boot-mode", &gEfiAppleBootGuid, &Value, &Size2);
|
|
if (!EFI_ERROR(Status)) {
|
|
//If it presents, then wait for \com.apple.recovery.boot\boot.efi boot
|
|
DBG(" recovery-boot-mode present\n");
|
|
StartFlag = StrStriBasic(FilePathText,L"\\com.apple.recovery.boot\\boot.efi");
|
|
if (Counter > 0x00){
|
|
Status = gRT->SetVariable(L"aptiofixflag", &gEfiAppleBootGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
Size2, Value);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG("Something goes wrong! \n");
|
|
}
|
|
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
|
}
|
|
} else {
|
|
StartFlag = StrStriBasic(FilePathText,L"boot.efi");
|
|
/*if (!StartFlag) {
|
|
StartFlag = StrStriBasic(FilePathText,L"booter") ;
|
|
}*/
|
|
}
|
|
FreePool(Value);
|
|
}
|
|
|
|
// check if this is boot.efi
|
|
if (StartFlag && !gHibernateWake) {
|
|
Counter++;
|
|
Print(L"OsxAptioFixDrv: Starting overrides for %s\nUsing reloc block: yes, hibernate wake: %s \n",
|
|
FilePathText, gHibernateWake ? L"yes" : L"no");
|
|
//gBS->Stall(2000000);
|
|
|
|
// run with our overrides
|
|
Status = RunImageWithOverrides(ImageHandle, ExitDataSize, ExitData);
|
|
|
|
} else {
|
|
// call original function to do the job
|
|
Status = gStartImage(ImageHandle, ExitDataSize, ExitData);
|
|
}
|
|
|
|
if (FilePathText != NULL) {
|
|
gBS->FreePool(FilePathText);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/** Entry point. Installs our StartImage override.
|
|
* All other stuff will be installed from there when boot.efi is started.
|
|
*/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
OsxAptioFixDrvEntrypoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
// install StartImage override
|
|
// all other overrides will be started when boot.efi is started
|
|
gStartImage = gBS->StartImage;
|
|
gBS->StartImage = MOStartImage;
|
|
gBS->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32(gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|