mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcAppleBootCompatLib: Initial version
This commit is contained in:
parent
20120c7b6e
commit
7eca596604
67
Include/Library/OcAppleBootCompatLib.h
Normal file
67
Include/Library/OcAppleBootCompatLib.h
Normal file
@ -0,0 +1,67 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#ifndef OC_APPLE_BOOT_COMPAT_LIB_H
|
||||
#define OC_APPLE_BOOT_COMPAT_LIB_H
|
||||
|
||||
/**
|
||||
Apple Boot Compatibility layer configuration.
|
||||
**/
|
||||
typedef struct OC_ABC_SETTINGS_ {
|
||||
///
|
||||
/// Protect from boot.efi from defragmenting runtime memory and setup virtual memory
|
||||
/// early mapping. This fixes NVRAM support on many firmwares.
|
||||
///
|
||||
BOOLEAN SetupAppleMap;
|
||||
///
|
||||
/// Provide custom Apple KASLR slide calculation for firmwares with polluted low memory ranges.
|
||||
///
|
||||
BOOLEAN SetupAppleSlide;
|
||||
///
|
||||
/// Discard UEFI memory map after waking from hibernation and preserve the original mapping.
|
||||
///
|
||||
BOOLEAN DiscardAppleS4Map;
|
||||
///
|
||||
/// Try to patch Apple bootloader to have KASLR enabled even in SafeMode.
|
||||
///
|
||||
BOOLEAN EnableAppleSmSlide;
|
||||
///
|
||||
/// Attempt to protect certain CSM memory regions from being used by the kernel .
|
||||
/// On older firmwares this caused wake issues.
|
||||
///
|
||||
BOOLEAN ProtectCsmRegion;
|
||||
///
|
||||
/// Attempt to reduce memory map entries through grouping to fit into Apple kernel.
|
||||
///
|
||||
BOOLEAN ShrinkMemoryMap;
|
||||
///
|
||||
/// Ensure that ExitBootServices call succeeds even with outdated MemoryMap key.
|
||||
///
|
||||
BOOLEAN ForceExitBootServices;
|
||||
} OC_ABC_SETTINGS;
|
||||
|
||||
/**
|
||||
Initialize Apple Boot Compatibility layer. This layer is needed on partially
|
||||
incompatible firmwares to prevent boot failure and UEFI services breakage.
|
||||
|
||||
@param[in] Settings Compatibility layer configuration.
|
||||
|
||||
@retval EFI_SUCCESS on success.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcAbcInitialize (
|
||||
IN OC_ABC_SETTINGS *Settings
|
||||
);
|
||||
|
||||
#endif // OC_APPLE_BOOT_COMPAT_LIB_H
|
||||
@ -469,6 +469,16 @@ OcActivateHibernateWake (
|
||||
IN UINT32 HibernateMask
|
||||
);
|
||||
|
||||
/**
|
||||
Check if active hibernation is happening.
|
||||
|
||||
@retval TRUE on waking from hibernation.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcIsAppleHibernateWake (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Install missing boot policy, scan, and show simple boot menu.
|
||||
|
||||
@ -547,6 +557,24 @@ OcParseBootArgs (
|
||||
IN VOID *BootArgs
|
||||
);
|
||||
|
||||
/**
|
||||
Check if boot argument is currently passed (via image options or NVRAM).
|
||||
|
||||
@param[in] LoadImage UEFI loaded image protocol instance, optional.
|
||||
@param[in] GetVariable Preferred UEFI NVRAM reader, optional.
|
||||
@param[in] Argument Argument, e.g. -v, slide=, debug=, etc.
|
||||
@param[in] ArgumentLength Argument length, e.g. L_STR_LEN ("-v").
|
||||
|
||||
@retval TRUE if argument is present.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcCheckArgumentFromEnv (
|
||||
IN EFI_LOADED_IMAGE *LoadedImage OPTIONAL,
|
||||
IN EFI_GET_VARIABLE GetVariable OPTIONAL,
|
||||
IN CONST CHAR8 *Argument,
|
||||
IN CONST UINTN ArgumentLength
|
||||
);
|
||||
|
||||
/**
|
||||
Get argument value from command line.
|
||||
|
||||
|
||||
@ -26,6 +26,11 @@
|
||||
**/
|
||||
#define DEBUG_BULK_INFO (DEBUG_VERBOSE|DEBUG_INFO)
|
||||
|
||||
/**
|
||||
This is a place print debug messages when they happen after ExitBootServices.
|
||||
**/
|
||||
#define RUNTIME_DEBUG(x) do { } while (0)
|
||||
|
||||
/**
|
||||
Install or update the OcLog protocol with specified options.
|
||||
|
||||
|
||||
@ -98,4 +98,13 @@ ReleaseUsbOwnership (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Perform cold reboot directly bypassing UEFI services. Does not return.
|
||||
Supposed to work in any modern physical or virtual environment.
|
||||
**/
|
||||
VOID
|
||||
DirectRestCold (
|
||||
VOID
|
||||
);
|
||||
|
||||
#endif // OC_MISC_LIB_H
|
||||
|
||||
37
Include/Protocol/OcAppleBootCompat.h
Normal file
37
Include/Protocol/OcAppleBootCompat.h
Normal file
@ -0,0 +1,37 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#ifndef OC_APPLE_BOOT_COMPAT_PROTOCOL_H
|
||||
#define OC_APPLE_BOOT_COMPAT_PROTOCOL_H
|
||||
|
||||
#define OC_APPLE_BOOT_COMPAT_PROTOCOL_REVISION 0x010000
|
||||
|
||||
//
|
||||
// OC_APPLE_BOOT_COMPAT_PROTOCOL_GUID
|
||||
// C7CBA84E-CC77-461D-9E3C-6BE0CB79A7C1
|
||||
//
|
||||
#define OC_APPLE_BOOT_COMPAT_PROTOCOL_GUID \
|
||||
{ 0xC7CBA84E, 0xCC77, 0x461D, \
|
||||
{ 0x9E, 0x3C, 0x6B, 0xE0, 0xCB, 0x79, 0xA7, 0xC1 } }
|
||||
|
||||
//
|
||||
// Includes a revision for debugging reasons
|
||||
//
|
||||
typedef struct {
|
||||
UINTN Revision;
|
||||
} OC_APPLE_BOOT_COMPAT_PROTOCOL;
|
||||
|
||||
extern EFI_GUID gOcAppleBootCompatProtocolGuid;
|
||||
|
||||
#endif // OC_APPLE_BOOT_COMPAT_PROTOCOL_H
|
||||
335
Library/OcAppleBootCompatLib/BootCompatInternal.h
Normal file
335
Library/OcAppleBootCompatLib/BootCompatInternal.h
Normal file
@ -0,0 +1,335 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#ifndef BOOT_COMPAT_INTERNAL_H
|
||||
#define BOOT_COMPAT_INTERNAL_H
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcAppleBootCompatLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcMemoryLib.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
|
||||
#ifdef MDE_CPU_X64
|
||||
#include "X64/ContextSwitch.h"
|
||||
#else
|
||||
#error "Unsupported architecture!"
|
||||
#endif
|
||||
|
||||
/**
|
||||
Maximum number of supported runtime reloc protection areas.
|
||||
Currently hardocded for simplicity.
|
||||
**/
|
||||
#define RT_RELOC_PROTECT_MAX_NUM ((UINTN) 64)
|
||||
|
||||
/**
|
||||
Runtime descriptor number to virtualise.
|
||||
Currently hardocded for simplicity.
|
||||
**/
|
||||
#define RT_DESC_ENTRY_NUM ((UINTN) 64)
|
||||
|
||||
/**
|
||||
Base kernel address.
|
||||
**/
|
||||
#define BASE_KERNEL_ADDR ((UINTN)0x100000)
|
||||
|
||||
/**
|
||||
Slide offset per slide entry
|
||||
**/
|
||||
#define SLIDE_GRANULARITY ((UINTN)0x200000)
|
||||
|
||||
/**
|
||||
Total possible number of KASLR slide offsets.
|
||||
**/
|
||||
#define TOTAL_SLIDE_NUM 256
|
||||
|
||||
/**
|
||||
Preserved relocation entry.
|
||||
**/
|
||||
typedef struct RT_RELOC_PROTECT_INFO_ {
|
||||
///
|
||||
/// Physical address of descriptor start.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
||||
///
|
||||
/// Physical address of descriptor end.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
||||
///
|
||||
/// Descriptor original memory type.
|
||||
///
|
||||
EFI_MEMORY_TYPE Type;
|
||||
} RT_RELOC_PROTECT_INFO;
|
||||
|
||||
/**
|
||||
Preserved relocation entry list.
|
||||
**/
|
||||
typedef struct RT_RELOC_PROTECT_DATA_ {
|
||||
///
|
||||
/// Number of currently used methods in the table.
|
||||
///
|
||||
UINTN NumEntries;
|
||||
///
|
||||
/// Reloc entries fitted.
|
||||
///
|
||||
RT_RELOC_PROTECT_INFO RelocInfo[RT_RELOC_PROTECT_MAX_NUM];
|
||||
} RT_RELOC_PROTECT_DATA;
|
||||
|
||||
/**
|
||||
UEFI Boot & Runtime Services original pointers.
|
||||
**/
|
||||
typedef struct UEFI_SERVICES_POINTERS_ {
|
||||
///
|
||||
/// Original page allocator. We override it to obtain
|
||||
/// the location macOS kernel and hibernation images.
|
||||
///
|
||||
EFI_ALLOCATE_PAGES AllocatePages;
|
||||
///
|
||||
/// Original memory map function. We override it to make
|
||||
/// memory map shrinking and CSM region protection.
|
||||
///
|
||||
EFI_GET_MEMORY_MAP GetMemoryMap;
|
||||
///
|
||||
/// Original exit boot services function. We override it
|
||||
/// to ensure we always succeed exiting boot services.
|
||||
///
|
||||
EFI_EXIT_BOOT_SERVICES ExitBootServices;
|
||||
///
|
||||
/// Image starting routine. We override to catch boot.efi
|
||||
/// loading and enable the rest of functions.
|
||||
///
|
||||
EFI_IMAGE_START StartImage;
|
||||
///
|
||||
/// Original get variable function. We override it to alter
|
||||
/// boot.efi boot arguments for custom KASLR slide.
|
||||
///
|
||||
EFI_GET_VARIABLE GetVariable;
|
||||
///
|
||||
/// Original virtual address mapping function. We override
|
||||
/// it to perform runtime area protection to prevent boot.efi
|
||||
/// defragmentation and setup virtual memory for firmwares
|
||||
/// accessing it after exit boot services.
|
||||
///
|
||||
EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap;
|
||||
} UEFI_SERVICES_POINTERS;
|
||||
|
||||
/**
|
||||
UEFI services override internal state.
|
||||
**/
|
||||
typedef struct SERVICES_OVERRIDE_STATE_ {
|
||||
///
|
||||
/// GetVariable arrival event.
|
||||
///
|
||||
EFI_EVENT GetVariableEvent;
|
||||
///
|
||||
/// Minimum address allocated by AlocatePages.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS MinAllocatedAddr;
|
||||
///
|
||||
/// Maximum address allocated by AlocatePages.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS MaxAllocatedAddr;
|
||||
///
|
||||
/// Apple hibernate image address allocated by AlocatePages.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS HibernateImageAddress;
|
||||
///
|
||||
/// Last descriptor size obtained from GetMemoryMap.
|
||||
///
|
||||
UINTN MemoryMapDescriptorSize;
|
||||
///
|
||||
/// Amount of nested boot.efi detected.
|
||||
///
|
||||
UINTN AppleBootNestedCount;
|
||||
///
|
||||
/// TRUE if we are doing boot.efi hibernate wake.
|
||||
///
|
||||
BOOLEAN AppleHibernateWake;
|
||||
///
|
||||
/// TRUE if we are using custom KASLR slide (via boot arg).
|
||||
///
|
||||
BOOLEAN AppleCustomSlide;
|
||||
} SERVICES_OVERRIDE_STATE;
|
||||
|
||||
/**
|
||||
Apple kernel support internal state..
|
||||
**/
|
||||
typedef struct KERNEL_SUPPORT_STATE_ {
|
||||
///
|
||||
/// Assembly support internal state.
|
||||
///
|
||||
ASM_SUPPORT_STATE AsmState;
|
||||
///
|
||||
/// Kernel jump trampoline.
|
||||
///
|
||||
ASM_KERNEL_JUMP KernelJump;
|
||||
///
|
||||
/// Original kernel memory.
|
||||
///
|
||||
UINT8 KernelOrg[sizeof (ASM_KERNEL_JUMP)];
|
||||
///
|
||||
/// Custom kernel UEFI System Table.
|
||||
///
|
||||
EFI_PHYSICAL_ADDRESS SysTableRtArea;
|
||||
///
|
||||
/// Virtual memory mapper context.
|
||||
///
|
||||
OC_VMEM_CONTEXT VmContext;
|
||||
///
|
||||
/// Virtual memory map containing partial memory map with runtime areas only.
|
||||
/// Actual number of entries may be less than RT_DESC_ENTRY_NUM due to DescriptorSize
|
||||
/// being potentially bigger than sizeof (EFI_MEMORY_DESCRIPTOR).
|
||||
///
|
||||
EFI_MEMORY_DESCRIPTOR VmMap[RT_DESC_ENTRY_NUM];
|
||||
///
|
||||
/// Virtual memory map size in bytes.
|
||||
///
|
||||
UINTN VmMapSize;
|
||||
///
|
||||
/// Virtual memory map descriptor size in bytes.
|
||||
///
|
||||
UINTN VmMapDescSize;
|
||||
} KERNEL_SUPPORT_STATE;
|
||||
|
||||
/**
|
||||
Apple Boot Compatibility context.
|
||||
**/
|
||||
typedef struct BOOT_COMPAT_CONTEXT_ {
|
||||
///
|
||||
/// Apple Coot Compatibility settings.
|
||||
///
|
||||
OC_ABC_SETTINGS Settings;
|
||||
///
|
||||
/// Runtime relocations.
|
||||
///
|
||||
RT_RELOC_PROTECT_DATA RtReloc;
|
||||
///
|
||||
/// UEFI Boot & Runtime Services original pointers.
|
||||
///
|
||||
UEFI_SERVICES_POINTERS ServicePtrs;
|
||||
///
|
||||
/// UEFI services override internal state.
|
||||
///
|
||||
SERVICES_OVERRIDE_STATE ServiceState;
|
||||
///
|
||||
/// Apple kernel support internal state.
|
||||
///
|
||||
KERNEL_SUPPORT_STATE KernelState;
|
||||
} BOOT_COMPAT_CONTEXT;
|
||||
|
||||
/**
|
||||
Obtain Apple Boot Compatibility context. This function must only
|
||||
be called from wrapped services, where passing context arguments
|
||||
is not possible.
|
||||
|
||||
@retval Apple Boot Compatibility context (not null).
|
||||
**/
|
||||
BOOT_COMPAT_CONTEXT *
|
||||
GetBootCompatContext (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Install UEFI services overrides as necessary.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
**/
|
||||
VOID
|
||||
InstallServiceOverrides (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *ServicePtrs
|
||||
);
|
||||
|
||||
/**
|
||||
Prepare virtual memory management environment for later usage.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
**/
|
||||
VOID
|
||||
AppleMapPrepareMemoryPool (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
|
||||
);
|
||||
|
||||
/**
|
||||
Prepare environment for Apple UEFI bootloader. See more details inside.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
@param[in,out] LoadedImage UEFI loaded image protocol instance.
|
||||
@param[in] GetMemoryMap Unmodified GetMemoryMap pointer, optional.
|
||||
**/
|
||||
VOID
|
||||
AppleMapPrepareBooterState (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN OUT EFI_LOADED_IMAGE *LoadedImage,
|
||||
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Save UEFI environment state in implementation specific way.
|
||||
|
||||
@param[in,out] AsmState Assembly state to update, can be preserved.
|
||||
@param[out] KernelJump Kernel jump trampoline to fill.
|
||||
**/
|
||||
VOID
|
||||
AppleMapPlatformSaveState (
|
||||
IN OUT ASM_SUPPORT_STATE *AsmState,
|
||||
OUT ASM_KERNEL_JUMP *KernelJump
|
||||
);
|
||||
|
||||
/**
|
||||
Patch kernel entry point with KernelJump to later land in AppleMapPrepareKernelState.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
@param[in] ImageAddress Kernel or hibernation image address.
|
||||
@param[in] AppleHibernateWake TRUE when ImageAddress points to hibernation image.
|
||||
**/
|
||||
VOID
|
||||
AppleMapPrepareKernelJump (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN UINTN ImageAddress,
|
||||
IN BOOLEAN AppleHibernateWake
|
||||
);
|
||||
|
||||
/**
|
||||
Patch kernel entry point with KernelJump to later land in AppleMapPrepareKernelState.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
@param[in] ImageAddress Kernel or hibernation image address.
|
||||
@param[in] AppleHibernateWake TRUE when ImageAddress points to hibernation image.
|
||||
**/
|
||||
EFI_STATUS
|
||||
AppleMapPrepareVmState (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN UINT32 DescriptorVersion,
|
||||
IN EFI_MEMORY_DESCRIPTOR *MemoryMap
|
||||
);
|
||||
|
||||
/**
|
||||
Prepare environment for Apple kernel bootloader in boot or wake cases.
|
||||
This callback arrives when boot.efi jumps to kernel.
|
||||
|
||||
@param[in] Args Case-specific kernel argument handle.
|
||||
@param[in] ModeX64 Debug flag about kernel context type, TRUE when X64.
|
||||
|
||||
@retval Args must be returned with the necessary modifications if any.
|
||||
**/
|
||||
UINTN
|
||||
EFIAPI
|
||||
AppleMapPrepareKernelState (
|
||||
IN UINTN Args,
|
||||
IN BOOLEAN ModeX64
|
||||
);
|
||||
|
||||
#endif // BOOT_COMPAT_INTERNAL_H
|
||||
655
Library/OcAppleBootCompatLib/KernelSupport.c
Normal file
655
Library/OcAppleBootCompatLib/KernelSupport.c
Normal file
@ -0,0 +1,655 @@
|
||||
/** @file
|
||||
Copyright (C) 2013, dmazar. All rights reserved.
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "BootCompatInternal.h"
|
||||
|
||||
#include <IndustryStandard/AppleHibernate.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcMachoLib.h>
|
||||
#include <Library/OcMemoryLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
/**
|
||||
Protect RT data from boot.efi relocation by marking them MemMapIO.
|
||||
See more details in the function definition.
|
||||
|
||||
@param[in,out] RtReloc Relocation entry list to store entry types.
|
||||
@param[in] MemoryMapSize Memory map size.
|
||||
@param[in] DescriptorSize Memory map descriptor size.
|
||||
@param[in,out] MemoryMap MemoryMap to protect entries in.
|
||||
@param[in] SysTableArea Special address that should not be protected.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
ProtectRtMemoryFromRelocation (
|
||||
IN OUT RT_RELOC_PROTECT_DATA *RtReloc,
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
||||
IN EFI_PHYSICAL_ADDRESS SysTableArea
|
||||
)
|
||||
{
|
||||
//
|
||||
// We protect RT data & code from relocation by marking them MemMapIO except EFI_SYSTEM_TABLE area.
|
||||
//
|
||||
// This fixes NVRAM issues on some boards where access to NVRAM after boot services is possible
|
||||
// only in SMM mode. RT driver passes data to SMM handler through previously negotiated buffer
|
||||
// and this buffer must not be relocated.
|
||||
// Explained and examined in detail by CodeRush and night199uk:
|
||||
// https://web.archive.org/web/20141025080709/http://www.projectosx.com/forum/lofiversion/index.php/t3298.html
|
||||
//
|
||||
// Starting with APTIO V for NVRAM to work not only RT data but RT code too can no longer be moved
|
||||
// due to the use of commbuffers. This, however, creates a memory protection issue, because
|
||||
// XNU maps RT data as RW and code as RX, and AMI appears use global variables in some RT drivers.
|
||||
// For this reason we shim (most?) affected RT services via wrapers that unset the WP bit during
|
||||
// the UEFI call and set it back on return in a separate driver.
|
||||
// Explained in detail by Download-Fritz and vit9696:
|
||||
// http://www.insanelymac.com/forum/topic/331381-aptiomemoryfix (first 2 links in particular).
|
||||
//
|
||||
// EFI_SYSTEM_TABLE is passed directly through kernel boot arguments, and thus goes through static
|
||||
// mapping (ml_static_ptovirt) in efi_set_tables_64 call. This mapping works as PHYS | CONST = VIRT.
|
||||
// To avoid kernel accessing unmapped virtual address we let boot.efi relocate the page with
|
||||
// EFI_SYSTEM_TABLE area. While technically it is possible to let the original page to be relocated,
|
||||
// we pick a safer root by using a private copy.
|
||||
//
|
||||
// The primary downside of this approach is that boot.efi will still reserve the contiguous memory
|
||||
// for runtime services after the kernel: efiRuntimeServicesPageCount pages starting from
|
||||
// efiRuntimeServicesPageStart within kaddr ~ ksize range. However, unlike Macs, which have reserved
|
||||
// gaps only for ACPI NVS, MemMapIO and similar regions, with this approach almost no physical memory
|
||||
// in efiRuntimeServicesPageStart area is used at all. This memory is never reclaimed by XNU, which
|
||||
// marks it as allocated in i386_vm_init. Expirements show that at least 85 MBs (Z170) are used for
|
||||
// this process. On server systems the issue is much worse due to many devices in place.
|
||||
// Ideally boot.efi should only count RT code and RT data pages, but it is not easy to change.
|
||||
//
|
||||
|
||||
UINTN NumEntries;
|
||||
UINTN Index;
|
||||
EFI_MEMORY_DESCRIPTOR *Desc;
|
||||
RT_RELOC_PROTECT_INFO *RelocInfo;
|
||||
|
||||
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 (RtReloc->NumEntries == ARRAY_SIZE (RtReloc->RelocInfo)) {
|
||||
RUNTIME_DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OCABC: Cannot save mem type for entry: %Lx (type 0x%x)\n",
|
||||
(UINT64) Desc->PhysicalStart,
|
||||
(UINT32) Desc->Type
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
RelocInfo->PhysicalStart = Desc->PhysicalStart;
|
||||
RelocInfo->PhysicalEnd = Desc->PhysicalStart + (EFI_PAGES_TO_SIZE (Desc->NumberOfPages) - 1);
|
||||
RelocInfo->Type = Desc->Type;
|
||||
Desc->Type = EfiMemoryMappedIO;
|
||||
++RelocInfo;
|
||||
++RtReloc->NumEntries;
|
||||
}
|
||||
|
||||
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Copy RT flagged areas to separate memmap, define virtual to physical address mapping,
|
||||
and call SetVirtualAddressMap() only with that partial memmap.
|
||||
|
||||
@param[in,out] KernelState Kernel support state.
|
||||
@param[in] MemoryMapSize Memory map size.
|
||||
@param[in] DescriptorSize Memory map descriptor size.
|
||||
@param[in] DescriptorVersion Memor map descriptor version.
|
||||
@param[in,out] MemoryMap Complete memory map with all entries.
|
||||
|
||||
@retval EFI_SUCCESS on success.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
PerformRtMemoryVirtualMapping (
|
||||
IN OUT KERNEL_SUPPORT_STATE *KernelState,
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN UINT32 DescriptorVersion,
|
||||
IN EFI_MEMORY_DESCRIPTOR *MemoryMap
|
||||
)
|
||||
{
|
||||
//
|
||||
// About partial memmap:
|
||||
// Some UEFIs are converting pointers to virtual addresses even if they do not
|
||||
// point to regions with RT flag. This means that those UEFIs are using
|
||||
// Desc->VirtualStart even for non-RT regions. Linux had issues with this:
|
||||
// http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7cb00b72876ea2451eb79d468da0e8fb9134aa8a
|
||||
// They are doing it Windows way now - copying RT descriptors to separate
|
||||
// mem map and passing that stripped map to SetVirtualAddressMap().
|
||||
// We'll do the same, although it seems that just assigning
|
||||
// VirtualStart = PhysicalStart for non-RT areas also does the job.
|
||||
//
|
||||
// About virtual to physical mappings:
|
||||
// Also adds virtual to physical address mappings for RT areas. This is needed since
|
||||
// SetVirtualAddressMap() does not work on my Aptio without that. Probably because some driver
|
||||
// has a bug and is trying to access new virtual addresses during the change.
|
||||
// Linux and Windows are doing the same thing and problem is
|
||||
// not visible there.
|
||||
//
|
||||
|
||||
UINTN NumEntries;
|
||||
UINTN Index;
|
||||
EFI_MEMORY_DESCRIPTOR *Desc;
|
||||
EFI_MEMORY_DESCRIPTOR *VirtualDesc;
|
||||
EFI_STATUS Status;
|
||||
PAGE_MAP_AND_DIRECTORY_POINTER *PageTable;
|
||||
UINTN Flags;
|
||||
|
||||
Desc = MemoryMap;
|
||||
NumEntries = MemoryMapSize / DescriptorSize;
|
||||
VirtualDesc = KernelState->VmMap;
|
||||
KernelState->VmMapSize = 0;
|
||||
KernelState->VmMapDescSize = DescriptorSize;
|
||||
|
||||
//
|
||||
// Get current VM page table
|
||||
//
|
||||
GetCurrentPageTable (&PageTable, &Flags);
|
||||
|
||||
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:
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
if (Desc->Type != EfiReservedMemoryType && (Desc->Attribute & EFI_MEMORY_RUNTIME) != 0) {
|
||||
//
|
||||
// Check if there is enough space in virtual map.
|
||||
//
|
||||
if (KernelState->VmMapSize + DescriptorSize > sizeof (KernelState->VmMap)) {
|
||||
RUNTIME_DEBUG ((DEBUG_ERROR, "OCABC: Too many RT entries to memory map\n"));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy region with EFI_MEMORY_RUNTIME flag to virtual map.
|
||||
//
|
||||
CopyMem (VirtualDesc, Desc, DescriptorSize);
|
||||
|
||||
//
|
||||
// Define virtual to physical mapping.
|
||||
//
|
||||
Status = VmMapVirtualPages (
|
||||
&KernelState->VmContext,
|
||||
PageTable,
|
||||
Desc->VirtualStart,
|
||||
Desc->NumberOfPages,
|
||||
Desc->PhysicalStart
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
RUNTIME_DEBUG ((DEBUG_ERROR, "OCABC: RT mapping failure - %r\n", Status));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Proceed to next virtual map slot.
|
||||
//
|
||||
VirtualDesc = NEXT_MEMORY_DESCRIPTOR (VirtualDesc, DescriptorSize);
|
||||
KernelState->VmMapSize += DescriptorSize;
|
||||
}
|
||||
|
||||
//
|
||||
// Proceed to next original map slot.
|
||||
//
|
||||
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
|
||||
}
|
||||
|
||||
VmFlushCaches ();
|
||||
|
||||
Status = gRT->SetVirtualAddressMap (
|
||||
KernelState->VmMapSize,
|
||||
DescriptorSize,
|
||||
DescriptorVersion,
|
||||
KernelState->VmMap
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Revert RT data protected types to let XNU kernel kernel properly map data.
|
||||
|
||||
@param[in] RtReloc Relocated entry list with entry types.
|
||||
@param[in] MemoryMapSize Memory map size.
|
||||
@param[in] DescriptorSize Memory map descriptor size.
|
||||
@param[in,out] MemoryMap MemoryMap to restore protected entries in.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
RestoreProtectedRtMemoryTypes (
|
||||
IN RT_RELOC_PROTECT_DATA *RtReloc,
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
UINTN Index2;
|
||||
UINTN NumEntriesLeft;
|
||||
UINTN NumEntries;
|
||||
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);
|
||||
|
||||
for (Index2 = 0; Index2 < RtReloc->NumEntries; ++Index2) {
|
||||
//
|
||||
// I would expect PhysicalStart and PhysicalEnd to always match here, but
|
||||
// the region can be merged with a nearby one, thus we check for overlap
|
||||
// rather than full match. "Desc contains RtReloc" should also do.
|
||||
//
|
||||
if (PhysicalStart <= RtReloc->RelocInfo[Index2].PhysicalEnd
|
||||
&& RtReloc->RelocInfo[Index2].PhysicalStart <= PhysicalEnd) {
|
||||
Desc->Type = RtReloc->RelocInfo[Index2].Type;
|
||||
Found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (Found) {
|
||||
--NumEntriesLeft;
|
||||
}
|
||||
|
||||
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
|
||||
}
|
||||
|
||||
if (NumEntriesLeft > 0) {
|
||||
RUNTIME_DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OCABC: Failed to restore %u entries out of %u\n",
|
||||
(UINT32) NumEntriesLeft,
|
||||
(UINT32) RtReloc->NumEntries
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Prepare environment for normal booting. Called when boot.efi jumps to kernel.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
@param[in,out] BootArgs Apple kernel boot arguments.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
AppleMapPrepareForBooting (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN OUT VOID *BootArgs
|
||||
)
|
||||
{
|
||||
OC_BOOT_ARGUMENTS BA;
|
||||
UINTN MemoryMapSize;
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
||||
UINTN DescriptorSize;
|
||||
|
||||
OcParseBootArgs (&BA, BootArgs);
|
||||
|
||||
//
|
||||
// FIXME: Restore the variables we tempered with to support custom slides.
|
||||
//
|
||||
// RestoreCustomSlideOverrides (&BA);
|
||||
|
||||
MemoryMapSize = *BA.MemoryMapSize;
|
||||
MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN) (*BA.MemoryMap);
|
||||
DescriptorSize = *BA.MemoryMapDescriptorSize;
|
||||
|
||||
//
|
||||
// We must restore EfiRuntimeServicesCode memory area types, because otherwise
|
||||
// RuntimeServices won't be mapped.
|
||||
//
|
||||
RestoreProtectedRtMemoryTypes (
|
||||
&BootCompat->RtReloc,
|
||||
MemoryMapSize,
|
||||
DescriptorSize,
|
||||
MemoryMap
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Prepare environment for hibernate wake. Called when boot.efi jumps to kernel.
|
||||
|
||||
@param[in,out] BootCompat Boot compatibility context.
|
||||
@param[in,out] ImageHeaderPage Apple hibernate image page number.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
AppleMapPrepareForHibernateWake (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN UINTN ImageHeaderPage
|
||||
)
|
||||
{
|
||||
IOHibernateImageHeader *ImageHeader;
|
||||
IOHibernateHandoff *Handoff;
|
||||
|
||||
ImageHeader = (IOHibernateImageHeader *) EFI_PAGES_TO_SIZE (ImageHeaderPage);
|
||||
|
||||
//
|
||||
// Legacy note. In legacy implementations systemTableOffset was unconditionally overwritten
|
||||
// with a wrong address due to ImageHeader->runtimePages not being converted from pages to bytes.
|
||||
// Fortunately systemTableOffset was unused when kIOHibernateHandoffTypeMemoryMap is unspecified.
|
||||
// systemTableOffset is calculated properly by boot.efi itself starting from 10.6.8 at least,
|
||||
// and thus this assignment was useless in the first place.
|
||||
//
|
||||
|
||||
//
|
||||
// At this step we have two routes.
|
||||
//
|
||||
// 1. Remove newly generated memory map from hibernate image to let XNU use the original mapping.
|
||||
// This is known to work well on most systems primarily because Windows requires UEFI firmwares
|
||||
// to preserve physical memory consistency at S4 wake. "On a UEFI platform, firmware runtime memory
|
||||
// must be consistent across S4 sleep state transitions, in both size and location.", see:
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-uefi#hibernation-state-s4-transition-requirements
|
||||
// 2. Recover memory map just as we do for normal booting. This was causing issues on some firmwares,
|
||||
// which provided very strange memory maps after S4 wake. In other cases this should not immediately
|
||||
// break things. XNU will entirely remove efiRuntimeServicesPageStart/efiRuntimeServicesPageSize
|
||||
// mapping, and our new memory map entries will unconditionally overwrite previous ones. In case
|
||||
// no physical memory changes happened this should work fine.
|
||||
//
|
||||
Handoff = (IOHibernateHandoff *) EFI_PAGES_TO_SIZE ((UINTN) ImageHeader->handoffPages);
|
||||
while (Handoff->type != kIOHibernateHandoffTypeEnd) {
|
||||
if (Handoff->type == kIOHibernateHandoffTypeMemoryMap) {
|
||||
if (BootCompat->Settings.DiscardAppleS4Map) {
|
||||
//
|
||||
// Route 1. Discard the new memory map here, and let XNU use what it had.
|
||||
//
|
||||
Handoff->type = kIOHibernateHandoffType;
|
||||
} else {
|
||||
//
|
||||
// Route 2. Recovery memory protection types just as normal boot.
|
||||
//
|
||||
|
||||
if (BootCompat->KernelState.VmMapDescSize == 0) {
|
||||
RUNTIME_DEBUG (("OCABC: Saved descriptor size cannot be 0\n"));
|
||||
BootCompat->KernelState.VmMapDescSize = sizeof (EFI_MEMORY_DESCRIPTOR);
|
||||
}
|
||||
|
||||
RestoreProtectedRtMemoryTypes (
|
||||
&BootCompat->RtReloc,
|
||||
Handoff->bytecount,
|
||||
MIN (BootCompat->KernelState.VmMapDescSize, sizeof (EFI_MEMORY_DESCRIPTOR)),
|
||||
(EFI_MEMORY_DESCRIPTOR *)(UINTN) Handoff->data
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Handoff = (IOHibernateHandoff *) ((UINTN) Handoff + sizeof(Handoff) + Handoff->bytecount);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
AppleMapPrepareMemoryPool (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = VmAllocateMemoryPool (
|
||||
&BootCompat->KernelState.VmContext,
|
||||
OC_DEFAULT_VMEM_PAGE_COUNT
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "OCABC: Memory pool allocation failure - %r\n", Status));
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
AppleMapPrepareBooterState (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN OUT EFI_LOADED_IMAGE *LoadedImage,
|
||||
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// This function may be called twice, do not redo in this case.
|
||||
//
|
||||
if (BootCompat->KernelState.SysTableRtArea == 0) {
|
||||
AppleMapPlatformSaveState (
|
||||
&BootCompat->KernelState.AsmState,
|
||||
&BootCompat->KernelState.KernelJump
|
||||
);
|
||||
|
||||
//
|
||||
// Allocate 1 RT data page 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;
|
||||
Status = AllocatePagesFromTop (
|
||||
EfiRuntimeServicesData,
|
||||
1,
|
||||
&BootCompat->KernelState.SysTableRtArea,
|
||||
GetMemoryMap,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OCABC: Failed to allocate system table memory - %r\n",
|
||||
Status
|
||||
));
|
||||
BootCompat->KernelState.SysTableRtArea = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// 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)
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Assign loaded image with custom system table.
|
||||
//
|
||||
LoadedImage->SystemTable =
|
||||
(EFI_SYSTEM_TABLE *)(UINTN) BootCompat->KernelState.SysTableRtArea;
|
||||
}
|
||||
|
||||
VOID
|
||||
AppleMapPrepareKernelJump (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN UINTN ImageAddress,
|
||||
IN BOOLEAN AppleHibernateWake
|
||||
)
|
||||
{
|
||||
UINT8 *KernelEntry;
|
||||
UINTN SlideAddr;
|
||||
VOID *MachOImage;
|
||||
IOHibernateImageHeader *ImageHeader;
|
||||
|
||||
if (!AppleHibernateWake) {
|
||||
//
|
||||
// Read kernel entry from Mach-O load command and patch it with jump.
|
||||
//
|
||||
SlideAddr = ImageAddress - BASE_KERNEL_ADDR;
|
||||
MachOImage = (VOID*) (SlideAddr + SLIDE_GRANULARITY);
|
||||
KernelEntry = (UINT8*) MachoRuntimeGetEntryAddress (MachOImage);
|
||||
if (KernelEntry != 0) {
|
||||
KernelEntry += SlideAddr;
|
||||
}
|
||||
} 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.
|
||||
//
|
||||
ImageHeader = (IOHibernateImageHeader *) ImageAddress;
|
||||
KernelEntry = (UINT8 *) &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,
|
||||
sizeof (BootCompat->KernelState.KernelOrg)
|
||||
);
|
||||
|
||||
//
|
||||
// Copy kernel jump code to kernel entry address.
|
||||
//
|
||||
CopyMem (
|
||||
KernelEntry,
|
||||
&BootCompat->KernelState.KernelJump,
|
||||
sizeof (BootCompat->KernelState.KernelJump)
|
||||
);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
AppleMapPrepareVmState (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN UINT32 DescriptorVersion,
|
||||
IN EFI_MEMORY_DESCRIPTOR *MemoryMap
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Protect RT areas from relocation by marking then MemMapIO.
|
||||
//
|
||||
ProtectRtMemoryFromRelocation (
|
||||
&BootCompat->RtReloc,
|
||||
MemoryMapSize,
|
||||
DescriptorSize,
|
||||
MemoryMap,
|
||||
BootCompat->KernelState.SysTableRtArea
|
||||
);
|
||||
|
||||
//
|
||||
// Virtualize RT services with all needed fixes.
|
||||
//
|
||||
Status = PerformRtMemoryVirtualMapping (
|
||||
&BootCompat->KernelState,
|
||||
MemoryMapSize,
|
||||
DescriptorSize,
|
||||
DescriptorVersion,
|
||||
MemoryMap
|
||||
);
|
||||
|
||||
//
|
||||
// Copy now virtualized UEFI system table for boot.efi to hand it to the kernel.
|
||||
//
|
||||
CopyMem (
|
||||
(VOID *)(UINTN) BootCompat->KernelState.SysTableRtArea,
|
||||
gST,
|
||||
gST->Hdr.HeaderSize
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
UINTN
|
||||
EFIAPI
|
||||
AppleMapPrepareKernelState (
|
||||
IN UINTN Args,
|
||||
IN BOOLEAN ModeX64
|
||||
)
|
||||
{
|
||||
BOOT_COMPAT_CONTEXT *BootCompatContext;
|
||||
|
||||
BootCompatContext = GetBootCompatContext ();
|
||||
|
||||
if (BootCompatContext->ServiceState.AppleHibernateWake) {
|
||||
AppleMapPrepareForHibernateWake (
|
||||
BootCompatContext,
|
||||
Args
|
||||
);
|
||||
} else {
|
||||
AppleMapPrepareForBooting (
|
||||
BootCompatContext,
|
||||
(VOID *) Args
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Restore original kernel entry code.
|
||||
//
|
||||
CopyMem (
|
||||
BootCompatContext->KernelState.AsmState.KernelEntry,
|
||||
&BootCompatContext->KernelState.KernelOrg[0],
|
||||
sizeof (BootCompatContext->KernelState.KernelOrg)
|
||||
);
|
||||
|
||||
return Args;
|
||||
}
|
||||
114
Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c
Normal file
114
Library/OcAppleBootCompatLib/OcAppleBootCompatLib.c
Normal file
@ -0,0 +1,114 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcAppleBootCompatLib.h>
|
||||
#include <Library/OcDevicePathLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
#include <Protocol/OcAppleBootCompat.h>
|
||||
|
||||
#include "BootCompatInternal.h"
|
||||
|
||||
/**
|
||||
Apple Boot Compatibility protocol instance. Its GUID matches
|
||||
with legacy AptioMemoryFix protocol, allowing us to avoid
|
||||
conflicts between the two.
|
||||
**/
|
||||
STATIC OC_APPLE_BOOT_COMPAT_PROTOCOL mOcAppleBootCompatProtocol = {
|
||||
OC_APPLE_BOOT_COMPAT_PROTOCOL_REVISION
|
||||
};
|
||||
|
||||
/**
|
||||
Apple Boot Compatibility context. This context is used throughout
|
||||
the library. Must be accessed through GetBootCompatContext ().
|
||||
**/
|
||||
STATIC BOOT_COMPAT_CONTEXT mOcAppleBootCompatContext;
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
InstallAbcProtocol (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *Interface;
|
||||
EFI_HANDLE Handle;
|
||||
|
||||
Status = gBS->LocateProtocol (
|
||||
&gOcAppleBootCompatProtocolGuid,
|
||||
NULL,
|
||||
&Interface
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Ensure we do not run with AptioMemoryFix.
|
||||
// It also checks for attempts to install this protocol twice.
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "OCABC: Found legacy AptioMemoryFix driver!\n"));
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
Handle = NULL;
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Handle,
|
||||
&gOcAppleBootCompatProtocolGuid,
|
||||
&mOcAppleBootCompatProtocol,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "OCABC: protocol install failure - %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
BOOT_COMPAT_CONTEXT *
|
||||
GetBootCompatContext (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &mOcAppleBootCompatContext;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcAbcInitialize (
|
||||
IN OC_ABC_SETTINGS *Settings
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = InstallAbcProtocol ();
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
InstallServiceOverrides (
|
||||
GetBootCompatContext ()
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
64
Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf
Normal file
64
Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf
Normal file
@ -0,0 +1,64 @@
|
||||
## @file
|
||||
#
|
||||
# Component description file for the library producing the Apple Device property protocol.
|
||||
#
|
||||
# Copyright (C) 2019, vit9696. All rights reserved.<BR>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = OcAppleBootCompatLib
|
||||
FILE_GUID = A393F7CF-3966-4C7E-8763-3DD991681C9B
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = OcAppleBootCompatLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_SMM_DRIVER
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
BootCompatInternal.h
|
||||
KernelSupport.c
|
||||
OcAppleBootCompatLib.c
|
||||
ServiceOverrides.c
|
||||
|
||||
[Sources.X64]
|
||||
X64/ContextSwitch.nasm
|
||||
X64/ContextSwitchSupport.c
|
||||
|
||||
[Packages]
|
||||
OcSupportPkg/OcSupportPkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
EfiPkg/EfiPkg.dec
|
||||
|
||||
[Guids]
|
||||
gAppleBootVariableGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[Protocols]
|
||||
gOcAppleBootCompatProtocolGuid ## PRODUCES
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
DevicePathLib
|
||||
MemoryAllocationLib
|
||||
PrintLib
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeServicesTableLib
|
||||
OcGuardLib
|
||||
OcMemoryLib
|
||||
565
Library/OcAppleBootCompatLib/ServiceOverrides.c
Normal file
565
Library/OcAppleBootCompatLib/ServiceOverrides.c
Normal file
@ -0,0 +1,565 @@
|
||||
/** @file
|
||||
Copyright (C) 2013, dmazar. All rights reserved.
|
||||
Copyright (C) 2017, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "BootCompatInternal.h"
|
||||
|
||||
#include <IndustryStandard/AppleHibernate.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcMemoryLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Protocol/OcFirmwareRuntime.h>
|
||||
|
||||
/**
|
||||
Helper function to call ExitBootServices that can handle outdated MapKey issues.
|
||||
|
||||
@param[in] ExitBootServices ExitBootServices function pointer, optional.
|
||||
@param[in] GetMemoryMap GetMemoryMap function pointer, optional.
|
||||
@param[in] ImageHandle Image handle to call ExitBootServices on.
|
||||
@param[in] MapKey MapKey to call ExitBootServices on.
|
||||
|
||||
@retval EFI_SUCCESS on success.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
ForceExitBootServices (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN UINTN MapKey,
|
||||
IN EFI_EXIT_BOOT_SERVICES ExitBootServices OPTIONAL,
|
||||
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
||||
UINTN MemoryMapSize;
|
||||
UINTN DescriptorSize;
|
||||
UINT32 DescriptorVersion;
|
||||
|
||||
if (ExitBootServices == NULL) {
|
||||
ExitBootServices = gBS->ExitBootServices;
|
||||
}
|
||||
|
||||
if (GetMemoryMap == NULL) {
|
||||
GetMemoryMap = gBS->GetMemoryMap;
|
||||
}
|
||||
|
||||
//
|
||||
// Firstly try the easy way.
|
||||
//
|
||||
Status = ExitBootServices (ImageHandle, MapKey);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// 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 = GetCurrentMemoryMapAlloc (
|
||||
&MemoryMapSize,
|
||||
&MemoryMap,
|
||||
&MapKey,
|
||||
&DescriptorSize,
|
||||
&DescriptorVersion,
|
||||
GetMemoryMap,
|
||||
NULL
|
||||
);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
//
|
||||
// We have the latest memory map and its key, try again!
|
||||
//
|
||||
Status = ExitBootServices (ImageHandle, MapKey);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "OCABC: ExitBootServices failed twice - %r\n", Status));
|
||||
}
|
||||
} else {
|
||||
DEBUG ((DEBUG_WARN, "OCABC: Failed to get MapKey for ExitBootServices - %r\n", Status));
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "OCABC: Waiting 10 secs...\n"));
|
||||
gBS->Stall (SECONDS_TO_MICROSECONDS (10));
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Boot Services StartImage override. Called to start an efi image.
|
||||
If this is boot.efi, then our overrides are enabled.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcStartImage (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
OUT UINTN *ExitDataSize,
|
||||
OUT CHAR16 **ExitData OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *AppleLoadedImage;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
AppleLoadedImage = OcGetAppleBootLoadedImage (ImageHandle);
|
||||
|
||||
//
|
||||
// Clear monitoring vars
|
||||
//
|
||||
BootCompat->ServiceState.MinAllocatedAddr = 0;
|
||||
BootCompat->ServiceState.MaxAllocatedAddr = 0;
|
||||
|
||||
if (AppleLoadedImage != NULL) {
|
||||
//
|
||||
// Report about macOS being loaded.
|
||||
//
|
||||
++BootCompat->ServiceState.AppleBootNestedCount;
|
||||
BootCompat->ServiceState.AppleHibernateWake = OcIsAppleHibernateWake ();
|
||||
BootCompat->ServiceState.AppleCustomSlide = OcCheckArgumentFromEnv (
|
||||
AppleLoadedImage,
|
||||
BootCompat->ServicePtrs.GetVariable,
|
||||
"slide=",
|
||||
L_STR_LEN ("slide=")
|
||||
);
|
||||
|
||||
if (BootCompat->Settings.EnableAppleSmSlide) {
|
||||
// FIXME: Implement.
|
||||
//UnlockSlideSupportForSafeMode (
|
||||
// (UINT8 *) AppleLoadedImage->ImageBase,
|
||||
// AppleLoadedImage->ImageSize
|
||||
// );
|
||||
}
|
||||
|
||||
if (BootCompat->Settings.SetupAppleMap) {
|
||||
AppleMapPrepareBooterState (
|
||||
BootCompat,
|
||||
AppleLoadedImage,
|
||||
BootCompat->ServicePtrs.GetMemoryMap
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Status = BootCompat->ServicePtrs.StartImage (
|
||||
ImageHandle,
|
||||
ExitDataSize,
|
||||
ExitData
|
||||
);
|
||||
|
||||
if (AppleLoadedImage != NULL) {
|
||||
//
|
||||
// We failed but other operating systems should be loadable.
|
||||
//
|
||||
--BootCompat->ServiceState.AppleBootNestedCount;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Boot Services AllocatePages override.
|
||||
Returns pages from free memory block to boot.efi for kernel boot image.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcAllocatePages (
|
||||
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;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
|
||||
Status = BootCompat->ServicePtrs.AllocatePages (
|
||||
Type,
|
||||
MemoryType,
|
||||
NumberOfPages,
|
||||
Memory
|
||||
);
|
||||
|
||||
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.
|
||||
//
|
||||
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) {
|
||||
//
|
||||
// Called from boot.efi during hibernate wake,
|
||||
// first such allocation is for hibernate image
|
||||
//
|
||||
BootCompat->ServiceState.HibernateImageAddress = *Memory;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Boot Services GetMemoryMap override.
|
||||
Returns shrinked memory map as XNU can handle up to PMAP_MEMORY_REGIONS_SIZE (128) entries.
|
||||
Also applies any further memory map alterations as necessary.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcGetMemoryMap (
|
||||
IN OUT UINTN *MemoryMapSize,
|
||||
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
||||
OUT UINTN *MapKey,
|
||||
OUT UINTN *DescriptorSize,
|
||||
OUT UINT32 *DescriptorVersion
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
|
||||
Status = BootCompat->ServicePtrs.GetMemoryMap (
|
||||
MemoryMapSize,
|
||||
MemoryMap,
|
||||
MapKey,
|
||||
DescriptorSize,
|
||||
DescriptorVersion
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
|
||||
if (BootCompat->Settings.ProtectCsmRegion) {
|
||||
// FIXME: Implement.
|
||||
//ProtectCsmRegion (
|
||||
// *MemoryMapSize,
|
||||
// MemoryMap,
|
||||
// *DescriptorSize
|
||||
// );
|
||||
}
|
||||
|
||||
if (BootCompat->Settings.ShrinkMemoryMap) {
|
||||
ShrinkMemoryMap (
|
||||
MemoryMapSize,
|
||||
MemoryMap,
|
||||
*DescriptorSize
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Remember some descriptor size, since we will not have it later
|
||||
// during hibernate wake to be able to iterate memory map.
|
||||
//
|
||||
BootCompat->ServiceState.MemoryMapDescriptorSize = *DescriptorSize;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Boot Services ExitBootServices override.
|
||||
Patches kernel entry point with jump to our KernelEntryPatchJumpBack().
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcExitBootServices (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN UINTN MapKey
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
|
||||
//
|
||||
// For non-macOS operating systems return directly.
|
||||
//
|
||||
if (BootCompat->ServiceState.AppleBootNestedCount == 0) {
|
||||
return BootCompat->ServicePtrs.ExitBootServices (
|
||||
ImageHandle,
|
||||
MapKey
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// We need hibernate image address for wake, check it quickly before
|
||||
// killing boot services to be able to print the error.
|
||||
//
|
||||
if (BootCompat->Settings.SetupAppleMap
|
||||
&& BootCompat->ServiceState.AppleHibernateWake
|
||||
&& BootCompat->ServiceState.HibernateImageAddress == 0) {
|
||||
DEBUG ((DEBUG_ERROR, "OCABC: Failed to find hibernate image address\n"));
|
||||
gBS->Stall (SECONDS_TO_MICROSECONDS (5));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (BootCompat->Settings.ForceExitBootServices) {
|
||||
Status = ForceExitBootServices (
|
||||
ImageHandle,
|
||||
MapKey,
|
||||
BootCompat->ServicePtrs.ExitBootServices,
|
||||
BootCompat->ServicePtrs.GetMemoryMap
|
||||
);
|
||||
} else {
|
||||
Status = BootCompat->ServicePtrs.ExitBootServices (
|
||||
ImageHandle,
|
||||
MapKey
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Abort on error or when we are not supposed to do extra mapping.
|
||||
//
|
||||
if (EFI_ERROR (Status) || !BootCompat->Settings.SetupAppleMap) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!BootCompat->ServiceState.AppleHibernateWake) {
|
||||
AppleMapPrepareKernelJump (
|
||||
BootCompat,
|
||||
(UINTN) BootCompat->ServiceState.MinAllocatedAddr,
|
||||
FALSE
|
||||
);
|
||||
} else {
|
||||
AppleMapPrepareKernelJump (
|
||||
BootCompat,
|
||||
(UINTN) BootCompat->ServiceState.HibernateImageAddress,
|
||||
TRUE
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Runtime Services SetVirtualAddressMap override.
|
||||
Fixes virtualizing of RT services.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcSetVirtualAddressMap (
|
||||
IN UINTN MemoryMapSize,
|
||||
IN UINTN DescriptorSize,
|
||||
IN UINT32 DescriptorVersion,
|
||||
IN EFI_MEMORY_DESCRIPTOR *MemoryMap
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
|
||||
//
|
||||
// This is the time for us to remove our hacks.
|
||||
// Make SetVirtualAddressMap useable once again.
|
||||
// We do not need to recover BS, since they already are invalid.
|
||||
//
|
||||
gRT->SetVirtualAddressMap = BootCompat->ServicePtrs.SetVirtualAddressMap;
|
||||
gRT->Hdr.CRC32 = 0;
|
||||
gRT->Hdr.CRC32 = CalculateCrc32 (gRT, gRT->Hdr.HeaderSize);
|
||||
|
||||
//
|
||||
// For non-macOS operating systems return directly.
|
||||
// Also do nothing for custom mapping.
|
||||
//
|
||||
if (BootCompat->ServiceState.AppleBootNestedCount == 0
|
||||
|| !BootCompat->Settings.SetupAppleMap) {
|
||||
Status = gRT->SetVirtualAddressMap (
|
||||
MemoryMapSize,
|
||||
DescriptorSize,
|
||||
DescriptorVersion,
|
||||
MemoryMap
|
||||
);
|
||||
} else {
|
||||
Status = AppleMapPrepareVmState (
|
||||
BootCompat,
|
||||
MemoryMapSize,
|
||||
DescriptorSize,
|
||||
DescriptorVersion,
|
||||
MemoryMap
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Runtime Services GetVariable override.
|
||||
Used to return customised values for boot-args and csr-active-config variables.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcGetVariable (
|
||||
IN CHAR16 *VariableName,
|
||||
IN EFI_GUID *VendorGuid,
|
||||
OUT UINT32 *Attributes OPTIONAL,
|
||||
IN OUT UINTN *DataSize,
|
||||
OUT VOID *Data
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOT_COMPAT_CONTEXT *BootCompat;
|
||||
|
||||
BootCompat = GetBootCompatContext ();
|
||||
|
||||
if (BootCompat->Settings.SetupAppleSlide) {
|
||||
// FIXME: Implement
|
||||
}
|
||||
|
||||
Status = BootCompat->ServicePtrs.GetVariable (
|
||||
VariableName,
|
||||
VendorGuid,
|
||||
Attributes,
|
||||
DataSize,
|
||||
Data
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
UEFI Runtime Services GetVariable override event handler.
|
||||
We do not override GetVariable ourselves but let our runtime do that.
|
||||
|
||||
@param[in] Event Event handle.
|
||||
@param[in] Context Services pointers context.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
SetGetVariableHookHandler (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
OC_FIRMWARE_RUNTIME_PROTOCOL *FwRuntime;
|
||||
UEFI_SERVICES_POINTERS *ServicePtrs;
|
||||
|
||||
ServicePtrs = (UEFI_SERVICES_POINTERS *) Context;
|
||||
|
||||
if (ServicePtrs->GetVariable == NULL) {
|
||||
Status = gBS->LocateProtocol (
|
||||
&gOcFirmwareRuntimeProtocolGuid,
|
||||
NULL,
|
||||
(VOID **) &FwRuntime
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status) && FwRuntime->Revision == OC_FIRMWARE_RUNTIME_REVISION) {
|
||||
FwRuntime->OnGetVariable (OcGetVariable, &ServicePtrs->GetVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
InstallServiceOverrides (
|
||||
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *Registration;
|
||||
UEFI_SERVICES_POINTERS *ServicePtrs;
|
||||
|
||||
ServicePtrs = &BootCompat->ServicePtrs;
|
||||
|
||||
ServicePtrs->AllocatePages = gBS->AllocatePages;
|
||||
ServicePtrs->GetMemoryMap = gBS->GetMemoryMap;
|
||||
ServicePtrs->ExitBootServices = gBS->ExitBootServices;
|
||||
ServicePtrs->StartImage = gBS->StartImage;
|
||||
ServicePtrs->SetVirtualAddressMap = gRT->SetVirtualAddressMap;
|
||||
|
||||
gBS->AllocatePages = OcAllocatePages;
|
||||
gBS->GetMemoryMap = OcGetMemoryMap;
|
||||
gBS->ExitBootServices = OcExitBootServices;
|
||||
gBS->StartImage = OcStartImage;
|
||||
gRT->SetVirtualAddressMap = OcSetVirtualAddressMap;
|
||||
|
||||
gBS->Hdr.CRC32 = 0;
|
||||
gBS->Hdr.CRC32 = CalculateCrc32 (gBS, gBS->Hdr.HeaderSize);
|
||||
|
||||
gRT->Hdr.CRC32 = 0;
|
||||
gRT->Hdr.CRC32 = CalculateCrc32 (gRT, gRT->Hdr.HeaderSize);
|
||||
|
||||
//
|
||||
// Allocate memory pool if needed.
|
||||
//
|
||||
if (BootCompat->Settings.SetupAppleMap) {
|
||||
AppleMapPrepareMemoryPool (
|
||||
BootCompat
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Update GetVariable handle with the help of external runtime services.
|
||||
//
|
||||
SetGetVariableHookHandler (NULL, ServicePtrs);
|
||||
|
||||
if (ServicePtrs->GetVariable != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
SetGetVariableHookHandler,
|
||||
ServicePtrs,
|
||||
&BootCompat->ServiceState.GetVariableEvent
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = gBS->RegisterProtocolNotify (
|
||||
&gOcFirmwareRuntimeProtocolGuid,
|
||||
BootCompat->ServiceState.GetVariableEvent,
|
||||
&Registration
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->CloseEvent (&BootCompat->ServiceState.GetVariableEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Library/OcAppleBootCompatLib/X64/ContextSwitch.h
Normal file
89
Library/OcAppleBootCompatLib/X64/ContextSwitch.h
Normal file
@ -0,0 +1,89 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#ifndef CONTEXT_SWITCH_H
|
||||
#define CONTEXT_SWITCH_H
|
||||
|
||||
//
|
||||
// Structure definitions shared with ASM code.
|
||||
// Keep these definitions in sync with ContextSwitch.nasm!
|
||||
//
|
||||
|
||||
/**
|
||||
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_ {
|
||||
UINT64 SavedGDTR;
|
||||
UINT16 SavedGDTRLimit;
|
||||
UINT64 SavedIDTR;
|
||||
UINT16 SavedIDTRLimit;
|
||||
UINT64 SavedCR3;
|
||||
UINT16 SavedCS;
|
||||
UINT16 SavedDS;
|
||||
UINT16 SavedES;
|
||||
UINT16 SavedFS;
|
||||
UINT16 SavedGS;
|
||||
UINT16 SavedSS;
|
||||
|
||||
UINT64 SavedGDTR32;
|
||||
UINT16 SavedGDTR32Limit;
|
||||
UINT64 SavedIDTR32;
|
||||
UINT16 SavedIDTR32Limit;
|
||||
UINT16 SavedCS32;
|
||||
UINT16 SavedDS32;
|
||||
UINT16 SavedES32;
|
||||
UINT16 SavedFS32;
|
||||
UINT16 SavedGS32;
|
||||
UINT16 SavedSS32;
|
||||
UINT32 SavedESP32;
|
||||
|
||||
VOID *KernelEntry;
|
||||
} ASM_SUPPORT_STATE;
|
||||
|
||||
/**
|
||||
Assembly kernel trampoline.
|
||||
This structure contains encoded assembly to jump from kernel
|
||||
code to UEFI code through AsmAppleMapPlatformPrepareKernelState
|
||||
intermediate handler.
|
||||
**/
|
||||
typedef struct ASM_KERNEL_JUMP_ {
|
||||
UINT8 MovInst;
|
||||
UINT32 Addr;
|
||||
UINT16 CallInst;
|
||||
} ASM_KERNEL_JUMP;
|
||||
|
||||
VOID
|
||||
EFIAPI
|
||||
AsmAppleMapPlatformSaveState (
|
||||
IN OUT ASM_SUPPORT_STATE *AsmState
|
||||
);
|
||||
|
||||
/**
|
||||
Assembly interface for backjump from kernel code.
|
||||
Takes kernel arguments through RAX or EAX register.
|
||||
**/
|
||||
VOID
|
||||
AsmAppleMapPlatformPrepareKernelState (
|
||||
);
|
||||
|
||||
/**
|
||||
Assembly global variable containing ASM_SUPPORT_STATE address.
|
||||
Must fit into lower 32-bit bytes due to 32-bit .
|
||||
**/
|
||||
extern UINT32 gOcAbcAsmStateAddr32;
|
||||
|
||||
#endif // CONTEXT_SWITCH_H
|
||||
336
Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm
Executable file
336
Library/OcAppleBootCompatLib/X64/ContextSwitch.nasm
Executable file
@ -0,0 +1,336 @@
|
||||
;------------------------------------------------------------------------------
|
||||
; @file
|
||||
; Copyright (C) 2013, dmazar. All rights reserved.
|
||||
; Copyright (C) 2019, vit9696. All rights reserved.
|
||||
;
|
||||
; All rights reserved.
|
||||
;
|
||||
; This program and the accompanying materials
|
||||
; are licensed and made available under the terms and conditions of the BSD License
|
||||
; which accompanies this distribution. The full text of the license may be found at
|
||||
; http://opensource.org/licenses/bsd-license.php
|
||||
;
|
||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
BITS 64
|
||||
DEFAULT REL
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Structure definitions shared with C code.
|
||||
; Keep these definitions in sync with ContextSwitch.h!
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
struc ASM_SUPPORT_STATE
|
||||
;------------------------------------------------------------------------------
|
||||
; 64-bit state
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.SavedGDTR resq 1
|
||||
.SavedGDTRLimit resw 1
|
||||
.SavedIDTR resq 1
|
||||
.SavedIDTRLimit resw 1
|
||||
.SavedCR3 resq 1
|
||||
.SavedCS resw 1
|
||||
.SavedDS resw 1
|
||||
.SavedES resw 1
|
||||
.SavedFS resw 1
|
||||
.SavedGS resw 1
|
||||
.SavedSS resw 1
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; 32-bit state
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.SavedGDTR32 resq 1
|
||||
.SavedGDTR32Limit resw 1
|
||||
.SavedIDTR32 resq 1
|
||||
.SavedIDTR32Limit resw 1
|
||||
.SavedCS32 resw 1
|
||||
.SavedDS32 resw 1
|
||||
.SavedES32 resw 1
|
||||
.SavedFS32 resw 1
|
||||
.SavedGS32 resw 1
|
||||
.SavedSS32 resw 1
|
||||
.SavedESP32 resd 1
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Kernel entry address.
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.KernelEntry resq 1
|
||||
|
||||
.Size:
|
||||
endstruc
|
||||
|
||||
struc ASM_KERNEL_JUMP
|
||||
.MovInst resb 1
|
||||
.Addr resd 1
|
||||
.CallInst resw 1
|
||||
|
||||
.Size:
|
||||
endstruc
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; C callback method called on jump to kernel after boot.efi finishes.
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
extern ASM_PFX(AppleMapPrepareKernelState)
|
||||
|
||||
SECTION .text
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; VOID
|
||||
; EFIAPI
|
||||
; AsmAppleMapPlatformSaveState (
|
||||
; OUT ASM_SUPPORT_STATE *AsmState
|
||||
; );
|
||||
;------------------------------------------------------------------------------
|
||||
align 8
|
||||
global ASM_PFX(AsmAppleMapSaveState)
|
||||
ASM_PFX(AsmAppleMapSaveState):
|
||||
BITS 64
|
||||
sgdt [rcx + ASM_SUPPORT_STATE.SavedGDTR]
|
||||
sidt [rcx + ASM_SUPPORT_STATE.SavedIDTR]
|
||||
mov rax, cr3
|
||||
mov [rcx + ASM_SUPPORT_STATE.SavedCR3], rax
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedCS], cs
|
||||
mov word [rcx + ASM_SUPPORT_STATE.SavedDS], ds
|
||||
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
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Long (far) return.
|
||||
; retfq (lretq) - 64-bit encoding 48 CB
|
||||
; retf (lret) - 32-bit encoding CB
|
||||
;------------------------------------------------------------------------------
|
||||
LONG_RET64:
|
||||
db 048h
|
||||
LONG_RET32:
|
||||
db 0CBh
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; AsmAppleMapPlatformPrepareKernelState
|
||||
;
|
||||
; Callback from boot.efi - this is where we jump when boot.efi jumps to kernel.
|
||||
; eax register contains boot arguments for the kernel.
|
||||
;
|
||||
; - test if we are in 32 bit or in 64 bit
|
||||
; - if 64 bit, then jump to AsmJumpFromKernel64
|
||||
; - else just continue with AsmJumpFromKernel32
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(AsmAppleMapPlatformPrepareKernelState)
|
||||
ASM_PFX(AsmAppleMapPlatformPrepareKernelState):
|
||||
BITS 32
|
||||
push eax ; save bootArgs pointer to stack
|
||||
mov dword ecx, 0C0000080h ; EFER MSR number.
|
||||
rdmsr ; Read EFER.
|
||||
bt eax, 8 ; Check if LME==1 -> CF=1.
|
||||
pop eax
|
||||
jc AsmJumpFromKernel64 ; LME==1 -> jump to 64 bit code
|
||||
; otherwise, continue with AsmJumpFromKernel32
|
||||
|
||||
; Above 32-bit code must give the opcodes equivalent to following in 64-bit.
|
||||
;BITS 64
|
||||
; push rax ; save bootArgs pointer to stack
|
||||
; mov ecx, C0000080h ; EFER MSR number.
|
||||
; rdmsr ; Read EFER.
|
||||
; bt eax, 8 ; Check if LME==1 -> CF=1.
|
||||
; pop rax
|
||||
; jc AsmJumpFromKernel64 ; LME==1 -> jump to 64 bit code
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; AsmJumpFromKernel32
|
||||
;
|
||||
; Callback from boot.efi in 32 bit mode.
|
||||
;------------------------------------------------------------------------------
|
||||
AsmJumpFromKernel32:
|
||||
BITS 32
|
||||
; Save bootArgs pointer to edi.
|
||||
mov edi, eax
|
||||
|
||||
; Load ebx with AsmState - we'll access our saved data with it.
|
||||
db 0BBh ; mov ebx, OFFSET DataBase
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; 32-bit pointer to AsmState used to reduce global variable access.
|
||||
; Defined here becuase 32-bit mode does not support relative addressing.
|
||||
; As both jumps can happen from 64-bit kernel, the address must fit in 4 bytes.
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(gOcAbcAsmStateAddr32)
|
||||
ASM_PFX(gOcAbcAsmStateAddr32):
|
||||
dd 0
|
||||
|
||||
; Store kernel entery point prior to hunk code.
|
||||
pop ecx
|
||||
sub ecx, ASM_KERNEL_JUMP.Size
|
||||
mov dword [ebx + ASM_SUPPORT_STATE.KernelEntry], ecx
|
||||
|
||||
; Store 32-bit state to be able to recover it later.
|
||||
sgdt [ebx + ASM_SUPPORT_STATE.SavedGDTR32]
|
||||
sidt [ebx + ASM_SUPPORT_STATE.SavedIDTR32]
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedCS32], cs
|
||||
mov word [ebx + ASM_SUPPORT_STATE.SavedDS32], ds
|
||||
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.
|
||||
;
|
||||
|
||||
; Load saved UEFI GDT and IDT.
|
||||
; They will become active after code segment is changed in long jump.
|
||||
lgdt [ebx + ASM_SUPPORT_STATE.SavedGDTR]
|
||||
lidt [ebx + ASM_SUPPORT_STATE.SavedIDTR]
|
||||
|
||||
; Enable the 64-bit page-translation-table entries by setting CR4.PAE=1.
|
||||
mov eax, cr4
|
||||
bts eax, 5
|
||||
mov cr4, eax
|
||||
|
||||
; Set the long-mode page tables by reusing saved UEFI tables.
|
||||
mov eax, dword [ebx + ASM_SUPPORT_STATE.SavedCR3]
|
||||
mov cr3, eax
|
||||
|
||||
; Enable long mode (set EFER.LME=1).
|
||||
mov ecx, 0C0000080h ; EFER MSR number.
|
||||
rdmsr ; Read EFER.
|
||||
bts eax, 8 ; Set LME=1.
|
||||
wrmsr ; Write EFER.
|
||||
|
||||
; Enable paging to activate long mode (set CR0.PG=1).
|
||||
mov eax, cr0 ; Read CR0.
|
||||
bts eax, 31 ; Set PG=1.
|
||||
mov cr0, eax ; Write CR0.
|
||||
|
||||
; Jump to the 64-bit code segment.
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedCS]
|
||||
push eax
|
||||
call LONG_RET32
|
||||
|
||||
BITS 64
|
||||
|
||||
;
|
||||
; Done transitioning to 64-bit code.
|
||||
;
|
||||
|
||||
; Set other segment selectors. In most firmwares all segment registers but cs
|
||||
; point to the same selector, but we must not rely on it.
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedDS]
|
||||
mov ds, ax
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedES]
|
||||
mov es, ax
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedFS]
|
||||
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.
|
||||
and rsp, 0FFFFFFFFFFFFFFF0h
|
||||
|
||||
; Call AppleMapPrepareKernelState (rcx = rax = bootArgs, rdx = 0 = 32 bit kernel jump).
|
||||
mov rcx, rdi
|
||||
xor edx, edx
|
||||
push rdx
|
||||
push rdx
|
||||
push rdx
|
||||
push rcx
|
||||
call ASM_PFX(AppleMapPrepareKernelState)
|
||||
|
||||
; Return value in rax is bootArgs pointer again.
|
||||
mov rdi, rax
|
||||
|
||||
;
|
||||
; Transition back to 32-bit.
|
||||
;
|
||||
|
||||
; Load saved 32-bit GDT.
|
||||
lgdt [rbx + ASM_SUPPORT_STATE.SavedGDTR32]
|
||||
|
||||
; Jump to the 32-bit code segment.
|
||||
mov ax, word [rbx + ASM_SUPPORT_STATE.SavedCS32]
|
||||
push rax
|
||||
call LONG_RET64
|
||||
|
||||
BITS 32
|
||||
|
||||
;
|
||||
; Done transitioning to 32-bit code.
|
||||
;
|
||||
|
||||
; Disable paging (set CR0.PG=0).
|
||||
mov eax, cr0 ; Read CR0.
|
||||
btr eax, 31 ; Set PG=0.
|
||||
mov cr0, eax ; Write CR0.
|
||||
|
||||
; Disable long mode (set EFER.LME=0).
|
||||
mov ecx, 0C0000080h ; EFER MSR number.
|
||||
rdmsr ; Read EFER.
|
||||
btr eax, 8 ; Set LME=0.
|
||||
wrmsr ; Write EFER.
|
||||
jmp AsmJumpFromKernel32Compatibility
|
||||
|
||||
AsmJumpFromKernel32Compatibility:
|
||||
|
||||
;
|
||||
; We are in 32-bit protected mode, no paging.
|
||||
;
|
||||
|
||||
; Reload saved 32 bit state data.
|
||||
lidt [ebx + ASM_SUPPORT_STATE.SavedIDTR32]
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedDS32]
|
||||
mov ds, ax
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedES32]
|
||||
mov es, ax
|
||||
mov ax, word [ebx + ASM_SUPPORT_STATE.SavedFS32]
|
||||
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
|
||||
mov edx, dword [ebx + ASM_SUPPORT_STATE.KernelEntry]
|
||||
jmp edx
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; AsmJumpFromKernel64
|
||||
;
|
||||
; Callback from boot.efi in 64 bit mode.
|
||||
; State is prepared for kernel: 64 bit, pointer to bootArgs in rax.
|
||||
;------------------------------------------------------------------------------
|
||||
AsmJumpFromKernel64:
|
||||
BITS 64
|
||||
; Load rbx with AsmState - we'll access our saved data with it.
|
||||
mov ebx, dword [ASM_PFX(gOcAbcAsmStateAddr32)]
|
||||
|
||||
; Store kernel entery point prior to hunk code.
|
||||
pop rcx
|
||||
sub rcx, ASM_KERNEL_JUMP.Size
|
||||
mov qword [rbx + ASM_SUPPORT_STATE.KernelEntry], rcx
|
||||
|
||||
; Call AppleMapPrepareKernelState (rcx = rax = bootArgs, rdx = 1 = 64-bit kernel jump).
|
||||
mov rcx, rax
|
||||
xor edx, edx
|
||||
push rdx
|
||||
push rdx
|
||||
push rdx
|
||||
push rcx
|
||||
inc edx
|
||||
call ASM_PFX(AppleMapPrepareKernelState)
|
||||
|
||||
; Jump back to the kernel passing boot arguments in rax.
|
||||
mov rdx, [rbx + ASM_SUPPORT_STATE.KernelEntry]
|
||||
jmp rdx
|
||||
48
Library/OcAppleBootCompatLib/X64/ContextSwitchSupport.c
Normal file
48
Library/OcAppleBootCompatLib/X64/ContextSwitchSupport.c
Normal file
@ -0,0 +1,48 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "../BootCompatInternal.h"
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
VOID
|
||||
AppleMapPlatformSaveState (
|
||||
IN OUT ASM_SUPPORT_STATE *AsmState,
|
||||
OUT ASM_KERNEL_JUMP *KernelJump
|
||||
)
|
||||
{
|
||||
//
|
||||
// Save current 64-bit state - will be used later in callback from kernel jump
|
||||
// to be able to transition to 64-bit in case 32-bit kernel startup code is used.
|
||||
//
|
||||
AsmAppleMapPlatformSaveState (AsmState);
|
||||
|
||||
//
|
||||
// Assembly state must fit into 32-bit address as we may jumo from 32-bit kernel
|
||||
// startup code. This is used instead of GetBootCompatContext.
|
||||
//
|
||||
ASSERT ((UINT32)(UINTN) AsmState == (UINTN) AsmState);
|
||||
gOcAbcAsmStateAddr32 = (UINT32)(UINTN) AsmState;
|
||||
|
||||
//
|
||||
// Kernel trampoline for jumping to kernel.
|
||||
//
|
||||
ASSERT (
|
||||
(UINT32)(UINTN) AsmAppleMapPlatformPrepareKernelState
|
||||
== (UINTN) AsmAppleMapPlatformPrepareKernelState
|
||||
);
|
||||
KernelJump->MovInst = 0xB9;
|
||||
KernelJump->Addr = (UINT32)(UINTN) AsmAppleMapPlatformPrepareKernelState;
|
||||
KernelJump->CallInst = 0xD1FF;
|
||||
}
|
||||
@ -12,11 +12,14 @@
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include <Guid/AppleVariable.h>
|
||||
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
VOID
|
||||
OcParseBootArgs (
|
||||
@ -151,3 +154,76 @@ OcAppendArgumentToCmd (
|
||||
AsciiStrnCpyS (CommandLine, ArgumentLength + 1, Argument, ArgumentLength + 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcCheckArgumentFromEnv (
|
||||
IN EFI_LOADED_IMAGE *LoadedImage OPTIONAL,
|
||||
IN EFI_GET_VARIABLE GetVariable OPTIONAL,
|
||||
IN CONST CHAR8 *Argument,
|
||||
IN CONST UINTN ArgumentLength
|
||||
)
|
||||
{
|
||||
CHAR16 *Options;
|
||||
UINTN OptionsSize;
|
||||
CHAR8 BootArgsVar[BOOT_LINE_LENGTH];
|
||||
UINTN BootArgsVarLen;
|
||||
EFI_STATUS Status;
|
||||
UINTN LastIndex;
|
||||
CHAR16 Last;
|
||||
BOOLEAN HasArgument;
|
||||
|
||||
HasArgument = FALSE;
|
||||
|
||||
if (LoadedImage != NULL) {
|
||||
Options = (CHAR16 *) LoadedImage->LoadOptions;
|
||||
OptionsSize = LoadedImage->LoadOptionsSize / sizeof (CHAR16);
|
||||
|
||||
if (Options != NULL && OptionsSize > 0) {
|
||||
//
|
||||
// Just in case we do not have 0-termination.
|
||||
// This may cut some data with unexpected options, but it is not like we care.
|
||||
//
|
||||
LastIndex = OptionsSize - 1;
|
||||
Last = Options[LastIndex];
|
||||
Options[LastIndex] = '\0';
|
||||
|
||||
UnicodeStrToAsciiStrS (Options, BootArgsVar, BOOT_LINE_LENGTH);
|
||||
|
||||
if (OcGetArgumentFromCmd (BootArgsVar, Argument, ArgumentLength)) {
|
||||
HasArgument = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Options do not belong to us, restore the changed value.
|
||||
//
|
||||
Options[LastIndex] = Last;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasArgument) {
|
||||
//
|
||||
// Important to avoid triggering boot-args wrapper too early if we have any.
|
||||
//
|
||||
BootArgsVarLen = sizeof (BootArgsVar);
|
||||
Status = (GetVariable != NULL ? GetVariable : gRT->GetVariable) (
|
||||
L"boot-args",
|
||||
&gAppleBootVariableGuid,
|
||||
NULL,
|
||||
&BootArgsVarLen,
|
||||
BootArgsVar
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status) && BootArgsVarLen > 0) {
|
||||
//
|
||||
// Just in case we do not have 0-termination
|
||||
//
|
||||
BootArgsVar[BootArgsVarLen-1] = '\0';
|
||||
|
||||
if (OcGetArgumentFromCmd (BootArgsVar, Argument, ArgumentLength)) {
|
||||
HasArgument = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HasArgument;
|
||||
}
|
||||
|
||||
@ -601,6 +601,59 @@ OcActivateHibernateWake (
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcIsAppleHibernateWake (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN ValueSize;
|
||||
|
||||
//
|
||||
// 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;
|
||||
Status = gRT->GetVariable (
|
||||
L"boot-signature",
|
||||
&gAppleBootVariableGuid,
|
||||
NULL,
|
||||
&ValueSize,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||||
ValueSize = 0;
|
||||
Status = gRT->GetVariable (
|
||||
L"boot-image-key",
|
||||
&gAppleBootVariableGuid,
|
||||
NULL,
|
||||
&ValueSize,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
ValueSize = 0;
|
||||
Status = gRT->GetVariable (
|
||||
L"boot-switch-vars",
|
||||
&gAppleBootVariableGuid,
|
||||
NULL,
|
||||
&ValueSize,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcShowSimpleBootMenu (
|
||||
IN OC_BOOT_ENTRY *BootEntries,
|
||||
|
||||
@ -160,8 +160,6 @@ VmAllocateMemoryPool (
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Context->MemoryPool = (UINT8 *) Addr;
|
||||
Context->FreePages = NumPages;
|
||||
} else {
|
||||
DEBUG ((DEBUG_ERROR, "OCVM: memory pool allocation failure - %r\n", Status));
|
||||
}
|
||||
|
||||
return Status;
|
||||
@ -181,8 +179,6 @@ VmAllocatePages (
|
||||
AllocatedPages = Context->MemoryPool;
|
||||
Context->MemoryPool += EFI_PAGES_TO_SIZE (NumPages);
|
||||
Context->FreePages -= NumPages;
|
||||
} else {
|
||||
DEBUG ((DEBUG_ERROR, "OCVM: memory pool out of free pages\n"));
|
||||
}
|
||||
|
||||
return AllocatedPages;
|
||||
|
||||
29
Library/OcMiscLib/DirectReset.c
Normal file
29
Library/OcMiscLib/DirectReset.c
Normal file
@ -0,0 +1,29 @@
|
||||
/** @file
|
||||
Reset System Library functions for OVMF
|
||||
|
||||
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
|
||||
VOID
|
||||
DirectRestCold (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
volatile UINTN Index;
|
||||
IoWrite8 (0xCF9, BIT2 | BIT1); // 1st choice: PIIX3 RCR, RCPU|SRST
|
||||
|
||||
for (Index = 0; Index < 100; ++Index) {
|
||||
;
|
||||
}
|
||||
|
||||
IoWrite8 (0x64, 0xfe); // 2nd choice: keyboard controller
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
@ -46,6 +46,7 @@
|
||||
[Sources]
|
||||
Base64Decode.c
|
||||
DataPatcher.c
|
||||
DirectReset.c
|
||||
ReleaseUsbOwnership.c
|
||||
NullTextOutput.c
|
||||
UninstallAllProtocolInterfaces.c
|
||||
|
||||
@ -41,6 +41,9 @@
|
||||
## Include/Protocol/OcLog.h
|
||||
gOcLogProtocolGuid = { 0xDBB6008F, 0x89E4, 0x4272, { 0x98, 0x81, 0xCE, 0x3A, 0xFD, 0x97, 0x24, 0xD0 }}
|
||||
|
||||
# Include/Protocol/OcAppleBootCompat.h
|
||||
gOcAppleBootCompatProtocolGuid = { 0xC7CBA84E, 0xCC77, 0x461D, { 0x9E, 0x3C, 0x6B, 0xE0, 0xCB, 0x79, 0xA7, 0xC1 } }
|
||||
|
||||
## Include/Protocol/OcFirmwareRuntime.h
|
||||
gOcFirmwareRuntimeProtocolGuid = { 0x9C820F96, 0xF16C, 0x4FFD, { 0xB2, 0x66, 0xDF, 0x0A, 0x8F, 0xDF, 0xC4, 0x55 }}
|
||||
|
||||
@ -74,6 +77,9 @@
|
||||
## @libraryclass
|
||||
OcAcpiLib|Include/Library/OcAcpiLib.h
|
||||
|
||||
## @libraryclass
|
||||
OcAppleBootCompatLib|Include/Library/OcAppleBootCompatLib.h
|
||||
|
||||
## @libraryclass
|
||||
OcAppleBootPolicyLib|Include/Library/OcAppleBootPolicyLib.h
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
|
||||
FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
|
||||
OcAcpiLib|OcSupportPkg/Library/OcAcpiLib/OcAcpiLib.inf
|
||||
OcAppleBootCompatLib|OcSupportPkg/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf
|
||||
OcAppleBootPolicyLib|OcSupportPkg/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf
|
||||
OcAppleChunklistLib|OcSupportPkg/Library/OcAppleChunklistLib/OcAppleChunklistLib.inf
|
||||
OcAppleDiskImageLib|OcSupportPkg/Library/OcAppleDiskImageLib/OcAppleDiskImageLib.inf
|
||||
@ -85,6 +86,7 @@
|
||||
|
||||
[Components]
|
||||
OcSupportPkg/Library/OcAcpiLib/OcAcpiLib.inf
|
||||
OcSupportPkg/Library/OcAppleBootCompatLib/OcAppleBootCompatLib.inf
|
||||
OcSupportPkg/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf
|
||||
OcSupportPkg/Library/OcAppleChunklistLib/OcAppleChunklistLib.inf
|
||||
OcSupportPkg/Library/OcAppleDiskImageLib/OcAppleDiskImageLib.inf
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user