提交 7eca5966 编写于 作者: V vit9696

OcAppleBootCompatLib: Initial version

上级 20120c7b
/** @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
/** @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
/** @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
此差异已折叠。
/** @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;
}
## @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
/** @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);
}
}
}
/** @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
;------------------------------------------------------------------------------
; @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
/** @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;
......
/** @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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册