[BOOT:MM] Big work on MM :)
This commit is contained in:
parent
6a868b45ba
commit
2751b0f7bb
@ -106,7 +106,7 @@ typedef struct {
|
||||
ULONG MdlOffset;
|
||||
ULONG DescriptorCount;
|
||||
ULONG DescriptorSize;
|
||||
ULONG BasePageOffset;
|
||||
ULONG FirstPageOffset;
|
||||
} BOOT_MEMORY_INFO, *PBOOT_MEMORY_INFO;
|
||||
|
||||
//
|
||||
@ -154,11 +154,12 @@ typedef enum {
|
||||
typedef struct {
|
||||
LIST_ENTRY ListEntry;
|
||||
|
||||
ULONGLONG BasePage;
|
||||
ULONG Pages;
|
||||
ULONGLONG FirstPage;
|
||||
ULONGLONG MappedFirstPage;
|
||||
ULONG PageCount;
|
||||
|
||||
ULONG Attributes;
|
||||
ULONG Type;
|
||||
MEMORY_TYPE Type;
|
||||
} MEMORY_DESCRIPTOR, *PMEMORY_DESCRIPTOR;
|
||||
|
||||
typedef enum {
|
||||
|
@ -18,12 +18,27 @@ Abstract:
|
||||
|
||||
#include "bootlib.h"
|
||||
|
||||
#define MDL_OPERATION_FLAGS_TRUNCATE 0x02
|
||||
|
||||
NTSTATUS
|
||||
MmFwGetMemoryMap (
|
||||
IN OUT PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
IN ULONG Flags
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
MmMdpHasPrecedence (
|
||||
IN MEMORY_TYPE A,
|
||||
IN MEMORY_TYPE B
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
MmMdpTruncateDescriptor (
|
||||
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
IN PMEMORY_DESCRIPTOR Descriptor,
|
||||
IN ULONG Flags
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
MmMdAddDescriptorToList (
|
||||
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
@ -49,8 +64,8 @@ MmMdFreeList (
|
||||
|
||||
PMEMORY_DESCRIPTOR
|
||||
MmMdInitDescriptor (
|
||||
IN ULONGLONG BasePage,
|
||||
IN ULONGLONG MappedBasePage,
|
||||
IN ULONGLONG FirstPage,
|
||||
IN ULONGLONG MappedFirstPage,
|
||||
IN ULONGLONG PageCount,
|
||||
IN ULONG Attributes,
|
||||
IN MEMORY_TYPE Type
|
||||
|
@ -654,12 +654,12 @@ Return Value:
|
||||
MemoryInfo->MdlOffset = sizeof(BOOT_MEMORY_INFO);
|
||||
MemoryInfo->DescriptorCount = 1;
|
||||
MemoryInfo->DescriptorSize = sizeof(MEMORY_DESCRIPTOR);
|
||||
MemoryInfo->BasePageOffset = FIELD_OFFSET(MEMORY_DESCRIPTOR, BasePage);
|
||||
MemoryInfo->FirstPageOffset = FIELD_OFFSET(MEMORY_DESCRIPTOR, FirstPage);
|
||||
|
||||
MemoryDescriptor = (PMEMORY_DESCRIPTOR)(&EfiInitScratch[ScratchUsed]);
|
||||
ScratchUsed += sizeof(MEMORY_DESCRIPTOR);
|
||||
MemoryDescriptor->BasePage = (UINTN)InputParameters->ImageBase >> PAGE_SHIFT;
|
||||
MemoryDescriptor->Pages = ALIGN_UP(InputParameters->ImageSize, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
MemoryDescriptor->FirstPage = (UINTN)InputParameters->ImageBase >> PAGE_SHIFT;
|
||||
MemoryDescriptor->PageCount = ALIGN_UP(InputParameters->ImageSize, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
MemoryDescriptor->Attributes = MEMORY_ATTRIBUTE_WB;
|
||||
MemoryDescriptor->Type = MEMORY_TYPE_BOOT_APPLICATION;
|
||||
|
||||
|
@ -15,8 +15,266 @@ Abstract:
|
||||
|
||||
#include "bootmgr.h"
|
||||
#include "efi.h"
|
||||
#include "efilib.h"
|
||||
#include "mm.h"
|
||||
|
||||
#define _1MiB 1048576
|
||||
|
||||
#define EFI_PAGE(NtPage) (((NtPage) << PAGE_SHIFT) >> EFI_PAGE_SHIFT)
|
||||
#define NT_PAGE(EfiPage) (((EfiPage) << EFI_PAGE_SHIFT) >> PAGE_SHIFT)
|
||||
|
||||
extern EFI_BOOT_SERVICES *EfiBS;
|
||||
extern PBOOT_DEVICE BlpBootDevice;
|
||||
|
||||
NTSTATUS
|
||||
EfiGetMemoryMap (
|
||||
IN OUT UINTN *MemoryMapSize,
|
||||
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
||||
IN OUT UINTN *MapKey,
|
||||
IN OUT UINTN *DescriptorSize,
|
||||
IN OUT UINT32 *DescriptorVersion
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Wrapper for EFI_BOOT_SERVICES.GetMemoryMap(). Gets the firmware memory map
|
||||
and places it into a buffer.
|
||||
|
||||
Arguments:
|
||||
|
||||
MemoryMapSize - pointer to the size of the buffer.
|
||||
|
||||
MemoryMap - pointer to the buffer to store the memory map in.
|
||||
|
||||
MapKey - ponter to the memory map key.
|
||||
|
||||
DescriptorSize - pointer to the size of each memory map descriptor.
|
||||
|
||||
DescriptorVersion - pointer to the version of memory map descriptors.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS if successful,
|
||||
Other NTSTATUS value if an error occurs.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
return EfiGetNtStatusCode(
|
||||
EfiBS->GetMemoryMap(
|
||||
MemoryMapSize,
|
||||
MemoryMap,
|
||||
MapKey,
|
||||
DescriptorSize,
|
||||
DescriptorVersion
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
EfiAllocatePages (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Wrapper for EFI_BOOT_SERVICES.AllocatePages(). Allocates contiguous pages
|
||||
of physical memory.
|
||||
|
||||
Arguments:
|
||||
|
||||
Type - the type of allocation.
|
||||
|
||||
MemoryType - the type of memory to allocate.
|
||||
|
||||
Pages - the number of pages to allocate.
|
||||
|
||||
Memory - pointer to a physical address of the allocation.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS if successful,
|
||||
Other NTSTATUS value if an error occurs.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
return EfiGetNtStatusCode(
|
||||
EfiBS->AllocatePages(
|
||||
Type,
|
||||
MemoryType,
|
||||
Pages,
|
||||
Memory
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
EfiFreePages (
|
||||
IN EFI_PHYSICAL_ADDRESS Memory,
|
||||
IN UINTN Pages
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Wrapper for EFI_BOOT_SERVICES.FreePages(). Frees contiguous pages
|
||||
of physical memory.
|
||||
|
||||
Arguments:
|
||||
|
||||
Memory - physical address of the pages to be freed.
|
||||
|
||||
Pages - the number of pages to free.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS if successful,
|
||||
Other NTSTATUS value if an error occurs.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
return EfiGetNtStatusCode(
|
||||
EfiBS->FreePages(
|
||||
Memory,
|
||||
Pages
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
MEMORY_TYPE
|
||||
BlMmTranslateEfiMemoryType (
|
||||
IN EFI_MEMORY_TYPE EfiMemoryType
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Translates an EFI memory type to an NT memory type.
|
||||
|
||||
Arguments:
|
||||
|
||||
EfiMemoryType - the EFI memory type.
|
||||
|
||||
Return Value:
|
||||
|
||||
The NT memory type.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
switch (EfiMemoryType) {
|
||||
case EfiConventionalMemory:
|
||||
return MEMORY_TYPE_FREE;
|
||||
case EfiLoaderCode:
|
||||
case EfiLoaderData:
|
||||
return MEMORY_TYPE_BOOT_APPLICATION;
|
||||
case EfiBootServicesCode:
|
||||
case EfiBootServicesData:
|
||||
return MEMORY_TYPE_BOOT_SERVICES;
|
||||
case EfiRuntimeServicesCode:
|
||||
return MEMORY_TYPE_RUNTIME_SERVICES_CODE;
|
||||
case EfiRuntimeServicesData:
|
||||
return MEMORY_TYPE_RUNTIME_SERVICES_DATA;
|
||||
case EfiUnusableMemory:
|
||||
return MEMORY_TYPE_UNUSABLE;
|
||||
case EfiACPIReclaimMemory:
|
||||
return MEMORY_TYPE_ACPI_RECLAIM;
|
||||
case EfiACPIMemoryNVS:
|
||||
return MEMORY_TYPE_ACPI_NVS;
|
||||
case EfiMemoryMappedIO:
|
||||
return MEMORY_TYPE_MMIO;
|
||||
case EfiMemoryMappedIOPortSpace:
|
||||
return MEMORY_TYPE_MMIO_PORT_SPACE;
|
||||
case EfiPalCode:
|
||||
return MEMORY_TYPE_PAL_CODE;
|
||||
case EfiPersistentMemory:
|
||||
return MEMORY_TYPE_PERSISTENT;
|
||||
case EfiReservedMemoryType:
|
||||
default:
|
||||
if ((ULONG)EfiMemoryType < MAXLONG) {
|
||||
return MEMORY_TYPE_RESERVED;
|
||||
} else {
|
||||
return (MEMORY_TYPE)EfiMemoryType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ULONG
|
||||
MmFwpGetOsAttributeType (
|
||||
IN UINT64 EfiAttributes
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Translates EFI memory descriptor attributes to NT memory descriptor attributes.
|
||||
|
||||
Arguments:
|
||||
|
||||
EfiAttributes - the EFI attributes.
|
||||
|
||||
Return Value:
|
||||
|
||||
The NT attributes.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG NtAttributes;
|
||||
|
||||
NtAttributes = 0;
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_UC) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_UC;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_WC) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_WC;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_WT) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_WT;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_WB) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_WB;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_UCE) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_UCE;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_WP) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_WP;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_RP) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_RP;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_XP) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_XP;
|
||||
}
|
||||
|
||||
if (EfiAttributes & EFI_MEMORY_RUNTIME) {
|
||||
NtAttributes |= MEMORY_ATTRIBUTE_RUNTIME;
|
||||
}
|
||||
|
||||
return NtAttributes;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
MmFwGetMemoryMap (
|
||||
IN OUT PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
@ -27,11 +285,13 @@ MmFwGetMemoryMap (
|
||||
|
||||
Routine Description:
|
||||
|
||||
Converts an NT status code into an EFI status code.
|
||||
Gets the memory map from EFI and converts it into an MDL.
|
||||
|
||||
Arguments:
|
||||
|
||||
Status - The NT status code to be converted.
|
||||
Mdl - Pointer to the MDL to store new descriptors in.
|
||||
|
||||
Flags - Unused.
|
||||
|
||||
Return Value:
|
||||
|
||||
@ -41,16 +301,288 @@ Return Value:
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UINTN EfiMapSize;
|
||||
UINTN EfiMapKey;
|
||||
UINTN EfiDescriptorSize;
|
||||
UINT32 EfiDescriptorVersion;
|
||||
UINTN PageCount, EfiPageCount;
|
||||
EFI_PHYSICAL_ADDRESS EfiBuffer;
|
||||
EFI_MEMORY_DESCRIPTOR *EfiMap;
|
||||
BOOLEAN IsRamdisk;
|
||||
MEMORY_TYPE MemoryType;
|
||||
UINT64 EfiStartPage, EfiEndPage;
|
||||
UINT64 EfiRamdiskStartPage, EfiRamdiskEndPage;
|
||||
PMEMORY_DESCRIPTOR NtDescriptor;
|
||||
|
||||
(VOID)Flags;
|
||||
|
||||
//
|
||||
// Make sure Mdl is valid.
|
||||
//
|
||||
EfiBuffer = (EFI_PHYSICAL_ADDRESS)0;
|
||||
|
||||
if (Mdl == NULL) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MmMdFreeList(Mdl);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
//
|
||||
// Get the memory map from firmware.
|
||||
// This is a "fake" call to actually just get
|
||||
// the required buffer size and other info.
|
||||
//
|
||||
EfiMapSize = 0;
|
||||
Status = EfiGetMemoryMap(&EfiMapSize, NULL, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion);
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL) {
|
||||
DebugPrint(L"MmFwGetMemoryMap(): EfiGetMemoryMap() failed\r\n");
|
||||
|
||||
//
|
||||
// Make sure status is not successful, just in case
|
||||
// EfiGetMemoryMap() somehow succeeded.
|
||||
//
|
||||
if (NT_SUCCESS(Status)) {
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
EfiMapSize += 4 * EfiDescriptorSize;
|
||||
PageCount = (ALIGN_UP(EfiMapSize, PAGE_SIZE) >> PAGE_SHIFT) + 1;
|
||||
EfiPageCount = EFI_PAGE(PageCount);
|
||||
Status = EfiAllocatePages(AllocateAnyPages, EfiLoaderData, EfiPageCount, &EfiBuffer);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DebugPrint(L"MmFwGetMemoryMap(): EfiAllocatePages() failed\r\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
EfiMap = (EFI_MEMORY_DESCRIPTOR *)EfiBuffer;
|
||||
Status = EfiGetMemoryMap(&EfiMapSize, EfiMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DebugPrint(L"MmFwGetMemoryMap(): EfiGetMemoryMap() failed\r\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (EfiDescriptorSize < sizeof(EFI_MEMORY_DESCRIPTOR) || EfiMapSize % EfiDescriptorSize) {
|
||||
DebugPrint(L"MmFwGetMemoryMap(): Invalid EFI descriptor/map sizes\r\n");
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (BlpBootDevice->Type == BOOT_DEVICE_TYPE_BLOCK && BlpBootDevice->Block.Type == BOOT_BLOCK_DEVICE_TYPE_RAMDISK) {
|
||||
IsRamdisk = TRUE;
|
||||
EfiRamdiskStartPage = BlpBootDevice->Block.Ramdisk.ImageBase.QuadPart >> EFI_PAGE_SHIFT;
|
||||
EfiRamdiskEndPage = EfiRamdiskStartPage + ((BlpBootDevice->Block.Ramdisk.ImageBase.QuadPart + BlpBootDevice->Block.Ramdisk.ImageSize) >> EFI_PAGE_SHIFT);
|
||||
} else {
|
||||
IsRamdisk = FALSE;
|
||||
}
|
||||
|
||||
for (
|
||||
;
|
||||
EfiMapSize > 0;
|
||||
EfiMapSize -= EfiDescriptorSize,
|
||||
EfiMap = (EFI_MEMORY_DESCRIPTOR *)((PUCHAR)EfiMap + EfiDescriptorSize)
|
||||
) {
|
||||
//
|
||||
// Skip desciptors with no pages.
|
||||
//
|
||||
if (EfiMap->NumberOfPages == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MemoryType = BlMmTranslateEfiMemoryType(EfiMap->Type);
|
||||
if (MemoryType == MEMORY_TYPE_FREE) {
|
||||
EfiStartPage = ALIGN_UP(EfiMap->PhysicalStart, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT;
|
||||
|
||||
} else {
|
||||
EfiStartPage = EfiMap->PhysicalStart >> EFI_PAGE_SHIFT;
|
||||
}
|
||||
EfiEndPage = ALIGN_DOWN(EfiStartPage + EfiMap->NumberOfPages, EFI_PAGE(1));
|
||||
|
||||
//
|
||||
// Regions under 1MiB are mapped differently.
|
||||
//
|
||||
if (EfiStartPage < (_1MiB >> EFI_PAGE_SHIFT)) {
|
||||
//
|
||||
// Reserve region at page 0.
|
||||
//
|
||||
if (EfiStartPage == 0) {
|
||||
NtDescriptor = MmMdInitDescriptor(
|
||||
NT_PAGE(EfiStartPage),
|
||||
0,
|
||||
1,
|
||||
MmFwpGetOsAttributeType(EfiMap->Attribute),
|
||||
MEMORY_TYPE_RESERVED
|
||||
);
|
||||
if (NtDescriptor == NULL) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Continue if this descriptor was only one page.
|
||||
//
|
||||
if (EfiEndPage == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// For regions crossing over the 1MiB boundary,
|
||||
// create two descriptors. One for <1MiB and one
|
||||
// for over >=1MiB.
|
||||
//
|
||||
if (EfiEndPage > (_1MiB >> EFI_PAGE_SHIFT)) {
|
||||
NtDescriptor = MmMdInitDescriptor(
|
||||
NT_PAGE(EfiStartPage),
|
||||
0,
|
||||
(_1MiB >> PAGE_SHIFT) - NT_PAGE(EfiStartPage),
|
||||
MmFwpGetOsAttributeType(EfiMap->Attribute),
|
||||
MemoryType
|
||||
);
|
||||
if (NtDescriptor == NULL) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (NtDescriptor->Type == MEMORY_TYPE_FREE) {
|
||||
NtDescriptor->Attributes |= MEMORY_ATTRIBUTE_BELOW_1MIB;
|
||||
}
|
||||
|
||||
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Continue to creating the >=1MiB mapping.
|
||||
//
|
||||
EfiStartPage = _1MiB >> EFI_PAGE_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsRamdisk) {
|
||||
if (
|
||||
EfiStartPage <= EfiRamdiskStartPage
|
||||
&& EfiEndPage >= EfiRamdiskEndPage
|
||||
) {
|
||||
if (NT_PAGE(EfiStartPage) < NT_PAGE(EfiRamdiskStartPage)) {
|
||||
NtDescriptor = MmMdInitDescriptor(
|
||||
NT_PAGE(EfiStartPage),
|
||||
0,
|
||||
NT_PAGE(EfiRamdiskStartPage) - NT_PAGE(EfiStartPage),
|
||||
MmFwpGetOsAttributeType(EfiMap->Attribute),
|
||||
MemoryType
|
||||
);
|
||||
if (NtDescriptor == NULL) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create a memory descriptor for the ramdisk.
|
||||
//
|
||||
NtDescriptor = MmMdInitDescriptor(
|
||||
NT_PAGE(EfiRamdiskStartPage),
|
||||
0,
|
||||
NT_PAGE(EfiRamdiskEndPage) - NT_PAGE(EfiRamdiskStartPage),
|
||||
MmFwpGetOsAttributeType(EfiMap->Attribute),
|
||||
MemoryType
|
||||
);
|
||||
if (NtDescriptor == NULL) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Continue if there is no more memory to map inside the ramdisk.
|
||||
//
|
||||
if (NT_PAGE(EfiEndPage) <= NT_PAGE(EfiRamdiskEndPage)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EfiStartPage = EFI_PAGE(NT_PAGE(EfiRamdiskEndPage - 1) + 1);
|
||||
} else if (
|
||||
NT_PAGE(EfiStartPage) < NT_PAGE(EfiRamdiskStartPage)
|
||||
&& NT_PAGE(EfiEndPage) > NT_PAGE(EfiRamdiskStartPage)
|
||||
) {
|
||||
//
|
||||
// Remove the region inside the start of the ramdisk.
|
||||
//
|
||||
EfiEndPage = EfiRamdiskStartPage;
|
||||
} else if (
|
||||
NT_PAGE(EfiStartPage) < NT_PAGE(EfiRamdiskEndPage)
|
||||
&& NT_PAGE(EfiEndPage) > NT_PAGE(EfiRamdiskEndPage)
|
||||
) {
|
||||
//
|
||||
// Remove the region inside the end of the ramdisk.
|
||||
//
|
||||
EfiStartPage = EfiRamdiskEndPage;
|
||||
}
|
||||
|
||||
//
|
||||
// Continue if the region is now empty.
|
||||
//
|
||||
if (NT_PAGE(EfiStartPage) == NT_PAGE(EfiEndPage)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create a memory descriptor for the region.
|
||||
//
|
||||
NtDescriptor = MmMdInitDescriptor(
|
||||
NT_PAGE(EfiStartPage),
|
||||
0,
|
||||
NT_PAGE(EfiEndPage) - NT_PAGE(EfiStartPage),
|
||||
MmFwpGetOsAttributeType(EfiMap->Attribute),
|
||||
MemoryType
|
||||
);
|
||||
if (NtDescriptor == NULL) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Set attribute if below 1MiB.
|
||||
//
|
||||
if (NtDescriptor->Type == MEMORY_TYPE_FREE && EfiEndPage <= (_1MiB >> EFI_PAGE_SHIFT)) {
|
||||
NtDescriptor->Attributes |= MEMORY_ATTRIBUTE_BELOW_1MIB;
|
||||
}
|
||||
|
||||
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Account for possible MDL changes due to EfiFreePages(EfiBuffer).
|
||||
//
|
||||
|
||||
exit:
|
||||
if (EfiBuffer) {
|
||||
EfiFreePages(EfiBuffer, EfiPageCount);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
MmMdFreeList(Mdl);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
@ -32,11 +32,11 @@ Routine Description:
|
||||
|
||||
Arguments:
|
||||
|
||||
MemoryInfo - pointer to the memory info structure.
|
||||
MemoryInfo - Pointer to the memory info.
|
||||
|
||||
TranslationType - the current translation type being used.
|
||||
TranslationType - The current translation type.
|
||||
|
||||
LibraryParameters - pointer to the library parameters structure.
|
||||
LibraryParameters - Pointer to the library parameters.
|
||||
|
||||
Return Value:
|
||||
|
||||
|
@ -22,10 +22,316 @@ Abstract:
|
||||
MEMORY_DESCRIPTOR MmStaticMemoryDescriptors[MAX_STATIC_DESCRIPTOR_COUNT];
|
||||
|
||||
PMEMORY_DESCRIPTOR MmGlobalMemoryDescriptors;
|
||||
ULONG MmGlobalMemoryDescriptorCount;
|
||||
ULONG MmGlobalMemoryDescriptorCount, MmGlobalMemoryDescriptorsUsed;
|
||||
|
||||
PMEMORY_DESCRIPTOR MmDynamicMemoryDescriptors;
|
||||
ULONG MmDynamicMemoryDescriptorCount;
|
||||
ULONG MmDynamicMemoryDescriptorCount, MmDynamicMemoryDescriptorsUsed;
|
||||
|
||||
BOOLEAN
|
||||
MmMdpHasPrecedence (
|
||||
IN MEMORY_TYPE A,
|
||||
IN MEMORY_TYPE B
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Compares two memory types to determine which has precedence.
|
||||
|
||||
Arguments:
|
||||
|
||||
A - memory type A.
|
||||
|
||||
B - memory type B.
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if A has precedence over B, or if neither has precedence.
|
||||
FALSE if B has precedence over A.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG ClassA, ClassB;
|
||||
|
||||
ClassA = A >> 28;
|
||||
ClassB = B >> 28;
|
||||
|
||||
if (B == MEMORY_TYPE_FREE) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (A == MEMORY_TYPE_FREE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ClassA > 0x0F) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (ClassB > 0x0F) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ClassA != 0x0F) {
|
||||
return (ClassB != 0x0F && (ClassA == 0x0D || ClassB != 0x0D)) ? TRUE:FALSE;
|
||||
}
|
||||
|
||||
if (ClassB != 0x0F) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Incomplete.
|
||||
//
|
||||
ConsolePrint(L"MmMdpHasPrecedence() is incomplete\r\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
MmMdpTruncateDescriptor (
|
||||
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
IN PMEMORY_DESCRIPTOR Descriptor,
|
||||
IN ULONG Flags
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Trunactes a memory descriptor that overlaps
|
||||
with adjacent descriptors.
|
||||
|
||||
Arguments:
|
||||
|
||||
Mdl - The MDL containing Descriptor.
|
||||
|
||||
Descriptor - The descriptor to truncate.
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if Descriptor was deleted from Mdl.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PMEMORY_DESCRIPTOR PrevDescriptor, NextDescriptor, NewDescriptor;
|
||||
ULONGLONG DescriptorEnd, PrevDescriptorEnd, NextDescriptorEnd;
|
||||
ULONGLONG MappedFirstPage;
|
||||
ULONGLONG Change;
|
||||
|
||||
PrevDescriptor = (PMEMORY_DESCRIPTOR)Descriptor->ListEntry.Blink;
|
||||
NextDescriptor = (PMEMORY_DESCRIPTOR)Descriptor->ListEntry.Flink;
|
||||
|
||||
DescriptorEnd = Descriptor->FirstPage + Descriptor->PageCount;
|
||||
PrevDescriptorEnd = PrevDescriptor->FirstPage + PrevDescriptor->PageCount;
|
||||
NextDescriptorEnd = NextDescriptor->FirstPage + NextDescriptor->PageCount;
|
||||
|
||||
//
|
||||
// Check if overlapping with previous descriptor.
|
||||
//
|
||||
if (Descriptor->ListEntry.Blink != Mdl->Head && Descriptor->FirstPage < PrevDescriptorEnd) {
|
||||
if (MmMdpHasPrecedence(Descriptor->Type, PrevDescriptor->Type)) {
|
||||
PrevDescriptor->PageCount = Descriptor->FirstPage - PrevDescriptor->FirstPage;
|
||||
|
||||
if (DescriptorEnd < PrevDescriptorEnd) {
|
||||
if (PrevDescriptor->MappedFirstPage) {
|
||||
MappedFirstPage = PrevDescriptor->MappedFirstPage + DescriptorEnd - PrevDescriptor->FirstPage;
|
||||
} else {
|
||||
MappedFirstPage = 0;
|
||||
}
|
||||
|
||||
NewDescriptor = MmMdInitDescriptor(
|
||||
DescriptorEnd,
|
||||
MappedFirstPage,
|
||||
PrevDescriptorEnd - DescriptorEnd,
|
||||
PrevDescriptor->Attributes,
|
||||
PrevDescriptor->Type
|
||||
);
|
||||
if (NewDescriptor != NULL) {
|
||||
MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Delete and free the previous
|
||||
// descriptor if it is now empty.
|
||||
//
|
||||
if (PrevDescriptor->PageCount == 0) {
|
||||
MmMdRemoveDescriptorFromList(Mdl, PrevDescriptor);
|
||||
MmMdFreeDescriptor(PrevDescriptor);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Remove if completely overlapping.
|
||||
//
|
||||
if (DescriptorEnd <= PrevDescriptorEnd) {
|
||||
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
|
||||
MmMdFreeDescriptor(Descriptor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, move the descriptor.
|
||||
//
|
||||
Change = PrevDescriptorEnd - Descriptor->FirstPage;
|
||||
Descriptor->FirstPage += Change;
|
||||
Descriptor->PageCount -= Change;
|
||||
if (Descriptor->MappedFirstPage) {
|
||||
Descriptor->MappedFirstPage += Change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check if overlapping with next descriptor.
|
||||
//
|
||||
if (Descriptor->ListEntry.Flink != Mdl->Head && NextDescriptor->FirstPage < DescriptorEnd) {
|
||||
if (MmMdpHasPrecedence(NextDescriptor->Type, Descriptor->Type)) {
|
||||
Descriptor->PageCount = NextDescriptor->FirstPage - Descriptor->FirstPage;
|
||||
|
||||
if (NextDescriptorEnd < DescriptorEnd) {
|
||||
if (Descriptor->MappedFirstPage) {
|
||||
MappedFirstPage = Descriptor->MappedFirstPage + NextDescriptorEnd - Descriptor->FirstPage;
|
||||
} else {
|
||||
MappedFirstPage = 0;
|
||||
}
|
||||
|
||||
NewDescriptor = MmMdInitDescriptor(
|
||||
NextDescriptorEnd,
|
||||
MappedFirstPage,
|
||||
DescriptorEnd - NextDescriptorEnd,
|
||||
Descriptor->Attributes,
|
||||
Descriptor->Type
|
||||
);
|
||||
if (NewDescriptor != NULL) {
|
||||
MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Delete and free the previous
|
||||
// descriptor if it is now empty.
|
||||
//
|
||||
if (Descriptor->PageCount == 0) {
|
||||
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
|
||||
MmMdFreeDescriptor(Descriptor);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Remove if completely overlapping.
|
||||
//
|
||||
if (NextDescriptorEnd <= DescriptorEnd) {
|
||||
MmMdRemoveDescriptorFromList(Mdl, NextDescriptor);
|
||||
MmMdFreeDescriptor(NextDescriptor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, move the next descriptor.
|
||||
//
|
||||
Change = DescriptorEnd - NextDescriptor->FirstPage;
|
||||
NextDescriptor->FirstPage += Change;
|
||||
NextDescriptor->PageCount -= Change;
|
||||
if (NextDescriptor->MappedFirstPage) {
|
||||
NextDescriptor->MappedFirstPage += Change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
MmMdAddDescriptorToList (
|
||||
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
||||
IN PMEMORY_DESCRIPTOR Descriptor,
|
||||
IN ULONG Flags
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Adds a descriptor to a MDL.
|
||||
|
||||
Arguments:
|
||||
|
||||
Mdl - the MDL to add Descriptor to.
|
||||
|
||||
Descriptor - the descriptor to add to Mdl.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS if successful,
|
||||
STATUS_INVALID_PARAMETER if Mdl or Descriptor are invalid.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PMEMORY_DESCRIPTOR CurrentDescriptor;
|
||||
|
||||
if (Mdl == NULL || Descriptor == NULL) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Mdl->Current) {
|
||||
if (Descriptor->FirstPage < ((PMEMORY_DESCRIPTOR)Mdl->Current)->FirstPage) {
|
||||
Entry = Mdl->Head->Flink;
|
||||
} else {
|
||||
Entry = Mdl->Current;
|
||||
}
|
||||
} else {
|
||||
Entry = Mdl->Head->Flink;
|
||||
}
|
||||
|
||||
//
|
||||
// Search for an existing descriptor for this region.
|
||||
//
|
||||
while (Entry != Mdl->Head) {
|
||||
CurrentDescriptor = (PMEMORY_DESCRIPTOR)Entry;
|
||||
|
||||
if (
|
||||
Descriptor->FirstPage >= CurrentDescriptor->FirstPage && (Descriptor->FirstPage != CurrentDescriptor->FirstPage
|
||||
|| !MmMdpHasPrecedence(Descriptor->Type, CurrentDescriptor->Type))
|
||||
) {
|
||||
Entry = Entry->Flink;
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Insert descriptor into the list
|
||||
// right before the current entry.
|
||||
//
|
||||
Descriptor->ListEntry.Blink = Entry->Blink;
|
||||
Descriptor->ListEntry.Flink = Entry;
|
||||
Entry->Blink->Flink = &Descriptor->ListEntry;
|
||||
Entry->Blink = &Descriptor->ListEntry;
|
||||
|
||||
//
|
||||
// Truncate overlapping descriptors
|
||||
// into one larger descriptor.
|
||||
//
|
||||
if (Flags & MDL_OPERATION_FLAGS_TRUNCATE) {
|
||||
MmMdpTruncateDescriptor(Mdl, Descriptor, Flags);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// If there are no existing descriptors for this region
|
||||
// (or the list is empty), insert and truncate the descriptor.
|
||||
//
|
||||
InsertTailList(Mdl->Head, &Descriptor->ListEntry);
|
||||
if (Flags & MDL_OPERATION_FLAGS_TRUNCATE) {
|
||||
MmMdpTruncateDescriptor(Mdl, Descriptor, Flags);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
MmMdRemoveDescriptorFromList (
|
||||
@ -55,10 +361,6 @@ Return Value:
|
||||
PLIST_ENTRY Blink;
|
||||
|
||||
Blink = Descriptor->ListEntry.Blink;
|
||||
|
||||
//
|
||||
// Remove the descriptor from the MDL.
|
||||
//
|
||||
RemoveEntryList(&Descriptor->ListEntry);
|
||||
|
||||
//
|
||||
@ -129,7 +431,7 @@ Return Value:
|
||||
// Free the descriptor from the heap.
|
||||
// TODO: Use BlMmFreeHeap()
|
||||
//
|
||||
ConsolePrint(L"Cannot free memory descriptor: BlMmFreeHeap() is not implemented\r\n");
|
||||
ConsolePrint(L"MmMdFreeDescriptor(): need BlMmFreeHeap() to free descriptor\r\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
// return BlMmFreeHeap(Descriptor);
|
||||
}
|
||||
@ -147,7 +449,7 @@ Routine Description:
|
||||
|
||||
Arguments:
|
||||
|
||||
Mdl - the MDL to free.
|
||||
Mdl - the MDL.
|
||||
|
||||
Return Value:
|
||||
|
||||
@ -166,6 +468,56 @@ Return Value:
|
||||
}
|
||||
}
|
||||
|
||||
PMEMORY_DESCRIPTOR
|
||||
MmMdInitDescriptor (
|
||||
IN ULONGLONG FirstPage,
|
||||
IN ULONGLONG MappedFirstPage,
|
||||
IN ULONGLONG PageCount,
|
||||
IN ULONG Attributes,
|
||||
IN MEMORY_TYPE Type
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initializes a memory descriptor.
|
||||
|
||||
Arguments:
|
||||
|
||||
FirstPage - The first page in the region.
|
||||
|
||||
MappedFirstPage - The first page in the mapping.
|
||||
|
||||
Attributes - Memory attributes of the region.
|
||||
|
||||
Type - Memory type of the region.
|
||||
|
||||
Return Value:
|
||||
|
||||
Pointer to the memory descriptor,
|
||||
NULL if an error occurs.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PMEMORY_DESCRIPTOR Descriptor;
|
||||
|
||||
if (MmGlobalMemoryDescriptorsUsed >= MmGlobalMemoryDescriptorCount) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Descriptor = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorsUsed++];
|
||||
Descriptor->FirstPage = FirstPage;
|
||||
Descriptor->MappedFirstPage = MappedFirstPage;
|
||||
Descriptor->PageCount = PageCount;
|
||||
Descriptor->Attributes = Attributes;
|
||||
Descriptor->Type = Type;
|
||||
InitializeListHead(&Descriptor->ListEntry);
|
||||
|
||||
return Descriptor;
|
||||
}
|
||||
|
||||
VOID
|
||||
MmMdInitialize (
|
||||
IN ULONG Unused,
|
||||
@ -201,6 +553,7 @@ Return Value:
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ Routine Description:
|
||||
|
||||
Arguments:
|
||||
|
||||
Mdl - the MDL to initialize.
|
||||
Mdl - Pointer to the MDL.
|
||||
|
||||
Return Value:
|
||||
|
||||
@ -72,9 +72,9 @@ Routine Description:
|
||||
|
||||
Arguments:
|
||||
|
||||
MemoryInfo - pointer to the memory info structure.
|
||||
MemoryInfo - Pointer to the memory info structure.
|
||||
|
||||
MinimumAllocation - minimum amount of pages to grow the pool by at a time.
|
||||
MinimumAllocation - Minimum amount of pages to grow the pool by at a time.
|
||||
|
||||
Return Value:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user