[BOOT] Execution contexts and more refactoring

This commit is contained in:
Quinn Stephens 2024-10-05 15:44:25 -04:00
parent 7c3dafc051
commit 24a31cab26
13 changed files with 317 additions and 118 deletions

View File

@ -37,8 +37,9 @@ Arguments:
Return Value:
EFI_SUCCESS if successful.
EFI_INVALID_PARAMETER if EfiInitCreateInputParameters() fails.
Any status code returned by EfiGetEfiStatusCode(BmMain()).
Any other error code if BmMain() fails.
--*/
@ -54,7 +55,7 @@ Return Value:
}
//
// Transfer control to the firmware-independent boot manager.
// Transfer control to the firmware-independent boot manager code.
//
return EfiGetEfiStatusCode(BmMain(InputParameters));
}

View File

@ -60,6 +60,16 @@ Return Value:
//
(VOID)BmOpenDataStore(&DataStoreHandle);
//
// Stop here for now.
// Later this will be used to wait for input.
//
while (TRUE) {
#if defined(__x86_64__) || defined(__i386__)
asm volatile("hlt");
#endif
}
Exit:
BlDestroyLibrary();
return Status;

View File

@ -25,6 +25,12 @@ Abstract:
#define PAGE_SHIFT EFI_PAGE_SHIFT
#endif /* _EFI */
//
// Address translation types.
//
#define TRANSLATION_TYPE_NONE 0
#define TRANSLATION_TYPE_MAX 1
//
// Set machine type.
//
@ -34,11 +40,48 @@ Abstract:
#define BOOT_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
#endif
#if defined(__i386__) || defined(__x86_64__)
typedef struct __attribute__((packed)) {
USHORT Limit;
ULONG_PTR Base;
} DESCRIPTOR_TABLE_REGISTER, *PDESCRIPTOR_TABLE_REGISTER;
typedef struct __attribute__((packed)) {
DESCRIPTOR_TABLE_REGISTER Gdt;
DESCRIPTOR_TABLE_REGISTER Idt;
USHORT LdtSelector;
USHORT CS, DS, ES, FS, GS, SS;
} DESCRIPTOR_TABLE_CONTEXT, *PDESCRIPTOR_TABLE_CONTEXT;
#endif
//
// Address translation types.
// Firmware platform flags.
//
#define TRANSLATION_TYPE_NONE 0
#define TRANSLATION_TYPE_MAX 1
#define FIRMWARE_FLAG_EXECUTION_CONTEXT_SUPPORTED 0x00100000
//
// Execution contexts represent the current state
// of the processor/system.
//
typedef enum {
ExecutionContextApplication,
ExecutionContextFirmware,
ExecutionContextMax
} EXECUTION_CONTEXT_TYPE;
#define EXECUTION_CONTEXT_INTERRUPTS_ENABLED 0x02
#define EXECUTION_CONTEXT_PAGING_ENABLED 0x04
typedef struct {
EXECUTION_CONTEXT_TYPE Type;
#if defined(__i386__) || defined(__x86_64__)
ULONG_PTR Cr3;
#endif
ULONG Flags;
DESCRIPTOR_TABLE_CONTEXT DescriptorTableContext;
} EXECUTION_CONTEXT, *PEXECUTION_CONTEXT;
//
// Application entry option.
@ -181,6 +224,11 @@ typedef struct {
ULONG Reserved;
EFI_HANDLE ImageHandle;
EFI_SYSTEM_TABLE *SystemTable;
ULONG Reserved2;
#if defined(__i386__) || defined(__x86_64__)
ULONG_PTR Cr3;
#endif
DESCRIPTOR_TABLE_CONTEXT DescriptorTableContext;
} BOOT_FIRMWARE_DATA, *PBOOT_FIRMWARE_DATA;
#define BOOT_RETURN_DATA_VERSION 1
@ -191,28 +239,6 @@ typedef struct {
ULONG Flags;
} BOOT_RETURN_DATA, *PBOOT_RETURN_DATA;
#if defined(__i386__) || defined(__x86_64__)
typedef struct __attribute__((packed)) {
USHORT Limit;
ULONG_PTR Base;
} DESCRIPTOR_TABLE_REGISTER, *PDESCRIPTOR_TABLE_REGISTER;
typedef struct {
DESCRIPTOR_TABLE_REGISTER Gdt;
DESCRIPTOR_TABLE_REGISTER Idt;
USHORT LdtSelector;
USHORT CS, DS, ES, FS, GS, SS;
} DESCRIPTOR_TABLE_CONTEXT, *PDESCRIPTOR_TABLE_CONTEXT;
#endif
typedef struct {
ULONG Reserved;
#if defined(__i386__) || defined(__x86_64__)
ULONG_PTR CR3;
#endif
DESCRIPTOR_TABLE_CONTEXT DescriptorTableContext;
} BOOT_PLATFORM_DATA, *PBOOT_PLATFORM_DATA;
//
// Firmware-independent application parameters.
// Passed to any boot application's entry point.
@ -376,17 +402,6 @@ typedef struct {
BOOT_DEVICE Device;
} BCDE_DEVICE, *PBCDE_DEVICE;
VOID
ConsolePrint (
IN PWSTR String
);
VOID
ConsolePrintf (
IN PWSTR Format,
...
);
//
// Enable/disable debug printing.
//
@ -398,11 +413,38 @@ ConsolePrintf (
#define DebugPrintf(Format, ...)
#endif
extern PEXECUTION_CONTEXT CurrentExecutionContext;
VOID
ConsolePrint (
IN PWSTR String
);
VOID
ConsolePrintf (
IN PWSTR Format,
...
);
VOID
BlpArchGetDescriptorTableContext (
PDESCRIPTOR_TABLE_CONTEXT Context
);
BOOLEAN
BlArchIsFiveLevelPagingActive (
);
VOID
BlpArchSwitchContext (
IN EXECUTION_CONTEXT_TYPE Type
);
NTSTATUS
BlpArchInitialize (
IN ULONG Stage
);
NTSTATUS
BlpFwInitialize (
IN ULONG Stage,

View File

@ -70,6 +70,14 @@ MmMdRemoveRegionFromMdlEx (
OUT PMEMORY_DESCRIPTOR_LIST Unused
);
NTSTATUS
MmMdRemoveRegionFromMdl (
IN PMEMORY_DESCRIPTOR_LIST Mdl,
IN ULONGLONG RemoveStart,
IN ULONGLONG PageCount,
IN ULONG Flags
);
NTSTATUS
MmMdFreeDescriptor (
IN PMEMORY_DESCRIPTOR Descriptor

View File

@ -17,6 +17,7 @@ Abstract:
#include <wchar.h>
#include "bootlib.h"
extern PEXECUTION_CONTEXT CurrentExecutionContext;
extern SIMPLE_TEXT_OUTPUT_INTERFACE *EfiConOut;
VOID
@ -41,7 +42,18 @@ Return Value:
--*/
{
EXECUTION_CONTEXT_TYPE ContextType;
ContextType = CurrentExecutionContext->Type;
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ExecutionContextFirmware);
}
EfiConOut->OutputString(EfiConOut, String);
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ContextType);
}
}
VOID

