425 lines
10 KiB
C++
425 lines
10 KiB
C++
|
//++
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// blpool.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// This module implements pool support for the boot loader environment.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
#include "bl.h"
|
||
|
|
||
|
#define BL_POOL_FREE 1
|
||
|
#define BL_POOL_BUSY 2
|
||
|
|
||
|
#define BL_POOL_GRANULARITY 256
|
||
|
|
||
|
C_ASSERT((BL_POOL_GRANULARITY & (BL_POOL_GRANULARITY - 1)) == 0);
|
||
|
|
||
|
#define BL_POOL_ROUND_UP(X) ROUND_UP_TO_POWER2(X, BL_POOL_GRANULARITY)
|
||
|
|
||
|
#define BL_POOL_SEGMENT_SIZE (8 * PAGE_SIZE)
|
||
|
|
||
|
C_ASSERT((BL_POOL_SEGMENT_SIZE & (BL_POOL_SEGMENT_SIZE - 1)) == 0);
|
||
|
|
||
|
#define BL_POOL_SEGMENT_ROUND_UP(X) ((X + (BL_POOL_SEGMENT_SIZE - 1)) & (~(BL_POOL_SEGMENT_SIZE - 1)))
|
||
|
|
||
|
#if defined(BOOT_X86)
|
||
|
|
||
|
#define BL_POOL_BLOCK_MAGIC1 0x01020304
|
||
|
#define BL_POOL_BLOCK_MAGIC2 0x05060708
|
||
|
|
||
|
#elif defined(BOOT_X64)
|
||
|
|
||
|
#define BL_POOL_BLOCK_MAGIC1 0x0102030405060708UI64
|
||
|
#define BL_POOL_BLOCK_MAGIC2 0x090A0B0C0D0E0F10UI64
|
||
|
|
||
|
#endif
|
||
|
|
||
|
typedef struct _BL_POOL_BLOCK {
|
||
|
ULONG_PTR Magic1;
|
||
|
LIST_ENTRY Entry;
|
||
|
ULONG_PTR Size;
|
||
|
ULONG_PTR State;
|
||
|
PVOID Allocator;
|
||
|
ULONG_PTR Pad;
|
||
|
ULONG_PTR Magic2;
|
||
|
} BL_POOL_BLOCK, *PBL_POOL_BLOCK;
|
||
|
|
||
|
C_ASSERT((sizeof(BL_POOL_BLOCK) % 16) == 0);
|
||
|
|
||
|
#if defined(BOOT_X86)
|
||
|
|
||
|
#define BL_POOL_SEGMENT_MAGIC1 0xFFFEFDFC
|
||
|
#define BL_POOL_SEGMENT_MAGIC2 0xFBFAF9F8
|
||
|
|
||
|
#elif defined(BOOT_X64)
|
||
|
|
||
|
#define BL_POOL_SEGMENT_MAGIC1 0xFFFEFDFCFBFAF9F8UI64
|
||
|
#define BL_POOL_SEGMENT_MAGIC2 0xF7F6F5F4F3F2F1F0UI64
|
||
|
|
||
|
#endif
|
||
|
|
||
|
typedef struct _BL_POOL_SEGMENT {
|
||
|
ULONG_PTR Magic1;
|
||
|
LIST_ENTRY Entry;
|
||
|
ULONG_PTR Size;
|
||
|
ULONG_PTR Start;
|
||
|
ULONG_PTR Limit;
|
||
|
LIST_ENTRY BlockList;
|
||
|
ULONG_PTR Magic2;
|
||
|
} BL_POOL_SEGMENT, *PBL_POOL_SEGMENT;
|
||
|
|
||
|
LIST_ENTRY BlPoolSegmentList;
|
||
|
|
||
|
VOID
|
||
|
BlPoolInitialize(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function initializes boot loader pool.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlInitializeListHead(&BlPoolSegmentList);
|
||
|
|
||
|
#if POOL_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("POOL: Segment list @ %p.\n", &BlPoolSegmentList);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if DEBUG
|
||
|
|
||
|
VOID
|
||
|
BlPoolDump(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function dumps boot loader pool.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBL_POOL_BLOCK Block;
|
||
|
PLIST_ENTRY BlockEntry;
|
||
|
PLIST_ENTRY BlockHead;
|
||
|
PBL_POOL_SEGMENT Segment;
|
||
|
PLIST_ENTRY SegmentEntry;
|
||
|
PLIST_ENTRY SegmentHead;
|
||
|
|
||
|
BlRtlPrintf("POOL: BlDumpPool: <StartOfDump>\n");
|
||
|
|
||
|
SegmentHead = &BlPoolSegmentList;
|
||
|
|
||
|
for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) {
|
||
|
|
||
|
Segment = CONTAINING_RECORD(SegmentEntry,
|
||
|
BL_POOL_SEGMENT,
|
||
|
Entry);
|
||
|
|
||
|
BlRtlPrintf("POOL: BlDumpPool: Segment @ %p\n", Segment);
|
||
|
|
||
|
BlockHead = &Segment->BlockList;
|
||
|
|
||
|
for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) {
|
||
|
|
||
|
Block = CONTAINING_RECORD(BlockEntry,
|
||
|
BL_POOL_BLOCK,
|
||
|
Entry);
|
||
|
|
||
|
BlRtlPrintf("POOL: BlDumpPool: Entry %p ... %p [%u]\n",
|
||
|
Block,
|
||
|
(ULONG_PTR) Block + Block->Size,
|
||
|
Block->State);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BlRtlPrintf("pool: BlDumpPool: <EndOfDump>\n");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
VOID
|
||
|
BlPoolVerify(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function verifies boot loader pool.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBL_POOL_BLOCK Block;
|
||
|
PLIST_ENTRY BlockEntry;
|
||
|
PLIST_ENTRY BlockHead;
|
||
|
PBL_POOL_BLOCK NextBlock;
|
||
|
PBL_POOL_SEGMENT Segment;
|
||
|
PLIST_ENTRY SegmentEntry;
|
||
|
PLIST_ENTRY SegmentHead;
|
||
|
|
||
|
SegmentHead = &BlPoolSegmentList;
|
||
|
|
||
|
BLASSERT(SegmentHead->Flink->Blink == SegmentHead);
|
||
|
BLASSERT(SegmentHead->Blink->Flink == SegmentHead);
|
||
|
|
||
|
for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) {
|
||
|
|
||
|
Segment = CONTAINING_RECORD(SegmentEntry,
|
||
|
BL_POOL_SEGMENT,
|
||
|
Entry);
|
||
|
|
||
|
BLASSERT_PTR(Segment->Magic1 == BL_POOL_SEGMENT_MAGIC1, Segment);
|
||
|
BLASSERT_PTR(Segment->Magic2 == BL_POOL_SEGMENT_MAGIC2, Segment);
|
||
|
|
||
|
BLASSERT_PTR(Segment->Entry.Flink->Blink == &Segment->Entry, Segment);
|
||
|
BLASSERT_PTR(Segment->Entry.Blink->Flink == &Segment->Entry, Segment);
|
||
|
|
||
|
|
||
|
BlockHead = &Segment->BlockList;
|
||
|
|
||
|
for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) {
|
||
|
|
||
|
Block = CONTAINING_RECORD(BlockEntry,
|
||
|
BL_POOL_BLOCK,
|
||
|
Entry);
|
||
|
|
||
|
BLASSERT_PTR(Block->Magic1 == BL_POOL_BLOCK_MAGIC1, Block);
|
||
|
BLASSERT_PTR(Block->Magic2 == BL_POOL_BLOCK_MAGIC2, Block);
|
||
|
|
||
|
BLASSERT_PTR((Block->State == BL_POOL_FREE) || ((Block->State == BL_POOL_BUSY)), Block);
|
||
|
|
||
|
BLASSERT_PTR(((ULONG_PTR) Block % BL_POOL_GRANULARITY) == 0, Block);
|
||
|
|
||
|
BLASSERT_PTR(Block->Size > sizeof(BL_POOL_BLOCK), Block);
|
||
|
BLASSERT_PTR((Block->Size % BL_POOL_GRANULARITY) == 0, Block);
|
||
|
|
||
|
if (Block->Entry.Flink != BlockHead) {
|
||
|
|
||
|
NextBlock = CONTAINING_RECORD(Block->Entry.Flink,
|
||
|
BL_POOL_BLOCK,
|
||
|
Entry);
|
||
|
|
||
|
BLASSERT_PTR(((ULONG_PTR) Block + Block->Size) == ((ULONG_PTR) NextBlock), Block);
|
||
|
}
|
||
|
|
||
|
BLASSERT_PTR(Block->Entry.Flink->Blink == &Block->Entry, Block);
|
||
|
BLASSERT_PTR(Block->Entry.Blink->Flink == &Block->Entry, Block);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlPoolGrow(
|
||
|
UINT32 Size
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function grows the pool.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Size - Supplies the growth size.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBL_POOL_BLOCK Block;
|
||
|
PBL_POOL_SEGMENT Segment;
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
BLASSERT(Size > 0);
|
||
|
|
||
|
Size = ROUND_UP_TO_PAGES(Size);
|
||
|
|
||
|
Segment = (PBL_POOL_SEGMENT) (ULONG_PTR) BlMmAllocatePhysicalRegion(Size, BL_MM_PHYSICAL_REGION_BOOT_LOADER);
|
||
|
|
||
|
BlRtlZeroMemory(Segment, Size);
|
||
|
|
||
|
Segment->Magic1 = BL_POOL_SEGMENT_MAGIC1;
|
||
|
Segment->Magic2 = BL_POOL_SEGMENT_MAGIC2;
|
||
|
Segment->Start = (ULONG_PTR) Segment;
|
||
|
Segment->Size = Size;
|
||
|
Segment->Limit = Segment->Start + Segment->Size;
|
||
|
BlRtlInitializeListHead(&Segment->BlockList);
|
||
|
|
||
|
Block = (PBL_POOL_BLOCK) (BL_POOL_ROUND_UP(((ULONG_PTR) (Segment + 1))));
|
||
|
Block->Magic1 = BL_POOL_BLOCK_MAGIC1;
|
||
|
Block->Magic2 = BL_POOL_BLOCK_MAGIC2;
|
||
|
Block->Size = Segment->Limit - (ULONG_PTR) Block;
|
||
|
Block->State = BL_POOL_FREE;
|
||
|
Block->Allocator = NULL;
|
||
|
|
||
|
BlRtlInsertTailList(&Segment->BlockList, &Block->Entry);
|
||
|
|
||
|
BlRtlInsertTailList(&BlPoolSegmentList, &Segment->Entry);
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PVOID
|
||
|
BlPoolAllocateBlock(
|
||
|
UINT32 Size
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function allocates from the boot loader pool.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Size - Supplies the number of bytes to allocate.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// A pointer to the allocated buffer.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBL_POOL_BLOCK Block;
|
||
|
PLIST_ENTRY BlockEntry;
|
||
|
PLIST_ENTRY BlockHead;
|
||
|
UINT32 GrowthSize;
|
||
|
PBL_POOL_BLOCK NewBlock;
|
||
|
PBL_POOL_SEGMENT Segment;
|
||
|
PLIST_ENTRY SegmentEntry;
|
||
|
PLIST_ENTRY SegmentHead;
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
BLASSERT(Size > 0);
|
||
|
|
||
|
Size += sizeof(BL_POOL_BLOCK);
|
||
|
Size = BL_POOL_ROUND_UP(Size);
|
||
|
|
||
|
SegmentHead = &BlPoolSegmentList;
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) {
|
||
|
|
||
|
Segment = CONTAINING_RECORD(SegmentEntry,
|
||
|
BL_POOL_SEGMENT,
|
||
|
Entry);
|
||
|
|
||
|
BlockHead = &Segment->BlockList;
|
||
|
|
||
|
for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) {
|
||
|
|
||
|
Block = CONTAINING_RECORD(BlockEntry,
|
||
|
BL_POOL_BLOCK,
|
||
|
Entry);
|
||
|
|
||
|
if ((Block->State == BL_POOL_FREE) && (Block->Size >= Size)) {
|
||
|
|
||
|
if (Block->Size > Size) {
|
||
|
|
||
|
NewBlock = (PBL_POOL_BLOCK) ((ULONG_PTR) Block + Size);
|
||
|
|
||
|
BlRtlZeroMemory(NewBlock, sizeof(BL_POOL_BLOCK));
|
||
|
|
||
|
NewBlock->Magic1 = BL_POOL_BLOCK_MAGIC1;
|
||
|
NewBlock->Magic2 = BL_POOL_BLOCK_MAGIC2;
|
||
|
NewBlock->Size = Block->Size - Size;
|
||
|
NewBlock->State = BL_POOL_FREE;
|
||
|
NewBlock->Allocator = NULL;
|
||
|
|
||
|
BlRtlInsertHeadList(&Block->Entry, &NewBlock->Entry);
|
||
|
|
||
|
Block->Size = Size;
|
||
|
}
|
||
|
|
||
|
Block->State = BL_POOL_BUSY;
|
||
|
Block->Allocator = _ReturnAddress();
|
||
|
|
||
|
BlRtlZeroMemory(Block + 1, Block->Size - sizeof(BL_POOL_BLOCK));
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
return (Block + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GrowthSize = BL_POOL_SEGMENT_ROUND_UP(Size);
|
||
|
|
||
|
BlPoolGrow(GrowthSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlPoolFreeBlock(
|
||
|
PVOID P
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function frees the specified pool block.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// P - Supplies a pointer to the block to free.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBL_POOL_BLOCK Block;
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
BLASSERT(((ULONG_PTR) P % __alignof(BL_POOL_BLOCK)) == 0);
|
||
|
|
||
|
Block = ((PBL_POOL_BLOCK) P) - 1;
|
||
|
|
||
|
BLASSERT(((ULONG_PTR) Block % BL_POOL_GRANULARITY) == 0);
|
||
|
|
||
|
BLASSERT(Block->State == BL_POOL_BUSY);
|
||
|
|
||
|
Block->State = BL_POOL_FREE;
|
||
|
Block->Allocator = NULL;
|
||
|
|
||
|
//
|
||
|
// AIFIX: Check for adjacent free blocks and coalesce.
|
||
|
//
|
||
|
|
||
|
BlPoolVerify();
|
||
|
|
||
|
return;
|
||
|
}
|