diff --git a/BOOT/ENVIRON/INC/bootmgr.h b/BOOT/ENVIRON/INC/bootmgr.h index 765e24f..5e79bb6 100644 --- a/BOOT/ENVIRON/INC/bootmgr.h +++ b/BOOT/ENVIRON/INC/bootmgr.h @@ -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 { diff --git a/BOOT/ENVIRON/INC/mm.h b/BOOT/ENVIRON/INC/mm.h index 876c7ff..59b58f5 100644 --- a/BOOT/ENVIRON/INC/mm.h +++ b/BOOT/ENVIRON/INC/mm.h @@ -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 diff --git a/BOOT/ENVIRON/LIB/EFI/efiinit.c b/BOOT/ENVIRON/LIB/EFI/efiinit.c index 4fd294e..b20900f 100644 --- a/BOOT/ENVIRON/LIB/EFI/efiinit.c +++ b/BOOT/ENVIRON/LIB/EFI/efiinit.c @@ -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; diff --git a/BOOT/ENVIRON/LIB/EFI/efimm.c b/BOOT/ENVIRON/LIB/EFI/efimm.c index 3ec6031..10c83c3 100644 --- a/BOOT/ENVIRON/LIB/EFI/efimm.c +++ b/BOOT/ENVIRON/LIB/EFI/efimm.c @@ -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; } \ No newline at end of file diff --git a/BOOT/ENVIRON/LIB/MM/mm.c b/BOOT/ENVIRON/LIB/MM/mm.c index 703f0c0..d86074a 100644 --- a/BOOT/ENVIRON/LIB/MM/mm.c +++ b/BOOT/ENVIRON/LIB/MM/mm.c @@ -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: diff --git a/BOOT/ENVIRON/LIB/MM/mmmd.c b/BOOT/ENVIRON/LIB/MM/mmmd.c index 9205983..19bc153 100644 --- a/BOOT/ENVIRON/LIB/MM/mmmd.c +++ b/BOOT/ENVIRON/LIB/MM/mmmd.c @@ -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); } diff --git a/BOOT/ENVIRON/LIB/MM/mmpa.c b/BOOT/ENVIRON/LIB/MM/mmpa.c index 10b3992..41c103a 100644 --- a/BOOT/ENVIRON/LIB/MM/mmpa.c +++ b/BOOT/ENVIRON/LIB/MM/mmpa.c @@ -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: