未验证 提交 258fb83e 编写于 作者: V Vitaly Cheptsov 提交者: GitHub

OcAfterBootCompatLib: Implement relocation block support (#153)

closes acidanthera/bugtracker#1125
上级 e8cc05f5
......@@ -11,6 +11,7 @@ OpenCore Changelog
- Updated builtin firmware versions for SMBIOS and the rest
- Fixed ACPI patches not applying if tables are in locked memory
- Fixed `EnableSafeModeSlide` on macOS 11.0
- Added `AllowRelocationBlock` quirk for older macOS and safe mode
#### v0.6.3
- Added support for xml comments in plist files
......
......@@ -1308,6 +1308,36 @@ To view their current state use \texttt{pmset -g} command in Terminal.
\begin{enumerate}
\item
\texttt{AllowRelocationBlock}\\
\textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Allows booting macOS through a relocation block.
Relocation block is a scratch buffer allocated in lower 4 GB to be used for
loading the kernel and related structures by EfiBoot on firmwares where
lower memory is otherwise occupied by the (assumed to be) non-runtime data.
Right before kernel startup the relocation block is copied back to lower
addresses. Similarly all the other addresses pointing to relocation block
are also carefully adjusted. Relocation block can be used when:
\begin{itemize}
\tightlist
\item No better slide exists (all the memory is used)
\item \texttt{slide=0} is forced (by an argument or safe mode)
\item KASLR (slide) is unsupported (this is macOS 10.7 or older)
\end{itemize}
This quirk requires \texttt{ProvideCustomSlide} to also be enabled
and generally needs \texttt{AvoidRuntimeDefrag} to work correctly.
Hibernation is not supported when booting with a relocation block
(but relocation block is not always used when the quirk is enabled).
\emph{Note}: While this quirk is required to run older macOS versions
on platforms with used lower memory it is not compatible with some
hardware and macOS 11. In this case you may try to use
\texttt{EnableSafeModeSlide} instead.
\item
\texttt{AvoidRuntimeDefrag}\\
\textbf{Type}: \texttt{plist\ boolean}\\
......
\documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE
%DIF DEL PreviousConfiguration.tex Wed Nov 4 05:07:23 2020
%DIF ADD ../Configuration.tex Sat Nov 7 17:18:06 2020
%DIF ADD ../Configuration.tex Fri Nov 13 19:29:14 2020
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
......@@ -1369,7 +1369,41 @@ To view their current state use \texttt{pmset -g} command in Terminal.
\begin{enumerate}
\item
\texttt{AvoidRuntimeDefrag}\\
\DIFaddbegin \texttt{\DIFadd{AllowRelocationBlock}}\\
\textbf{\DIFadd{Type}}\DIFadd{: }\texttt{\DIFadd{plist\ boolean}}\\
\textbf{\DIFadd{Failsafe}}\DIFadd{: }\texttt{\DIFadd{false}}\\
\textbf{\DIFadd{Description}}\DIFadd{: Allows booting macOS through a relocation block.
}
\DIFadd{Relocation block is a scratch buffer allocated in lower 4 GB to be used for
loading the kernel and related structures by EfiBoot on firmwares where
lower memory is otherwise occupied by the (assumed to be) non-runtime data.
Right before kernel startup the relocation block is copied back to lower
addresses. Similarly all the other addresses pointing to relocation block
are also carefully adjusted. Relocation block can be used when:
}
\begin{itemize}
\tightlist
\item \DIFadd{No better slide exists (all the memory is used)
}\item \texttt{\DIFadd{slide=0}} \DIFadd{is forced (by an argument or safe mode)
}\item \DIFadd{KASLR (slide) is unsupported (this is macOS 10.7 or older)
}\end{itemize}
\DIFadd{This quirk requires }\texttt{\DIFadd{ProvideCustomSlide}} \DIFadd{to also be enabled
and generally needs }\DIFaddend \texttt{AvoidRuntimeDefrag} \DIFaddbegin \DIFadd{to work correctly.
Hibernation is not supported when booting with a relocation block
(but relocation block is not always used when the quirk is enabled).
}
\emph{\DIFadd{Note}}\DIFadd{: While this quirk is required to run older macOS versions
on platforms with used lower memory it is not compatible with some
hardware and macOS 11. In this case you may try to use
}\texttt{\DIFadd{EnableSafeModeSlide}} \DIFadd{instead.
}
\item
\texttt{\DIFadd{AvoidRuntimeDefrag}}\DIFaddend \\
\textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Protect from boot.efi runtime memory defragmentation.
......
......@@ -242,6 +242,8 @@
</array>
<key>Quirks</key>
<dict>
<key>AllowRelocationBlock</key>
<false/>
<key>AvoidRuntimeDefrag</key>
<true/>
<key>DevirtualiseMmio</key>
......
......@@ -242,6 +242,8 @@
</array>
<key>Quirks</key>
<dict>
<key>AllowRelocationBlock</key>
<false/>
<key>AvoidRuntimeDefrag</key>
<true/>
<key>DevirtualiseMmio</key>
......
......@@ -59,6 +59,11 @@ typedef struct OC_ABC_SETTINGS_ {
///
BOOLEAN EnableSafeModeSlide;
///
/// Try to relocate memory to different address space when KASLR is disabled
/// and lower memory is unavailable.
///
BOOLEAN AllowRelocationBlock;
///
/// Attempt to protect certain memory regions from being incorrectly mapped:
/// - CSM region could get used by the kernel due to being BS data,
/// which caused caused wake issues on older firmware.
......
......@@ -1099,6 +1099,10 @@ typedef struct OC_BOOT_ARGUMENTS_ {
UINT32 *MemoryMapDescriptorSize;
UINT32 *MemoryMapDescriptorVersion;
CHAR8 *CommandLine;
UINT32 *KernelAddrP;
UINT32 *SystemTableP;
UINT32 *RuntimeServicesPG;
UINT64 *RuntimeServicesV;
UINT32 *DeviceTreeP;
UINT32 *DeviceTreeLength;
UINT32 *CsrActiveConfig;
......
......@@ -112,6 +112,7 @@
OC_DECLARE (OC_BOOTER_WL_ARRAY)
#define OC_BOOTER_QUIRKS_FIELDS(_, __) \
_(BOOLEAN , AllowRelocationBlock , , FALSE , ()) \
_(BOOLEAN , AvoidRuntimeDefrag , , FALSE , ()) \
_(BOOLEAN , DevirtualiseMmio , , FALSE , ()) \
_(BOOLEAN , DisableSingleUser , , FALSE , ()) \
......
......@@ -52,6 +52,11 @@
**/
#define RT_DESC_ENTRY_NUM ((UINTN) 64)
/**
Kernel static vaddr mapping base.
**/
#define KERNEL_STATIC_VADDR ((UINT64) 0xFFFFFF8000000000ULL)
/**
Kernel __HIB segment virtual address.
**/
......@@ -103,6 +108,8 @@
/**
Assume call gate (normally a little over 100 bytes) can be up to 256 bytes.
It is allocated in its own page and is relocatable.
WARNING: Keep this in sync with RelocationCallGate assembly!
**/
#define ESTIMATED_CALL_GATE_SIZE 256
......@@ -133,6 +140,18 @@ UINTN
IN UINTN EntryPoint
);
/**
Relocation call gate prototype.
**/
typedef
UINTN
(EFIAPI *RELOCATION_CALL_GATE) (
IN UINTN QWordCount,
IN UINTN EntryPoint,
IN EFI_PHYSICAL_ADDRESS Source,
IN UINTN Args
);
/**
Preserved relocation entry.
**/
......@@ -301,6 +320,24 @@ typedef struct KERNEL_SUPPORT_STATE_ {
/// Virtual memory map descriptor size in bytes.
///
UINTN VmMapDescSize;
///
/// Relocation block is a scratch buffer allocated in lower 4GB to be used for
/// loading the kernel and related structures by EfiBoot on firmwares where
/// lower memory is otherwise occupied (assumed to be) non-runtime data.
/// Relocation block can be used when:
/// - no better slide exists (all the memory is used)
/// - slide=0 is forced (by an argument or safe mode)
/// - KASLR (slide) is unsupported (macOS 10.7 or older)
/// Right before kernel startup the relocation block is copied back to lower
/// addresses. Similarly all the other addresses pointing to relocation block
/// are also carefully adjusted.
///
EFI_PHYSICAL_ADDRESS RelocationBlock;
///
/// Real amount of memory used in the relocation block.
/// This value should match ksize in XNU BootArgs.
///
UINTN RelocationBlockUsed;
} KERNEL_SUPPORT_STATE;
/**
......@@ -535,4 +572,97 @@ AppleSlideRestore (
IN OUT OC_BOOT_ARGUMENTS *BootArgs
);
/**
Get calculated relocation block size for booting with slide=0
(e.g. Safe Mode) or without KASLR (older macOS) when it is
otherwise impossible.
@param[in,out] BootCompat Boot compatibility context.
@returns Size of the relocation block (maximum).
@retval 0 otherwise.
**/
UINTN
AppleSlideGetRelocationSize (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
);
/**
Allocate memory from a relocation block when zero slide is unavailable.
EfiLoaderData at address.
@param[in,out] BootCompat Boot compatibility context.
@param[in] GetMemoryMap Unmodified GetMemoryMap pointer, optional.
@param[in] AllocatePages Unmodified AllocatePages pointer.
@param[in] NumberOfPages Number of pages to allocate.
@param[in,out] Memory Memory address to allocate, may be updated.
@retval EFI_SUCCESS on success.
@retval EFI_UNSUPPORTED when zero slide is available.
**/
EFI_STATUS
AppleRelocationAllocatePages (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN EFI_GET_MEMORY_MAP GetMemoryMap,
IN EFI_ALLOCATE_PAGES AllocatePages,
IN UINTN NumberOfPages,
IN OUT EFI_PHYSICAL_ADDRESS *Memory
);
/**
Release relocation block if present.
@param[in,out] BootCompat Boot compatibility context.
@retval EFI_SUCCESS on success.
@retval EFI_UNSUPPORTED when zero slide is available.
**/
EFI_STATUS
AppleRelocationRelease (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
);
/**
Transitions to virtual memory for the relocation block.
@param[in,out] BootCompat Boot compatibility context.
@param[in,out] BootArgs Apple kernel boot arguments.
**/
EFI_STATUS
AppleRelocationVirtualize (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN OUT OC_BOOT_ARGUMENTS *BA
);
/**
Transition from relocation block address space to normal low
memory address space in the relevant XNU areas.
@param[in,out] BootCompat Boot compatibility context.
@param[in,out] BootArgs Apple kernel boot arguments.
**/
VOID
AppleRelocationRebase (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN OUT OC_BOOT_ARGUMENTS *BA
);
/**
Boot Apple Kernel through relocation block.
@param[in,out] BootCompat Boot compatibility context.
@param[in] Args Case-specific kernel argument handle.
@param[in] CallGate Kernel call gate address.
@param[in] EntryPoint Case-specific kernel entry point.
@returns Case-specific value if any.
**/
UINTN
AppleRelocationCallGate (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN KERNEL_CALL_GATE CallGate,
IN UINTN Args,
IN UINTN EntryPoint
);
#endif // BOOT_COMPAT_INTERNAL_H
......@@ -801,8 +801,9 @@ AppleSlideGetVariable (
Data
);
} else if (StrCmp (VariableName, L"boot-args") == 0
&& !BootCompat->ServiceState.AppleCustomSlide
&& ShouldUseCustomSlideOffset (&BootCompat->SlideSupport, GetMemoryMap, FilterMap, FilterMapContext)) {
&& (!BootCompat->ServiceState.AppleCustomSlide || BootCompat->Settings.AllowRelocationBlock)
&& ShouldUseCustomSlideOffset (&BootCompat->SlideSupport, GetMemoryMap, FilterMap, FilterMapContext)
&& !BootCompat->ServiceState.AppleCustomSlide) {
//
// When we cannot allow some KASLR values due to used address we generate
// a random slide value among the valid options, which we we pass via boot-args.
......@@ -815,6 +816,9 @@ AppleSlideGetVariable (
// on the only (so far) problematic X99 and X299 we have no free region for our pool anyway.
// In any case, the current APTIOFIX_SPECULATED_KERNEL_SIZE value appears to work reliably.
//
// Note, when relocation block support is enabled, we always do the slide analysis
// (even when slide=0 is requested) to understand whether we need it or not at a later stage.
//
return GetVariableBootArgs (
&BootCompat->SlideSupport,
GetVariable,
......@@ -854,3 +858,36 @@ AppleSlideRestore (
//
HideSlideFromOs (SlideSupport, BootArgs);
}
UINTN
AppleSlideGetRelocationSize (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
)
{
SLIDE_SUPPORT_STATE *SlideSupport;
SlideSupport = &BootCompat->SlideSupport;
//
// When we could not have performed the analysis we have nothing to offer.
//
if (!SlideSupport->HasMemoryMapAnalysis) {
return 0;
}
//
// When we have no slides available we assume 0 is also unavailable.
//
if (SlideSupport->ValidSlideCount == 0) {
return BootCompat->SlideSupport.EstimatedKernelArea;
}
//
// If the first slide is not zero, then zero is unavailable.
//
if (SlideSupport->ValidSlides[0] != 0) {
return BootCompat->SlideSupport.EstimatedKernelArea;
}
return 0;
}
......@@ -366,6 +366,20 @@ AppleMapPrepareForBooting (
}
}
if (BootCompat->KernelState.RelocationBlock != 0) {
//
// When using Relocation Block EfiBoot will not virtualize the addresses since they
// cannot be mapped 1:1 due to any region from the relocation block being outside
// of static XNU vaddr to paddr mapping. This causes a clean early exit in their
// SetVirtualAddressMap calling routine avoiding gRT->SetVirtualAddressMap.
//
// For this reason we need to perform it ourselves right here before we restored
// runtime memory protections as we also need to defragment EFI_SYSTEM_TABLE memory
// to be accessible from XNU.
//
AppleRelocationVirtualize (BootCompat, &BA);
}
if (BootCompat->Settings.AvoidRuntimeDefrag) {
MemoryMapSize = *BA.MemoryMapSize;
MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN) (*BA.MemoryMap);
......@@ -401,6 +415,10 @@ AppleMapPrepareForBooting (
);
}
}
if (BootCompat->KernelState.RelocationBlock != 0) {
AppleRelocationRebase (BootCompat, &BA);
}
}
/**
......@@ -462,6 +480,11 @@ AppleMapPrepareForHibernateWake (
return;
}
//
// TODO: If we try to work on hibernation support with relocation block
// We will need to add a call similar to AppleRelocationVirtualize here.
//
if (BootCompat->Settings.AvoidRuntimeDefrag) {
//
// I think we should not be there, but ideally all quirks are relatively independent.
......@@ -480,6 +503,11 @@ AppleMapPrepareForHibernateWake (
Handoff = (IOHibernateHandoff *) ((UINTN) Handoff + sizeof(Handoff) + Handoff->bytecount);
}
//
// TODO: To support hibernation with relocation block we will need to add a call similar
// to AppleRelocationRebase here.
//
}
VOID
......@@ -582,7 +610,9 @@ AppleMapPrepareKernelJump (
//
// There is no reason to patch the kernel when we do not need it.
//
if (!BootCompat->Settings.AvoidRuntimeDefrag && !BootCompat->Settings.DiscardHibernateMap) {
if (!BootCompat->Settings.AvoidRuntimeDefrag
&& !BootCompat->Settings.DiscardHibernateMap
&& !BootCompat->Settings.AllowRelocationBlock) {
return;
}
......@@ -701,5 +731,15 @@ AppleMapPrepareKernelState (
CallGate = (KERNEL_CALL_GATE)(UINTN) (
BootCompatContext->ServiceState.KernelCallGate + CALL_GATE_JUMP_SIZE
);
if (BootCompatContext->KernelState.RelocationBlock != 0) {
return AppleRelocationCallGate (
BootCompatContext,
CallGate,
Args,
EntryPoint
);
}
return CallGate (Args, EntryPoint);
}
......@@ -111,7 +111,8 @@ OcAbcInitialize (
DEBUG ((
DEBUG_INFO,
"OCABC: RTDFRG %d DEVMMIO %d NOSU %d NOVRWR %d NOSB %d NOHBMAP %d SMSLIDE %d WRUNPROT %d\n",
"OCABC: ALRBL %d RTDFRG %d DEVMMIO %d NOSU %d NOVRWR %d NOSB %d NOHBMAP %d SMSLIDE %d WRUNPROT %d\n",
Settings->AllowRelocationBlock,
Settings->AvoidRuntimeDefrag,
Settings->DevirtualiseMmio,
Settings->DisableSingleUser,
......
......@@ -35,6 +35,8 @@
CustomSlide.c
KernelSupport.c
OcAfterBootCompatLib.c
RelocationBlock.c
RelocationCallGate.h
ServiceOverrides.c
[Packages]
......
/** @file
Copyright (C) 2013, dmazar. All rights reserved.
Copyright (C) 2020, 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 <Guid/OcVariable.h>
#include <IndustryStandard/AppleHibernate.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/OcBootManagementLib.h>
#include <Library/OcDeviceTreeLib.h>
#include <Library/OcMachoLib.h>
#include <Library/OcMemoryLib.h>
#include <Library/OcMiscLib.h>
#include <Library/OcStringLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
STATIC CONST UINT8 mAsmRelocationCallGate[] = {
#include "RelocationCallGate.h"
};
EFI_STATUS
AppleRelocationAllocatePages (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN EFI_GET_MEMORY_MAP GetMemoryMap,
IN EFI_ALLOCATE_PAGES AllocatePages,
IN UINTN NumberOfPages,
IN OUT EFI_PHYSICAL_ADDRESS *Memory
)
{
EFI_STATUS Status;
UINTN EssentialSize;
EssentialSize = AppleSlideGetRelocationSize (BootCompat);
if (EssentialSize == 0) {
return EFI_UNSUPPORTED;
}
//
// Operating systems up to macOS 10.15 allocate starting with TEXT segment (2MB).
// macOS 11.0 allocates starting with HIB segment (1MB), but it does not support
// this quirk anyway due to AllocatePages in AllocateAddress mode Address pointer
// no longer being reread after the allocation in EfiBoot.
//
if (*Memory == KERNEL_TEXT_PADDR && BootCompat->KernelState.RelocationBlock == 0) {
BootCompat->KernelState.RelocationBlock = BASE_4GB;
Status = OcAllocatePagesFromTop (
EfiLoaderData,
EFI_SIZE_TO_PAGES (EssentialSize),
&BootCompat->KernelState.RelocationBlock,
GetMemoryMap,
AllocatePages,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
"OCABC: Relocation block (0x%Lx) allocation failure - %r\n",
EssentialSize,
Status
));
return Status;
}
BootCompat->KernelState.RelocationBlockUsed = 0;
}
//
// Not our allocation.
//
if (BootCompat->KernelState.RelocationBlock == 0
|| *Memory < KERNEL_BASE_PADDR
|| *Memory >= KERNEL_BASE_PADDR + EssentialSize) {
return EFI_INVALID_PARAMETER;
}
//
// Track actually occupied memory.
//
EssentialSize = (UINTN) (*Memory - KERNEL_BASE_PADDR + EFI_PAGES_TO_SIZE (NumberOfPages));
if (EssentialSize > BootCompat->KernelState.RelocationBlockUsed) {
BootCompat->KernelState.RelocationBlockUsed = EssentialSize;
}
//
// Assume that EfiBoot does not try to reallocate memory.
//
*Memory = *Memory - KERNEL_BASE_PADDR + BootCompat->KernelState.RelocationBlock;
return EFI_SUCCESS;
}
EFI_STATUS
AppleRelocationRelease (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat
)
{
EFI_STATUS Status;
UINTN EssentialSize;
EssentialSize = AppleSlideGetRelocationSize (BootCompat);
if (EssentialSize == 0) {
return EFI_UNSUPPORTED;
}
if (BootCompat->KernelState.RelocationBlock == 0) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->FreePages (
BootCompat->KernelState.RelocationBlock,
EFI_SIZE_TO_PAGES (EssentialSize)
);
BootCompat->KernelState.RelocationBlock = 0;
BootCompat->KernelState.RelocationBlockUsed = 0;
return Status;
}
EFI_STATUS
AppleRelocationVirtualize (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN OUT OC_BOOT_ARGUMENTS *BA
)
{
EFI_STATUS Status;
UINTN MemoryMapSize;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
EFI_PHYSICAL_ADDRESS KernelRTAddress;
UINTN NumEntries;
UINTN Index;
EFI_MEMORY_DESCRIPTOR *Desc;
UINTN BlockSize;
UINT8 *KernelRTBlock;
MemoryMapSize = *BA->MemoryMapSize;
DescriptorSize = *BA->MemoryMapDescriptorSize;
DescriptorVersion = *BA->MemoryMapDescriptorVersion;
MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN) *BA->MemoryMap;
KernelRTAddress = EFI_PAGES_TO_SIZE (*BA->RuntimeServicesPG)
- (UINT32) (BootCompat->KernelState.RelocationBlock - KERNEL_BASE_PADDR);
//
// (1) Assign virtual addresses to all runtime blocks (but reserved).
//
Desc = MemoryMap;
NumEntries = MemoryMapSize / DescriptorSize;
for (Index = 0; Index < NumEntries; ++Index) {
BlockSize = EFI_PAGES_TO_SIZE ((UINTN) Desc->NumberOfPages);
if (Desc->Type == EfiReservedMemoryType) {
Desc->Attribute &= ~EFI_MEMORY_RUNTIME;
} else if ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0) {
Desc->VirtualStart = KernelRTAddress + KERNEL_STATIC_VADDR;
KernelRTAddress += BlockSize;
}
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
}
//
// (2) Transition to virtual memory.
//
Status = gRT->SetVirtualAddressMap (
MemoryMapSize,
DescriptorSize,
DescriptorVersion,
MemoryMap
);
//
// (3) Perform quick dirty defragmentation similarly to EfiBoot to make vaddr = paddr
// for critical areas like EFI_SYSTEM_TABLE.
//
Desc = MemoryMap;
for (Index = 0; Index < NumEntries; ++Index) {
if (Desc->Type == EfiRuntimeServicesCode || Desc->Type == EfiRuntimeServicesData) {
//
// Get physical address from statically mapped virtual.
//
KernelRTBlock = (UINT8 *)(UINTN) (Desc->VirtualStart & (BASE_1GB - 1));
BlockSize = EFI_PAGES_TO_SIZE ((UINTN)Desc->NumberOfPages);
CopyMem (
KernelRTBlock + (BootCompat->KernelState.RelocationBlock - KERNEL_BASE_PADDR),
(VOID*)(UINTN) Desc->PhysicalStart,
BlockSize
);
ZeroMem ((VOID*)(UINTN) Desc->PhysicalStart, BlockSize);
//
// (4) Sync changes to EFI_SYSTEM_TABLE location with boot args.
//
if (Desc->PhysicalStart <= *BA->SystemTableP
&& *BA->SystemTableP <= LAST_DESCRIPTOR_ADDR (Desc)) {
*BA->SystemTableP = (UINT32)((UINTN) KernelRTBlock
+ (*BA->SystemTableP - Desc->PhysicalStart)
+ (BootCompat->KernelState.RelocationBlock - KERNEL_BASE_PADDR));
}
//
// Mark old RT block in MemMap as free memory and remove RT attribute.
//
Desc->Type = EfiConventionalMemory;
Desc->Attribute = Desc->Attribute & (~EFI_MEMORY_RUNTIME);
}
Desc = NEXT_MEMORY_DESCRIPTOR(Desc, DescriptorSize);
}
return Status;
}
VOID
AppleRelocationRebase (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN OUT OC_BOOT_ARGUMENTS *BA
)
{
EFI_STATUS Status;
DTEntry MemMap;
CHAR8 *PropName;
DTMemMapEntry *PropValue;
OpaqueDTPropertyIterator OPropIter;
DTPropertyIterator PropIter;
UINT32 RelocDiff;
PropIter = &OPropIter;
RelocDiff = (UINT32) (BootCompat->KernelState.RelocationBlock - KERNEL_BASE_PADDR);
DTInit ((DTEntry)(UINTN) *BA->DeviceTreeP, BA->DeviceTreeLength);
Status = DTLookupEntry (NULL, "/chosen/memory-map", &MemMap);
if (!EFI_ERROR (Status)) {
Status = DTCreatePropertyIterator (MemMap, &OPropIter);
if (!EFI_ERROR (Status)) {
while (!EFI_ERROR (DTIterateProperties (PropIter, &PropName))) {
//
// /chosen/memory-map props have DTMemMapEntry values (address, length).
// We need to correct the addresses in matching types.
//
//
// Filter entries with different size right away.
//
if (PropIter->CurrentProperty->Length != sizeof (DTMemMapEntry)) {
continue;
}
//
// Filter enteries out of the relocation range.
//
PropValue = (DTMemMapEntry*)((UINT8 *) PropIter->CurrentProperty + sizeof (DTProperty));
if (PropValue->Address < BootCompat->KernelState.RelocationBlock
|| PropValue->Address >= BootCompat->KernelState.RelocationBlock + BootCompat->KernelState.RelocationBlockUsed) {
continue;
}
//
// Patch the addresses up.
//
PropValue->Address -= RelocDiff;
}
}
}
*BA->MemoryMap -= RelocDiff;
*BA->KernelAddrP -= RelocDiff;
*BA->SystemTableP -= RelocDiff;
*BA->RuntimeServicesPG -= EFI_SIZE_TO_PAGES (RelocDiff);
//
// Note, this one does not seem to be used by XNU but we set it anyway.
//
*BA->RuntimeServicesV = EFI_PAGES_TO_SIZE (*BA->RuntimeServicesPG) + KERNEL_STATIC_VADDR;
*BA->DeviceTreeP -= RelocDiff;
}
UINTN
AppleRelocationCallGate (
IN OUT BOOT_COMPAT_CONTEXT *BootCompat,
IN KERNEL_CALL_GATE CallGate,
IN UINTN Args,
IN UINTN EntryPoint
)
{
UINT8 *Payload;
RELOCATION_CALL_GATE ReloGate;
//
// Shift kernel arguments back.
//
Args -= (UINTN) (BootCompat->KernelState.RelocationBlock - KERNEL_BASE_PADDR);
//
// Provide copying payload that will not be overwritten.
//
Payload = (VOID*)(UINTN) CallGate;
Payload += ESTIMATED_CALL_GATE_SIZE;
CopyMem (Payload, mAsmRelocationCallGate, sizeof (mAsmRelocationCallGate));
//
// Transition to payload.
//
ReloGate = (RELOCATION_CALL_GATE)(UINTN) Payload;
return ReloGate (
BootCompat->KernelState.RelocationBlockUsed / sizeof (UINT64),
EntryPoint,
BootCompat->KernelState.RelocationBlock,
Args
);
}
0xfa, 0xfc, 0x4c, 0x89, 0xc6, 0xbf, 0x00, 0x00, 0x10, 0x00, 0xf3, 0x48,
0xa5, 0x48, 0x89, 0xf4, 0x4c, 0x89, 0xc9, 0xe9, 0xe8, 0xfe, 0xff, 0xff
;------------------------------------------------------------------------------
; @file
; Copyright (C) 2020, 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
;------------------------------------------------------------------------------
; Copied from BootCompatInternal.h, keep in sync.
;------------------------------------------------------------------------------
%define ESTIMATED_CALL_GATE_SIZE 256
%define KERNEL_BASE_PADDR 0x100000
;------------------------------------------------------------------------------
; Copy kernel memory to lower memory and jump back to kernel call gate.
;
; To generate the binary blob execute the following command:
; nasm RelocationCallGate.nasm -o /dev/stdout | xxd -i > RelocationCallGate.h
;
; @param[in] QWordCount Number of QWORDS to copy (rcx).
; @param[in] EntryPoint Kernel entry point (rdx).
; @param[in] Source Relocation block address to copy from (r8).
; @param[in] Args Kernel arguments (r9).
;
; Kernel call gate resides ESTIMATED_CALL_GATE_SIZE above and expects
; Args (rcx), EntryPoint (rdx) arguments to be passed.
;
; UINTN
; EFIAPI
; AsmCopySelf (
; IN UINTN QWordCount,
; IN UINTN EntryPoint,
; IN EFI_PHYSICAL_ADDRESS Source,
; IN UINTN Args
; );
;------------------------------------------------------------------------------
AsmRelocationCallGate:
; Disable interrupts just in case UEFI timer kills us.
cli
; Perform copying with direction reset.
cld
mov rsi, r8
mov edi, KERNEL_BASE_PADDR
rep movsq
; Update stack pointer to point to the relocation block (just in case).
mov rsp, rsi
; Print K and die (useful for testing).
; mov cl, 0x4b
; mov dx, 0x3fd
;ready1:
; in al, dx
; test al, 0x20
; je ready1
; mov dx, 0x3f8
; mov al, cl
; out dx, al
; mov cl, 0xa
; mov dx, 0x3fd
;ready2:
; in al, dx
; test al, 0x20
; je ready2
; mov dx, 0x3f8
; mov al, cl
; out dx, al
;freeze:
; jmp freeze
; Move Args to the first argument.
mov rcx, r9
; Jump back to the Apple call gate.
jmp AsmRelocationCallGate - ESTIMATED_CALL_GATE_SIZE
......@@ -367,12 +367,31 @@ OcAllocatePages (
IsCallGateAlloc = TRUE;
}
Status = BootCompat->ServicePtrs.AllocatePages (
Type,
MemoryType,
NumberOfPages,
Memory
);
if (BootCompat->Settings.AllowRelocationBlock
&& BootCompat->ServiceState.AppleBootNestedCount > 0
&& Type == AllocateAddress
&& MemoryType == EfiLoaderData) {
Status = AppleRelocationAllocatePages (
BootCompat,
BootCompat->ServicePtrs.GetMemoryMap,
BootCompat->ServicePtrs.AllocatePages,
NumberOfPages,
Memory
);
} else {
Status = EFI_UNSUPPORTED;
}
if (EFI_ERROR (Status)) {
Status = BootCompat->ServicePtrs.AllocatePages (
Type,
MemoryType,
NumberOfPages,
Memory
);
}
DEBUG ((DEBUG_VERBOSE, "OCABC: AllocPages %u 0x%Lx (%u) - %r\n", Type, *Memory, NumberOfPages, Status));
if (!EFI_ERROR (Status)) {
FixRuntimeAttributes (BootCompat, MemoryType);
......@@ -761,6 +780,10 @@ OcStartImage (
// We failed but other operating systems should be loadable.
//
--BootCompat->ServiceState.AppleBootNestedCount;
if (BootCompat->ServiceState.AppleBootNestedCount == 0) {
AppleRelocationRelease (BootCompat);
}
}
return Status;
......
......@@ -45,6 +45,10 @@ OcParseBootArgs (
Arguments->CommandLine = &BA1->CommandLine[0];
Arguments->KernelAddrP = &BA1->kaddr;
Arguments->SystemTableP = &BA1->efiSystemTable;
Arguments->RuntimeServicesPG = &BA1->efiRuntimeServicesPageStart;
Arguments->RuntimeServicesV = &BA1->efiRuntimeServicesVirtualPageStart;
Arguments->DeviceTreeP = &BA1->deviceTreeP;
Arguments->DeviceTreeLength = &BA1->deviceTreeLength;
Arguments->SystemTable = (EFI_SYSTEM_TABLE*)(UINTN) BA1->efiSystemTable;
......@@ -59,6 +63,10 @@ OcParseBootArgs (
Arguments->CommandLine = &BA2->CommandLine[0];
Arguments->KernelAddrP = &BA2->kaddr;
Arguments->SystemTableP = &BA2->efiSystemTable;
Arguments->RuntimeServicesPG = &BA2->efiRuntimeServicesPageStart;
Arguments->RuntimeServicesV = &BA2->efiRuntimeServicesVirtualPageStart;
Arguments->DeviceTreeP = &BA2->deviceTreeP;
Arguments->DeviceTreeLength = &BA2->deviceTreeLength;
Arguments->SystemTable = (EFI_SYSTEM_TABLE*)(UINTN) BA2->efiSystemTable;
......
......@@ -172,6 +172,7 @@ mBooterWhitelistSchema = OC_SCHEMA_DICT (NULL, mBooterWhitelistEntrySchema);
STATIC
OC_SCHEMA
mBooterQuirksSchema[] = {
OC_SCHEMA_BOOLEAN_IN ("AllowRelocationBlock", OC_GLOBAL_CONFIG, Booter.Quirks.AllowRelocationBlock),
OC_SCHEMA_BOOLEAN_IN ("AvoidRuntimeDefrag", OC_GLOBAL_CONFIG, Booter.Quirks.AvoidRuntimeDefrag),
OC_SCHEMA_BOOLEAN_IN ("DevirtualiseMmio", OC_GLOBAL_CONFIG, Booter.Quirks.DevirtualiseMmio),
OC_SCHEMA_BOOLEAN_IN ("DisableSingleUser", OC_GLOBAL_CONFIG, Booter.Quirks.DisableSingleUser),
......
......@@ -458,6 +458,7 @@ OcLoadBooterUefiSupport (
AbcSettings.DisableVariableWrite = Config->Booter.Quirks.DisableVariableWrite;
AbcSettings.ProtectSecureBoot = Config->Booter.Quirks.ProtectSecureBoot;
AbcSettings.DiscardHibernateMap = Config->Booter.Quirks.DiscardHibernateMap;
AbcSettings.AllowRelocationBlock = Config->Booter.Quirks.AllowRelocationBlock;
AbcSettings.EnableSafeModeSlide = Config->Booter.Quirks.EnableSafeModeSlide;
AbcSettings.EnableWriteUnprotector = Config->Booter.Quirks.EnableWriteUnprotector;
AbcSettings.ForceExitBootServices = Config->Booter.Quirks.ForceExitBootServices;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册