View File

@ -13,9 +13,12 @@ Abstract:
--*/
#include <ntrtl.h>
#include "bootlib.h"
#include "efi.h"
BOOT_FIRMWARE_DATA EfiFirmwareData;
PBOOT_FIRMWARE_DATA EfiFirmwareParameters;
EFI_SYSTEM_TABLE *EfiST;
EFI_BOOT_SERVICES *EfiBS;
EFI_RUNTIME_SERVICES *EfiRT;
@ -36,7 +39,10 @@ Routine Description:
Arguments:
Stage - 0 or 1.
Stage - Which stage of initialization to perform.
Stage 0: Initialize global firmware-related data and pointers.
Once this stage is complete, ConsolePrint() and ConsolePrintf() can be used.
FirmwareData - Pointer to BOOT_FIRMWARE_DATA.
@ -53,6 +59,9 @@ Return Value:
}
if (Stage == 0) {
RtlCopyMemory(&EfiFirmwareData, FirmwareData, sizeof(BOOT_FIRMWARE_DATA));
EfiFirmwareParameters = &EfiFirmwareData;
EfiST = FirmwareData->SystemTable;
EfiBS = EfiST->BootServices;
EfiRT = EfiST->RuntimeServices;
@ -60,5 +69,9 @@ Return Value:
EfiConIn = EfiST->ConIn;
}
//
// TODO: Implement stage 1 initialization.
//
return STATUS_SUCCESS;
}

