singrdk/base/boot/SingLdrPc/blmm.cpp

1295 lines
27 KiB
C++
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
//++
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// blmm.cpp
//
// Abstract:
//
// This module implements memory management for the boot loader.
//
//--
#include "bl.h"
LIST_ENTRY BlMmPhysicalRegionList;
struct {
BL_MM_PHYSICAL_REGION StaticArray[16];
LIST_ENTRY FreeList;
} BlMmPhysicalRegionLookaside;
GDTR BlMmInitialGdtr;
ULONG_PTR BlMmLegacyCr3;
ULONG_PTR BlMmBootCr3;
typedef struct _BL_MM_PAGE_TABLE {
UINT64 Entry[512];
} BL_MM_PAGE_TABLE, *PBL_MM_PAGE_TABLE;
#if defined(BOOT_X64)
__declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPml4Table[1];
#endif
__declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPdpTable[1];
__declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPdTable[4];
__declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPgTable[1];
PVOID BlMmExtendedBiosDataArea;
VOID
BlMmCompactPhysicalRegionList(
VOID
)
//++
//
// Routine Description:
//
// This function compacts the physical region list by coalescing adjacent
// regions of the same type.
//
//--
{
PBL_MM_PHYSICAL_REGION Current;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Next;
Head = &BlMmPhysicalRegionList;
if (BlRtlIsListEmpty(Head) != FALSE) {
return;
}
Current = CONTAINING_RECORD(Head->Flink,
BL_MM_PHYSICAL_REGION,
Entry);
for (;;) {
BLASSERT(Current->Size > 0);
BLASSERT(Current->Start + Current->Size == Current->Limit);
BLASSERT((Current->Type >= BL_MM_PHYSICAL_REGION_MIN_TYPE) && (Current->Type <= BL_MM_PHYSICAL_REGION_MAX_TYPE));
if (Current->Entry.Flink == Head) {
break;
}
Next = CONTAINING_RECORD(Current->Entry.Flink,
BL_MM_PHYSICAL_REGION,
Entry);
BLASSERT(Next->Start >= Current->Limit);
if ((Next->Start == Current->Limit) &&
(Next->Type == Current->Type)) {
Current->Limit = Next->Limit;
Current->Size = Current->Limit - Current->Start;
BlRtlRemoveEntryList(&Next->Entry);
BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &Next->Entry);
continue;
}
Current = Next;
}
}
VOID
BlMmInsertPhysicalRegion(
PBL_MM_PHYSICAL_REGION Region
)
//++
//
// Routine Description:
//
// This function inserts a new physical region to the physical region list.
//
// Arguments:
//
// Region - Supplies a pointer to the region to insert.
//
//--
{
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Next;
Head = &BlMmPhysicalRegionList;
Entry = Head->Flink;
while (Entry != Head) {
Next = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if (Next->Start > Region->Start) {
break;
}
Entry = Entry->Flink;
}
BlRtlInsertTailList(Entry, &Region->Entry);
BlMmCompactPhysicalRegionList();
return;
}
VOID
BlMmCreatePhysicalRegion(
UINT64 Start,
UINT64 Size,
UINT32 Type
)
//++
//
// Routine Description:
//
// This function creates a physical region descriptor.
//
// Arguments:
//
// Start - Supplies the start address of the region.
//
// Size - Supplies the size of the region.
//
// Type - Supplies the type of the region.
//
//--
{
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
UINT64 Limit;
PBL_MM_PHYSICAL_REGION Region;
BLASSERT((Start % PAGE_SIZE) == 0);
BLASSERT(Size > 0);
BLASSERT((Size % PAGE_SIZE) == 0);
BLASSERT(Type >= BL_MM_PHYSICAL_REGION_MIN_TYPE);
BLASSERT(Type <= BL_MM_PHYSICAL_REGION_MAX_TYPE);
Limit = Start + Size;
BLASSERT(Limit > Start);
Head = &BlMmPhysicalRegionList;
Entry = Head->Flink;
while (Entry != Head) {
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if ((Start < Region->Limit) && (Limit > Region->Start)) {
BlRtlPrintf("MM: Physical region collision!\n");
BlRtlHalt();
}
Entry = Entry->Flink;
}
Entry = Head->Flink;
while (Entry != Head) {
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if (Start < Region->Start) {
break;
}
Entry = Entry->Flink;
}
BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE);
Region = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList),
BL_MM_PHYSICAL_REGION,
Entry);
Region->Start = Start;
Region->Size = Size;
Region->Limit = Limit;
Region->Type = Type;
BlMmInsertPhysicalRegion(Region);
return;
}
UINT64
BlMmAllocatePhysicalRegion(
UINT32 Size,
UINT32 Type
)
//++
//
// Routine Description:
//
// This function allocates a physical region from the lowest available and
// sufficient free region.
//
// Arguments:
//
// Size - Supplies the size of the region to allocate.
//
// Type - Supplies the type of the region to allocate.
//
// Return Value:
//
// The physical address of the allocated region.
//
//--
{
PLIST_ENTRY Entry;
PBL_MM_PHYSICAL_REGION FreeRegion;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Region;
BLASSERT(Size > 0);
BLASSERT(Type != BL_MM_PHYSICAL_REGION_FREE);
SATISFY_OVERZEALOUS_COMPILER(Region = NULL);
Size = ROUND_UP_TO_PAGES(Size);
Head = &BlMmPhysicalRegionList;
Entry = Head->Blink;
while (Entry != Head) {
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if ((Region->Type == BL_MM_PHYSICAL_REGION_FREE) &&
(Region->Size >= Size) &&
(Region->Limit < 0x100000000UI64)) {
break;
}
Entry = Entry->Blink;
}
if (Entry == Head) {
BlRtlPrintf("MM: Unable to allocate %x bytes!\n", Size);
BlRtlHalt();
}
if (Region->Size == Size) {
Region->Type = Type;
return Region->Start;
}
FreeRegion = Region;
BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE);
Region = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList),
BL_MM_PHYSICAL_REGION,
Entry);
Region->Start = FreeRegion->Limit - Size;
FreeRegion->Limit -= Size;
FreeRegion->Size -= Size;
Region->Size = Size;
Region->Limit = Region->Start + Region->Size;
Region->Type = Type;
BlRtlZeroMemory((PVOID) (ULONG_PTR) Region->Start, (ULONG_PTR) (UINT32) Region->Size);
BlMmInsertPhysicalRegion(Region);
return Region->Start;
}
BOOLEAN
BlMmAllocateSpecificPhysicalRegion(
UINT64 Base,
UINT64 Size,
UINT32 Type
)
//++
//
// Routine Description:
//
// This function allocates a specific physical region.
//
// Arguments:
//
// Base - Supplies the base physical address of the region to allocate.
//
// Size - Supplies the size of the region to allocate.
//
// Type - Supplies the type of the region to allocate.
//
// Return Value:
//
// TRUE, if allocation was successful.
// FALSE, otherwise.
//
//--
{
UINT64 End;
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION NextRegion;
PBL_MM_PHYSICAL_REGION PreviousRegion;
PBL_MM_PHYSICAL_REGION Region;
UINT64 Start;
BLASSERT((Base % PAGE_SIZE) == 0);
BLASSERT(Size > 0);
BLASSERT((Size % PAGE_SIZE) == 0);
BLASSERT(Type != BL_MM_PHYSICAL_REGION_FREE);
SATISFY_OVERZEALOUS_COMPILER(Region = NULL);
Start = Base;
End = Start + Size;
Head = &BlMmPhysicalRegionList;
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) {
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if ((Start >= Region->Start) && (End <= Region->Limit)) {
break;
}
}
if (Entry == Head) {
return FALSE;
}
if (Region->Type != BL_MM_PHYSICAL_REGION_FREE) {
return FALSE;
}
PreviousRegion = NULL;
NextRegion = NULL;
if (Region->Start < Start) {
BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE);
PreviousRegion = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList),
BL_MM_PHYSICAL_REGION,
Entry);
PreviousRegion->Start = Region->Start;
PreviousRegion->Size = Start - Region->Start;
PreviousRegion->Limit = Start;
PreviousRegion->Type = BL_MM_PHYSICAL_REGION_FREE;
}
if (Region->Limit > End) {
BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE);
NextRegion = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList),
BL_MM_PHYSICAL_REGION,
Entry);
NextRegion->Start = End;
NextRegion->Size = Region->Limit - End;
NextRegion->Limit = Region->Limit;
NextRegion->Type = BL_MM_PHYSICAL_REGION_FREE;
}
Region->Start = Start;
Region->Size = Size;
Region->Limit = End;
Region->Type = Type;
if (PreviousRegion != NULL) {
BlMmInsertPhysicalRegion(PreviousRegion);
}
if (NextRegion != NULL) {
BlMmInsertPhysicalRegion(NextRegion);
}
return TRUE;
}
BOOLEAN
BlMmFindFreePhysicalRegion(
PUINT64 Base,
PUINT64 Size
)
//++
//
// Routine Description:
//
// This function finds a free physical region.
//
// Arguments:
//
// Base - Receives the base address of the free region.
//
// Size - Receives the size of the free region.
//
// Return Value:
//
// TRUE, if a free region was found.
// FALSE, otherwise.
//
//--
{
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Region;
Head = &BlMmPhysicalRegionList;
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) {
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
if (Region->Type == BL_MM_PHYSICAL_REGION_FREE) {
*Base = Region->Start;
*Size = Region->Size;
return TRUE;
}
}
return FALSE;
}
BOOLEAN
BlMmGetNextPhysicalRegion(
PVOID *Handle,
PUINT64 Base,
PUINT64 Size,
PUINT32 Type
)
//++
//
// Routine Description:
//
// This function is used to enumerate physical regions.
//
// Arguments:
//
// Handle - Supplies a pointer to the last handle (or NULL to start
// enumeration) on entry.
// Receives the next handle (if any) on exit.
//
// Base - Receives the base address of the next region.
//
// Size - Receives the size of the next region.
//
// Type - Receives the type of the next region.
//
// Return Value:
//
// TRUE, if there is a next region.
// FALSE, otherwise.
//
//--
{
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Region;
Head = &BlMmPhysicalRegionList;
if (*Handle == NULL) {
Entry = Head;
} else {
Entry = (PLIST_ENTRY) *Handle;
}
Entry = Entry->Flink;
if (Entry == Head) {
return FALSE;
}
Region = CONTAINING_RECORD(Entry,
BL_MM_PHYSICAL_REGION,
Entry);
*Handle = &Region->Entry;
*Base = Region->Start;
*Size = Region->Size;
*Type = Region->Type;
return TRUE;
}
PCHAR
BlMmPhysicalRegionTypeString(
UINT32 Type
)
//++
//
// Routine Description:
//
// This function returns the specified physical region type string.
//
// Arguments:
//
// Type - Supplies the physical region type.
//
// Return Value:
//
// String representation for the specified type.
//
//--
{
#define CASE(X) case BL_MM_PHYSICAL_REGION_##X: return #X;
switch (Type) {
CASE(FREE)
CASE(BIOS)
CASE(BOOT_LOADER)
CASE(SMAP_RESERVED)
CASE(DISTRO)
CASE(KERNEL_IMAGE)
CASE(NATIVE_PLATFORM)
CASE(NATIVE_PROCESSOR)
CASE(LOG_RECORD)
CASE(LOG_TEXT)
CASE(KERNEL_STACK)
CASE(CONTEXT)
CASE(TASK)
CASE(SINGULARITY)
CASE(BOOT_STACK)
CASE(SINGULARITY_SMAP)
}
#undef CASE
BLASSERT(FALSE);
return NULL;
}
VOID
BlMmDumpPhysicalRegionList(
VOID
)
//++
//
// Routine Description:
//
// This function dumps the list of physical regions.
//
//--
{
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PBL_MM_PHYSICAL_REGION Region;
BlRtlPrintf("MM: Physical Region:\n");
Head = &BlMmPhysicalRegionList;
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) {
Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry);
BlRtlPrintf("MM: %016I64x...%016I64x %s\n",
Region->Start,
Region->Limit,
BlMmPhysicalRegionTypeString(Region->Type));
}
BlRtlPrintf("\n");
return;
}
//
// AIFIX: Switch from identity mapping to dynamic mapping.
//
VOID
BlMmInitializePageTables(
VOID
)
//++
//
// Routine Description:
//
// This function initializes boot loader page tables that identity map the first 4GB of memory.
//
//--
{
UINT64 Index;
UINT64 *Pde;
UINT64 PdtBase;
UINT64 *Pdpe;
UINT64 PdptBase;
#if defined(BOOT_X64)
UINT64 *Pml4e;
UINT64 Pml4tBase;
#endif
UINT64 *Pte;
UINT64 PtBase;
#if defined(BOOT_X64)
Pml4tBase = (UINT64) (ULONG_PTR) BlMmPml4Table;
#endif
PdptBase = (UINT64) (ULONG_PTR) BlMmPdpTable;
PdtBase = (UINT64) (ULONG_PTR) BlMmPdTable;
PtBase = (UINT64) (ULONG_PTR) BlMmPgTable;
#if defined(BOOT_X64)
Pml4e = (UINT64 *) (PVOID) Pml4tBase;
#endif
Pdpe = (UINT64 *) (PVOID) (ULONG_PTR) PdptBase;
Pde = (UINT64 *) (PVOID) (ULONG_PTR) PdtBase;
Pte = (UINT64 *) (PVOID) (ULONG_PTR) PtBase;
#if defined(BOOT_X64)
Pml4e[0] = PdptBase | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED;
#endif
for (Index = 0; Index < 4; Index += 1) {
Pdpe[Index] = (PdtBase + (Index * PAGE_SIZE)) | PAGE_PRESENT;
#if defined(BOOT_X64)
Pdpe[Index] |= PAGE_WRITEABLE | PAGE_ACCESSED;
#endif
}
Pde[0] = PtBase | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED;
for (Index = 1; Index < 512; Index += 1) {
Pte[Index] = (Index << 12) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED;
}
for (Index = 1; Index < 2048; Index += 1) {
Pde[Index] = (Index << 21) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED | PAGE_2MB;
}
#if defined(BOOT_X86)
BlMmBootCr3 = (ULONG_PTR) PdptBase;
#elif defined(BOOT_X64)
BlMmBootCr3 = Pml4tBase;
#endif
BlMmSetCr3(BlMmBootCr3);
BlGetBeb()->LegacyReturnCr3 = (UINT32) BlMmBootCr3;
#if MM_VERBOSE
BlRtlPrintf("MM: 4GB identity map [CR3=%p]\n", BlMmBootCr3);
#endif
return;
}
VOID
BlMmMapVirtualPage(
PVOID VirtualAddress,
PVOID PhysicalAddress,
BOOLEAN Writeable,
BOOLEAN Cacheable,
BOOLEAN WriteThrough
)
//++
//
// Routine Description:
//
// This function maps the specified virtual page.
//
// Arguments:
//
// VirtualAddress - Supplies the virtual address to map.
//
// PhysicalAddress - Supplies the physical address to map to.
//
// Writeable - Supplies whether the page is writeable.
//
// Cacheable - Supplies whether the page is cacheable.
//
// WriteThrough - Supplies whether the page is write-through.
//
//--
{
UINT64 Entry;
UINT32 Index;
UINT64 LargePageAddress;
PUINT64 PdBase;
UINT32 PdIndex;
PUINT64 PdpBase;
UINT32 PdpIndex;
UINT64 PhysicalPageNumber;
PUINT64 PtBase;
UINT32 PtIndex;
ULONG_PTR VirtualPageNumber;
BLASSERT((((ULONG_PTR) VirtualAddress) & 0xFFF) == 0);
BLASSERT((((ULONG_PTR) PhysicalAddress) & 0xFFF) == 0);
#if defined(BOOT_X64)
BLASSERT((ULONG_PTR) VirtualAddress < 0x100000000UI64);
#endif
//
// Compute virtual page number, page directory pointer, page directory, and page table indices.
//
VirtualPageNumber = ((ULONG_PTR) VirtualAddress) / PAGE_SIZE;
PdpIndex = (UINT32) ((VirtualPageNumber >> 18) & 0x1FF);
PdIndex = (UINT32) ((VirtualPageNumber >> 9) & 0x1FF);
PtIndex = (UINT32) (VirtualPageNumber & 0x1FF);
//
// Look up page directory base address.
//
PdpBase = &BlMmPdpTable[0].Entry[0];
PdBase = (PUINT64) (ULONG_PTR) (PdpBase[PdpIndex] & (~(0xFFFUI64)));
//
// If the specified page is currently being mapped with large pages, then split it into 4K mappings.
//
if ((PdBase[PdIndex] & PAGE_2MB) != 0) {
PtBase = (PUINT64) (ULONG_PTR) BlMmAllocatePhysicalRegion(PAGE_SIZE, BL_MM_PHYSICAL_REGION_BOOT_LOADER);
LargePageAddress = (PdBase[PdIndex] & (~(0xFFFUI64)));
BLASSERT(((LargePageAddress >> 12) & 0x1FF) == 0);
//
// Create page table entries to map the region in 4K pages.
//
for (Index = 0; Index < 512; Index += 1) {
PtBase[Index] = (LargePageAddress + (Index * PAGE_SIZE)) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED;
}
//
// Update page directory entry.
//
PdBase[PdIndex] = ((UINT64) (ULONG_PTR) PtBase) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED;
//
// Flush TLB.
//
BlMmSetCr3(BlMmBootCr3);
}
//
// Update page mapping.
//
PtBase = (PUINT64) (ULONG_PTR) (PdBase[PdIndex] & (~(0xFFFUI64)));
PhysicalPageNumber = ((ULONG_PTR) PhysicalAddress) >> 12;
Entry = (PhysicalPageNumber << 12) | PAGE_PRESENT;
if (Writeable != FALSE) {
Entry |= PAGE_WRITEABLE;
}
if (Cacheable == FALSE) {
Entry |= PAGE_CACHEDISABLE;
} else if (WriteThrough != FALSE) {
Entry |= PAGE_WRITETHROUGH;
}
PtBase[PtIndex] = Entry;
//
// Flush TLB.
//
BlMmSetCr3(BlMmBootCr3);
return;
}
VOID
BlMmMapVirtualRange(
PVOID VirtualAddress,
PVOID PhysicalAddress,
ULONG_PTR Size,
BOOLEAN Writeable,
BOOLEAN Cacheable,
BOOLEAN WriteThrough
)
//++
//
// Routine Description:
//
// This function maps the specified virtual range.
//
// Arguments:
//
// VirtualAddress - Supplies the virtual address to map.
//
// PhysicalAddress - Supplies the physical address to map to.
//
// Size - Supplies the size of the mapping.
//
// Writeable - Supplies whether the page is writeable.
//
// Cacheable - Supplies whether the page is cacheable.
//
// WriteThrough - Supplies whether the page is write-through.
//
//--
{
ULONG_PTR PhysicalNext;
ULONG_PTR VirtualLimit;
ULONG_PTR VirtualNext;
VirtualNext = (ULONG_PTR) VirtualAddress;
VirtualLimit = VirtualNext + Size;
VirtualNext &= (~((ULONG_PTR) 0xFFF));
VirtualLimit = ROUND_UP_TO_PAGES(VirtualLimit);
PhysicalNext = (ULONG_PTR) PhysicalAddress;
PhysicalNext &= (~((ULONG_PTR) 0xFFF));
while (VirtualNext < VirtualLimit) {
BlMmMapVirtualPage((PVOID) VirtualNext,
(PVOID) PhysicalNext,
Writeable,
Cacheable,
WriteThrough);
VirtualNext += PAGE_SIZE;
PhysicalNext += PAGE_SIZE;
}
return;
}
VOID
BlMmInitializeCodeSegment(
PCODE_SEGMENT CodeSegment
)
//++
//
// Routine Description:
//
// This function initializes the specified code segment.
//
// Arguments:
//
// CodeSegment - Supplies a pointer to the code segment to initialize.
//
//--
{
BlRtlZeroMemory(CodeSegment, sizeof(CODE_SEGMENT));
CodeSegment->Accessed = 1;
CodeSegment->Readable = 1;
CodeSegment->Code = 1;
CodeSegment->S = 1;
CodeSegment->Present = 1;
CodeSegment->Long = 1;
return;
}
VOID
BlMmInitializeDataSegment(
PDATA_SEGMENT DataSegment,
UINT32 Base,
UINT32 Limit
)
//++
//
// Routine Description:
//
// This function initializes the specified data segment.
//
// Arguments:
//
// DataSegment - Supplies a pointer to the data segment to initialize.
//
// Base - Supplies the base address of the data segment.
//
// Limit - Supplies the limit of the data segment.
//
//--
{
BlRtlZeroMemory(DataSegment, sizeof(DATA_SEGMENT));
DataSegment->Accessed = 1;
DataSegment->Writable = 1;
DataSegment->S = 1;
DataSegment->Present = 1;
DataSegment->Big = 1;
DataSegment->Base_23_0 = Base & 0xFFFFFF;
DataSegment->Base_31_24 = Base >> 24;
if (Limit <= 0xFFFFF) {
DataSegment->Limit_15_0 = Limit & 0xFFFF;
DataSegment->Limit_19_16 = (Limit >> 16) & 0xF;
} else {
DataSegment->Granularity = 1;
DataSegment->Limit_15_0 = (Limit >> 12) & 0xFFFF;
DataSegment->Limit_19_16 = (Limit >> 28) & 0xF;
}
return;
}
VOID
BlMmInitializeSystemSegment(
PSYSTEM_SEGMENT SystemSegment,
UINT32 Type,
ULONG_PTR Base,
UINT32 Limit
)
//++
//
// Routine Description:
//
// This function initializes the specified system segment.
//
// Arguments:
//
// SystemSegment - Supplies a pointer to the system segment to initialize.
//
// Type - Supplies the type of the system segment.
//
// Base - Supplies the base address of the system segment.
//
// Limit - Supplies the limit of the system segment.
//
//--
{
BlRtlZeroMemory(SystemSegment, sizeof(SYSTEM_SEGMENT));
SystemSegment->Type = (Type & 0xF);
SystemSegment->Present = 1;
SystemSegment->Base_23_0 = Base & 0xFFFFFF;
SystemSegment->Base_31_24 = (Base >> 24) & 0xFF;
#if defined(BOOT_X64)
SystemSegment->Base_63_32 = Base >> 32;
#endif
if (Limit <= 0xFFFFF) {
SystemSegment->Limit_15_0 = Limit & 0xFFFF;
SystemSegment->Limit_19_16 = (Limit >> 16) & 0xF;
} else {
SystemSegment->Granularity = 1;
SystemSegment->Limit_15_0 = (Limit >> 12) & 0xFFFF;
SystemSegment->Limit_19_16 = (Limit >> 28) & 0xF;
}
return;
}
#if !defined(BOOT_PXE)
VOID
BlMmEnableA20Gate(
VOID
)
//++
//
// Routine Description:
//
// This function enables A20 gate.
//
//--
{
BL_KEYBOARD_WRITE_OUTPUT_PORT(BL_KEYBOARD_A20_ENABLE);
BL_KEYBOARD_WRITE_COMMAND(BL_KEYBOARD_COMMAND_PULSE_OUTPUT_PORT);
return;
}
#endif
PVOID
BlMmGetExtendedBiosDataArea(
VOID
)
//++
//
// Routine Description:
//
// This function gets the address of the extended BIOS data area.
//
// Return Value:
//
// Address of the extended BIOS data area.
//
//--
{
UINT16 Segment;
Segment = *((PUINT16) (ULONG_PTR) 0x40E);
return (PVOID) (((ULONG_PTR) Segment) << 4);
}
VOID
BlMmInitializeSystem(
VOID
)
//++
//
// Routine Description:
//
// This function initializes boot loader memory management.
//
//--
{
UINT64 Delta;
UINT32 Index;
PBL_MM_PHYSICAL_REGION PhysicalRegion;
PBL_SMAP_ENTRY SmapEntry;
#if !defined(BOOT_PXE)
//
// Enable A20 gate.
//
BlMmEnableA20Gate();
#endif
//
// Get extended BIOS data area.
//
BlMmExtendedBiosDataArea = BlMmGetExtendedBiosDataArea();
//
// Get legacy CR3 value;
//
BlMmLegacyCr3 = BlMmGetCr3();
//
// Get initial GDTR.
//
BlMmGetGdtr(&BlMmInitialGdtr);
//
// Initialize memory map.
//
BlSmapInitialize();
//
// Create physical region lookaside.
//
BlRtlInitializeListHead(&BlMmPhysicalRegionList);
BlRtlInitializeListHead(&BlMmPhysicalRegionLookaside.FreeList);
for (Index = 0; Index < (sizeof(BlMmPhysicalRegionLookaside.StaticArray) / sizeof(BlMmPhysicalRegionLookaside.StaticArray[0])); Index += 1) {
BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &BlMmPhysicalRegionLookaside.StaticArray[Index].Entry);
}
//
// Initialize page tables.
//
BlMmInitializePageTables();
//
// Create reserved BIOS region.
//
BlMmCreatePhysicalRegion(0,
BL_MM_BIOS_SIZE,
BL_MM_PHYSICAL_REGION_BIOS);
//
// Create free regions based on SMAP.
//
for (Index = 0; Index < BlSystemMemoryMap.EntryCount; Index += 1) {
SmapEntry = &BlSystemMemoryMap.Entry[Index];
//
// Don't use any memory below 1MB (BIOS area) and above 2GB (Singularity uses MSB for marking and such).
//
if ((SmapEntry->Type == BL_SMAP_AVAILABLE) &&
(SmapEntry->Base >= BL_MM_BIOS_SIZE) &&
(SmapEntry->Base < 0x80000000UI64)
) {
if ((SmapEntry->Base % PAGE_SIZE) != 0) {
Delta = PAGE_SIZE - (SmapEntry->Base % PAGE_SIZE);
SmapEntry->Base += Delta;
SmapEntry->Size -= Delta;
}
SmapEntry->Size &= (~(0xFFFUI64));
if ((SmapEntry->Base + SmapEntry->Size) > 0x80000000UI64) {
SmapEntry->Size = 0x80000000UI64 - SmapEntry->Base;
}
if (SmapEntry->Size > 0) {
BlMmCreatePhysicalRegion(SmapEntry->Base,
SmapEntry->Size,
BL_MM_PHYSICAL_REGION_FREE);
}
}
}
//
// Initialize pool.
//
BlPoolInitialize();
//
// Add more entries to the physical region lookaside.
//
for (Index = 0; Index < 256; Index += 1) {
PhysicalRegion = (PBL_MM_PHYSICAL_REGION)
BlPoolAllocateBlock(sizeof(BL_MM_PHYSICAL_REGION));
BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &PhysicalRegion->Entry);
}
return;
}