View File

@ -615,7 +615,6 @@ Return Value:
PMEMORY_DESCRIPTOR MemoryDescriptor;
PBOOT_DEVICE BootDevice;
PBOOT_FIRMWARE_DATA FirmwareData;
PBOOT_PLATFORM_DATA PlatformData;
PBOOT_RETURN_DATA ReturnData;
ScratchUsed = 0;
@ -697,19 +696,14 @@ Return Value:
InputParameters->FirmwareDataOffset = ScratchUsed;
FirmwareData = (PBOOT_FIRMWARE_DATA)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_FIRMWARE_DATA);
RtlZeroMemory(FirmwareData, sizeof(BOOT_FIRMWARE_DATA));
FirmwareData->Version = BOOT_FIRMWARE_DATA_VERSION;
FirmwareData->Reserved = 0;
FirmwareData->ImageHandle = ImageHandle;
FirmwareData->SystemTable = SystemTable;
InputParameters->PlatformDataOffset = ScratchUsed;
PlatformData = (PBOOT_PLATFORM_DATA)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_PLATFORM_DATA);
PlatformData->Reserved = 0;
#if defined(__i386__) || defined(__x86_64__)
asm volatile("mov %%cr3, %0" :"=r"(PlatformData->CR3));
asm volatile("mov %%cr3, %0" :"=r"(FirmwareData->Cr3));
#endif
BlpArchGetDescriptorTableContext(&PlatformData->DescriptorTableContext);
BlpArchGetDescriptorTableContext(&FirmwareData->DescriptorTableContext);
InputParameters->ReturnDataOffset = ScratchUsed;
ReturnData = (PBOOT_RETURN_DATA)(&EfiInitScratch[ScratchUsed]);

View File

@ -62,15 +62,32 @@ Return Value:
--*/
{
return EfiGetNtStatusCode(
EfiBS->GetMemoryMap(
MemoryMapSize,
MemoryMap,
MapKey,
DescriptorSize,
DescriptorVersion
)
EXECUTION_CONTEXT_TYPE ContextType;
EFI_STATUS EfiStatus;
ContextType = CurrentExecutionContext->Type;
if (ContextType != ExecutionContextFirmware) {
//
// TODO: Translate addresses here.
// Need MmArchTranslateVirtualAddress().
//
BlpArchSwitchContext(ExecutionContextFirmware);
}
EfiStatus = EfiBS->GetMemoryMap(
MemoryMapSize,
MemoryMap,
MapKey,
DescriptorSize,
DescriptorVersion
);
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ContextType);
}
return EfiGetNtStatusCode(EfiStatus);
}
NTSTATUS
@ -106,14 +123,26 @@ Return Value:
--*/
{
return EfiGetNtStatusCode(
EfiBS->AllocatePages(
Type,
MemoryType,
Pages,
Memory
)
EXECUTION_CONTEXT_TYPE ContextType;
EFI_STATUS EfiStatus;
ContextType = CurrentExecutionContext->Type;
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ExecutionContextFirmware);
}
EfiStatus = EfiBS->AllocatePages(
Type,
MemoryType,
Pages,
Memory
);
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ContextType);
}
return EfiGetNtStatusCode(EfiStatus);
}
NTSTATUS
@ -143,12 +172,24 @@ Return Value:
--*/
{
return EfiGetNtStatusCode(
EfiBS->FreePages(
Memory,
Pages
)
EXECUTION_CONTEXT_TYPE ContextType;
EFI_STATUS EfiStatus;
ContextType = CurrentExecutionContext->Type;
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ExecutionContextFirmware);
}
EfiStatus = EfiBS->FreePages(
Memory,
Pages
);
if (ContextType != ExecutionContextFirmware) {
BlpArchSwitchContext(ContextType);
}
return EfiGetNtStatusCode(EfiStatus);
}
MEMORY_TYPE
@ -616,7 +657,7 @@ Return Value:
//
// Remove the current descriptor.
//
Status = MmMdRemoveRegionFromMdlEx(Mdl, NtStartPage, NtPageCount, MDL_OPERATION_FLAGS_PHYSICAL, NULL);
Status = MmMdRemoveRegionFromMdl(Mdl, NtStartPage, NtPageCount, MDL_OPERATION_FLAGS_PHYSICAL);
if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit;

View File

@ -79,8 +79,6 @@ Return Value:
{
NTSTATUS Status;
DebugPrint(L"Initializing memory manager...\r\n");
//
// Check TranslationType.
//
@ -105,5 +103,9 @@ Return Value:
return Status;
}
//
// TODO: Finish this routine.
//
return STATUS_SUCCESS;
}

View File

@ -27,6 +27,8 @@ ULONG MmGlobalMemoryDescriptorCount, MmGlobalMemoryDescriptorsUsed;
PMEMORY_DESCRIPTOR MmDynamicMemoryDescriptors;
ULONG MmDynamicMemoryDescriptorCount, MmDynamicMemoryDescriptorsUsed;
#define MAX_PRECEDENCE_INDEX sizeof(MmPlatformMemoryTypePrecedence) / sizeof(MmPlatformMemoryTypePrecedence[0])
MEMORY_TYPE MmPlatformMemoryTypePrecedence[] = {
MEMORY_TYPE_RESERVED,
MEMORY_TYPE_UNUSABLE,
@ -44,6 +46,40 @@ MEMORY_TYPE MmPlatformMemoryTypePrecedence[] = {
MEMORY_TYPE_FREE_ZEROED
};
ULONG
GetPrecedenceIndex (
IN MEMORY_TYPE Type
)
/*++
Routine Description:
Finds the index into MmPlatformMemoryTypePrecedence for Type.
Arguments:
Type - The memory type.
Return Value:
The precedence index if found.
MAX_PRECEDENCE_INDEX if not found.
--*/
{
for (ULONG Index = 0;
Index < MAX_PRECEDENCE_INDEX;
Index++) {
if (MmPlatformMemoryTypePrecedence[Index] == Type) {
return Index;
}
}
return MAX_PRECEDENCE_INDEX;
}
BOOLEAN
MmMdpHasPrecedence (
IN MEMORY_TYPE TypeA,
@ -58,9 +94,9 @@ Routine Description:
Arguments:
TypeA - memory type A.
TypeA - Memory type A.
TypeB - memory type B.
TypeB - Memory type B.
Return Value:
@ -71,7 +107,7 @@ Return Value:
{
ULONG ClassA, ClassB;
ULONG IndexA, IndexB;
ULONG PrecedenceIndexA, PrecedenceIndexB;
if (TypeB == MEMORY_TYPE_FREE_ZEROED) {
return TRUE;
@ -103,26 +139,17 @@ Return Value:
return TRUE;
}
for (IndexA = 0;
IndexA < sizeof(MmPlatformMemoryTypePrecedence) / sizeof(MmPlatformMemoryTypePrecedence[0]);
IndexA++) {
if (TypeA == MmPlatformMemoryTypePrecedence[IndexA]) {
goto CheckTypeBPrecedence;
}
PrecedenceIndexA = GetPrecedenceIndex(TypeA);
if (PrecedenceIndexA == MAX_PRECEDENCE_INDEX) {
return TRUE;
}
return TRUE;
CheckTypeBPrecedence:
for (IndexB = 0;
IndexB < sizeof(MmPlatformMemoryTypePrecedence) / sizeof(MmPlatformMemoryTypePrecedence[0]);
IndexB++) {
if (TypeB == MmPlatformMemoryTypePrecedence[IndexB]) {
return IndexA <= IndexB ? TRUE:FALSE;
}
PrecedenceIndexB = GetPrecedenceIndex(TypeB);
if (PrecedenceIndexB == MAX_PRECEDENCE_INDEX) {
return FALSE;
}
return FALSE;
return PrecedenceIndexA <= PrecedenceIndexB ? TRUE:FALSE;
}
BOOLEAN
@ -690,6 +717,41 @@ Return Value:
return Status;
}
NTSTATUS
MmMdRemoveRegionFromMdl (
IN PMEMORY_DESCRIPTOR_LIST Mdl,
IN ULONGLONG RemoveStart,
IN ULONGLONG PageCount,
IN ULONG Flags
)
/*++
Routine Description:
Removes a region from a MDL.
Wrapper around MmMdRemoveRegionFromMdlEx().
Arguments:
Same as MmMdRemoveRegionFromMdlEx(), except for Unused.
Return Value:
Any status code returned by MmMdRemoveRegionFromMdlEx().
--*/
{
return MmMdRemoveRegionFromMdlEx(
Mdl,
RemoveStart,
PageCount,
Flags,
NULL
);
}
NTSTATUS
MmMdFreeDescriptor (
IN PMEMORY_DESCRIPTOR Descriptor
@ -732,10 +794,10 @@ Return Value:
}
//
// Free the descriptor from the heap.
// TODO: Use BlMmFreeHeap().
// TODO: Free the descriptor from the heap.
// Need BlMmFreeHeap().
//
ConsolePrint(L"MmMdFreeDescriptor(): Heap not available\r\n");
DebugPrint(L"MmMdFreeDescriptor(): Heap not available\r\n");
return STATUS_NOT_IMPLEMENTED;
// return BlMmFreeHeap(Descriptor);
}
@ -825,7 +887,7 @@ Return Value:
VOID
MmMdInitialize (
IN ULONG Unused,
IN ULONG Stage,
IN PBOOT_LIBRARY_PARAMETERS LibraryParameters
)
@ -837,9 +899,11 @@ Routine Description:
Arguments:
Unused - Ignored.
Stage - Which stage of initialization to perform.
LibraryParameters - pointer to the library parameters structure.
Stage 0: Initializes the static memory descriptor pool.
LibraryParameters - Pointer to the library parameters structure.
Return Value:
@ -848,17 +912,19 @@ Return Value:
--*/
{
(VOID)Unused;
(VOID)LibraryParameters;
DebugPrint(L"Initializing memory descriptor manager...\r\n");
if (Stage == 0) {
//
// Initialize static memory descriptor pool.
//
MmGlobalMemoryDescriptors = &MmStaticMemoryDescriptors[0];
MmGlobalMemoryDescriptorCount = MAX_STATIC_DESCRIPTOR_COUNT;
MmGlobalMemoryDescriptorsUsed = 0;
RtlZeroMemory(MmGlobalMemoryDescriptors, MAX_STATIC_DESCRIPTOR_COUNT * sizeof(MEMORY_DESCRIPTOR));
}
//
// Initialize global memory descriptor list.
// TODO: Implement stage 1 initialization.
//
MmGlobalMemoryDescriptors = &MmStaticMemoryDescriptors[0];
MmGlobalMemoryDescriptorCount = MAX_STATIC_DESCRIPTOR_COUNT;
MmGlobalMemoryDescriptorsUsed = 0;
RtlZeroMemory(MmGlobalMemoryDescriptors, MAX_STATIC_DESCRIPTOR_COUNT * sizeof(MEMORY_DESCRIPTOR));
DebugPrintf(L"Global memory descriptor count: %x\r\n", MmGlobalMemoryDescriptorCount);
}

View File

@ -88,14 +88,13 @@ Return Value:
NTSTATUS Status;
PMEMORY_DESCRIPTOR Descriptor, NewDescriptor;
(VOID)MemoryInfo;
DebugPrint(L"Initializing page allocator...\r\n");
PapMinimumAllocationCount = MinimumAllocation;
PapMinimumPhysicalPage = 1;
PapMaximumPhysicalPage = MAXULONGLONG >> PAGE_SHIFT;
//
// Initialize Memory Descriptor Lists
//
InitializeMdl(&MmMdlFwAllocationTracker);
InitializeMdl(&MmMdlBadMemory);
InitializeMdl(&MmMdlTruncatedMemory);
@ -116,11 +115,18 @@ Return Value:
// MDL the memory manager will use for allocation.
//
Descriptor = (PMEMORY_DESCRIPTOR)((PUCHAR)MemoryInfo + MemoryInfo->MdlOffset);
for (ULONG DescriptorCount = MemoryInfo->DescriptorCount; DescriptorCount > 0; DescriptorCount--) {
for (ULONG DescriptorCount = MemoryInfo->DescriptorCount;
DescriptorCount > 0;
DescriptorCount--) {
//
// Remove from the usable MDL.
//
Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedUnallocated, Descriptor->FirstPage, Descriptor->PageCount, MDL_OPERATION_FLAGS_PHYSICAL, NULL);
Status = MmMdRemoveRegionFromMdl(
&MmMdlUnmappedUnallocated,
Descriptor->FirstPage,
Descriptor->PageCount,
MDL_OPERATION_FLAGS_PHYSICAL
);
if (!NT_SUCCESS(Status)) {
return STATUS_INVALID_PARAMETER;
}

View File

@ -24,6 +24,7 @@ Abstract:
sizeof(BOOT_RETURN_DATA) \
)
ULONG BlPlatformFlags = 0x002a0000 | FIRMWARE_FLAG_EXECUTION_CONTEXT_SUPPORTED;
PBOOT_DEVICE BlpBootDevice;
PBOOT_APPLICATION_PARAMETERS BlpApplicationParameters;
BOOT_LIBRARY_PARAMETERS BlpLibraryParameters;
@ -59,8 +60,6 @@ Return Value:
PBOOT_INIT_APPLICATION_ENTRY ApplicationEntry;
PBOOT_FIRMWARE_DATA FirmwareData;
(VOID)LibraryParameters;
if (ApplicationParameters == NULL ||
ApplicationParameters->Signature != BOOT_APPLICATION_PARAMETERS_SIGNATURE ||
ApplicationParameters->Size < MIN_INPUT_PARAMETERS_SIZE) {
@ -84,7 +83,6 @@ Return Value:
ConsolePrint(L"> Alcyone EFI Boot Manager\r\n");
ConsolePrintf(L"Image base: %x %x\r\nImage size: %x\r\n", HIDWORD((ULONG_PTR)ApplicationParameters->ImageBase), LODWORD((ULONG_PTR)ApplicationParameters->ImageBase), ApplicationParameters->ImageSize);
DebugPrint(L"Initializing boot library...\r\n");
if (ApplicationEntry->Signature != BOOT_INIT_APPLICATION_ENTRY_SIGNATURE) {
DebugPrint(L"InitializeLibrary(): ApplicationEntry Signature is invalid\r\n");
@ -104,6 +102,11 @@ Return Value:
RtlCopyMemory(&BlpApplicationEntry.BcdIdentifier, &ApplicationEntry->BcdIdentifier, sizeof(GUID));
BlpApplicationEntry.Options = &ApplicationEntry->Options;
Status = BlpArchInitialize(0);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = BlpMmInitialize(MemoryInfo, ApplicationParameters->TranslationType, LibraryParameters);
if (!NT_SUCCESS(Status)) {
return Status;

View File

@ -5,15 +5,16 @@
| File | Public Routines |
|-|-|
| APP/BOOTMGR/EFI/efientry.c | EfiMain() |
| APP/BOOTMGR/bootmgr.c | BmMain() |
| APP/BOOTMGR/bcd.c | BmXXDataStore() |
| LIB/EFI/efifw.c | BlpFwXX() |
| LIB/EFI/efimm.c | MmFwXX() |
| LIB/EFI/efiinit.c | EfiInitXX() |
| APP/BOOTMGR/bootmgr.c | BmMain() |
| LIB/EFI/eficon.c | ConsoleXX() |
| LIB/EFI/efilib.c | EfiGetEfiStatusCode() |
| LIB/EFI/efifw.c | BlpFwXX() |
| LIB/EFI/efiinit.c | EfiInitXX() |
| LIB/EFI/efilib.c | EfiGetXXStatusCode() |
| LIB/EFI/efimm.c | MmFwXX() |
| LIB/MM/mm.c | BlpMmXX() |
| LIB/MM/mmmd.c | MmMdXX() |
| LIB/MM/mmpa.c | MmPaXX() |
| LIB/bootlib.c | BlXXLibrary() |
| LIB/bootopt.c | BlXXBootOptionXX() |
| LIB/XX/arch.c | BlpArchXX() |