Compare commits

..

4 Commits

Author SHA1 Message Date
2a19fd42de [BOOT] Improve debug logging 2024-09-01 17:54:40 -04:00
43c6c75710 [BOOT:MM] Fix descriptor memory leaks
Sometimes when handling MmMdAddDescriptorToList() errors, descriptors
were not freed with MmMdFreeDescriptor().
2024-09-01 16:56:18 -04:00
65e33fdad5 [BOOT:MM] Finish MmMdRemoveRegionFromMdlEx() 2024-09-01 16:49:19 -04:00
3aae765c9c [BOOT:MM] Implement MmMdFindDescriptorFromMdl() 2024-09-01 12:41:08 -04:00
5 changed files with 203 additions and 85 deletions

View File

@ -20,6 +20,7 @@ Abstract:
#define MDL_OPERATION_FLAGS_TRUNCATE 0x00000002 #define MDL_OPERATION_FLAGS_TRUNCATE 0x00000002
#define MDL_OPERATION_FLAGS_PHYSICAL 0x40000000 #define MDL_OPERATION_FLAGS_PHYSICAL 0x40000000
#define MDL_OPERATION_FLAGS_VIRTUAL 0x80000000
NTSTATUS NTSTATUS
MmFwGetMemoryMap ( MmFwGetMemoryMap (

View File

@ -421,6 +421,7 @@ Return Value:
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE); Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;
} }
@ -456,6 +457,7 @@ Return Value:
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE); Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;
} }
@ -486,6 +488,7 @@ Return Value:
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE); Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;
} }
} }
@ -507,6 +510,7 @@ Return Value:
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE); Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;
} }
@ -568,6 +572,7 @@ Return Value:
Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE); Status = MmMdAddDescriptorToList(Mdl, NtDescriptor, MDL_OPERATION_FLAGS_TRUNCATE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;
} }
} }
@ -611,7 +616,7 @@ Return Value:
// //
// Remove the current descriptor. // Remove the current descriptor.
// //
Status = MmMdRemoveRegionFromMdlEx(Mdl, NtStartPage, NtPageCount, MDL_OPERATION_FLAGS_PHYSICAL, 0); Status = MmMdRemoveRegionFromMdlEx(Mdl, NtStartPage, NtPageCount, MDL_OPERATION_FLAGS_PHYSICAL, NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NtDescriptor); MmMdFreeDescriptor(NtDescriptor);
goto exit; goto exit;

View File

@ -152,6 +152,7 @@ Return Value:
--*/ --*/
{ {
NTSTATUS Status;
PMEMORY_DESCRIPTOR PrevDescriptor, NextDescriptor, NewDescriptor; PMEMORY_DESCRIPTOR PrevDescriptor, NextDescriptor, NewDescriptor;
ULONGLONG DescriptorEnd, PrevDescriptorEnd, NextDescriptorEnd; ULONGLONG DescriptorEnd, PrevDescriptorEnd, NextDescriptorEnd;
ULONGLONG MappedFirstPage; ULONGLONG MappedFirstPage;
@ -186,7 +187,10 @@ Return Value:
PrevDescriptor->Type PrevDescriptor->Type
); );
if (NewDescriptor != NULL) { if (NewDescriptor != NULL) {
MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags); Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NewDescriptor);
}
} }
} }
@ -242,7 +246,10 @@ Return Value:
Descriptor->Type Descriptor->Type
); );
if (NewDescriptor != NULL) { if (NewDescriptor != NULL) {
MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags); Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NewDescriptor);
}
} }
} }
@ -310,6 +317,7 @@ Return Value:
PMEMORY_DESCRIPTOR CurrentDescriptor; PMEMORY_DESCRIPTOR CurrentDescriptor;
if (Mdl == NULL || Descriptor == NULL) { if (Mdl == NULL || Descriptor == NULL) {
DebugPrint(L"MmMdAddDescriptorToList(): Mdl and/or Descriptor are NULL\r\n");
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
@ -454,9 +462,61 @@ Return Value:
{ {
BOOLEAN Mapped;
PMEMORY_DESCRIPTOR Descriptor;
PLIST_ENTRY ListEntry;
ULONGLONG FirstPage;
Mapped = FALSE;
if (Flags & MDL_OPERATION_FLAGS_VIRTUAL) {
if (Mdl->Type == MDL_TYPE_PHYSICAL) {
Mapped = TRUE;
}
} else {
//
// If the MDL is virtual, the
// virtual flag must be set.
//
if (Mdl->Type == MDL_TYPE_VIRTUAL) {
DebugPrint(L"MmMdFindDescriptorFromMdl(): Flags is invalid\r\n");
return NULL;
}
}
// //
// TODO: Implement this routine. // Check if the cached descriptor is in range.
// //
if (!Mapped && Mdl->Current != NULL) {
Descriptor = (PMEMORY_DESCRIPTOR)Mdl->Current;
if (Page < Descriptor->FirstPage) {
ListEntry = Mdl->Head->Flink;
} else {
ListEntry = Mdl->Current;
}
} else {
ListEntry = Mdl->Head->Flink;
}
while (ListEntry != Mdl->Head) {
Descriptor = (PMEMORY_DESCRIPTOR)ListEntry;
if (Mapped) {
FirstPage = Descriptor->MappedFirstPage;
} else {
FirstPage = Descriptor->FirstPage;
}
//
// Check if this descriptor contains Page.
//
if ((!Mapped || FirstPage)
&& Page >= FirstPage
&& Page < FirstPage + Descriptor->PageCount) {
return Descriptor;
}
ListEntry = ListEntry->Flink;
}
return NULL; return NULL;
} }
@ -464,7 +524,7 @@ Return Value:
NTSTATUS NTSTATUS
MmMdRemoveRegionFromMdlEx ( MmMdRemoveRegionFromMdlEx (
IN PMEMORY_DESCRIPTOR_LIST Mdl, IN PMEMORY_DESCRIPTOR_LIST Mdl,
IN ULONGLONG FirstPage, IN ULONGLONG RemoveStart,
IN ULONGLONG PageCount, IN ULONGLONG PageCount,
IN ULONG Flags, IN ULONG Flags,
OUT PMEMORY_DESCRIPTOR_LIST Unused OUT PMEMORY_DESCRIPTOR_LIST Unused
@ -480,46 +540,154 @@ Arguments:
Mdl - MDL to remove the region from. Mdl - MDL to remove the region from.
FirstPage - The first page in the region. RemoveStart - The first page in the region.
PageCount - The number of pages in the region. PageCount - The number of pages in the region.
Flags - MDL_OPERATION_FLAGS_*. Flags - MDL_OPERATION_FLAGS_*.
MDL_OPERATION_FLAGS_PHYSICAL if the region is physical.
MDL_OPERATION_FLAGS_VIRTUAL if the region is virtual.
Unused - Unused. Unused - Unused.
Return Value: Return Value:
None. STATUS_SUCCESS if successful,
STATUS_INVALID_PARAMETER if Flags value is invalid.
--*/ --*/
{ {
ULONGLONG RemoveEnd, DescriptorEnd; NTSTATUS Status;
PLIST_ENTRY Entry; ULONG Offset;
PMEMORY_DESCRIPTOR Descriptor; BOOLEAN Mapped;
MEMORY_DESCRIPTOR RemovedDescriptor; ULONGLONG RemoveEnd;
PLIST_ENTRY ListEntry;
ULONGLONG DescriptorStart, DescriptorEnd;
PMEMORY_DESCRIPTOR Descriptor, NewDescriptor;
(VOID)Flags;
(VOID)Unused; (VOID)Unused;
RemoveEnd = FirstPage + PageCount; Mapped = FALSE;
Entry = Mdl->Head->Flink; if (Flags & MDL_OPERATION_FLAGS_VIRTUAL) {
while (Entry != Mdl->Head) { if (Mdl->Type == MDL_TYPE_PHYSICAL) {
Descriptor = (PMEMORY_DESCRIPTOR)Entry; Mapped = TRUE;
DescriptorEnd = Descriptor->FirstPage + Descriptor->PageCount; }
} else {
RtlCopyMemory(&RemovedDescriptor, Descriptor, sizeof(MEMORY_DESCRIPTOR)); //
// If the MDL is virtual, the
// if (FirstPage <= Descriptor->FirstPage && Descriptor->FirstPage < RemoveEnd) { // virtual flag must be set.
// } //
if (Mdl->Type == MDL_TYPE_VIRTUAL) {
DebugPrint(L"MmMdRemoveRegionFromMdlEx(): Flags is invalid\r\n");
return STATUS_INVALID_PARAMETER;
}
} }
// RemoveEnd = RemoveStart + PageCount;
// TODO: Implement the rest of this routine. ListEntry = Mdl->Head->Flink;
// while (ListEntry != Mdl->Head) {
Descriptor = (PMEMORY_DESCRIPTOR)ListEntry;
return STATUS_SUCCESS; if (Mapped) {
DescriptorStart = Descriptor->MappedFirstPage;
} else {
DescriptorStart = Descriptor->FirstPage;
}
DescriptorEnd = DescriptorStart + Descriptor->PageCount;
//
// Check if the region to be removed
// is inside the current descriptor.
//
if (RemoveStart <= DescriptorStart && RemoveEnd > DescriptorStart) {
//
// The region is around the start of the descriptor, or
// they have identical locations and sizes.
// | RemoveStart | DescriptorStart | RemoveEnd | DescriptorEnd |
// | Lower address ............................ Higher address |
//
if (RemoveEnd < DescriptorEnd) {
Offset = RemoveEnd - DescriptorStart;
} else {
Offset = DescriptorEnd - DescriptorStart;
}
//
// Shrink the descriptor.
//
Descriptor->FirstPage += Offset;
Descriptor->PageCount -= Offset;
if (Descriptor->MappedFirstPage) {
Descriptor->MappedFirstPage += Offset;
}
//
// Remove descriptor if now empty.
//
if (Descriptor->PageCount == 0) {
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
MmMdFreeDescriptor(Descriptor);
}
} else if (RemoveStart < DescriptorEnd && RemoveEnd >= DescriptorEnd) {
//
// The region is around the end of the descriptor.
// | DescriptorStart | RemoveStart | DescriptorEnd | RemoveEnd |
// | Lower address ............................ Higher address |
//
//
// Simply shrink the descriptor.
//
Descriptor->PageCount -= DescriptorEnd - RemoveStart;
} else if (RemoveStart > DescriptorStart && RemoveEnd < DescriptorEnd) {
//
// The region is completely inside the descriptor.
// In this case, the descriptor must be split in two.
// | DescriptorStart | RemoveStart | RemoveEnd | DescriptorEnd |
// | Lower address ............................ Higher address |
//
//
// Create a new descriptor before the removed region.
//
NewDescriptor = MmMdInitDescriptor(
Descriptor->FirstPage,
Descriptor->MappedFirstPage,
RemoveStart - DescriptorStart,
Descriptor->Attributes,
Descriptor->Type
);
//
// Shrink and move the current descriptor.
//
Offset = NewDescriptor->PageCount + PageCount;
Descriptor->FirstPage += Offset;
Descriptor->PageCount -= Offset;
if (Descriptor->MappedFirstPage) {
Descriptor->MappedFirstPage += Offset;
}
//
// Now check if MmMdInitDescriptor() actually worked.
//
if (NewDescriptor == NULL) {
return STATUS_NO_MEMORY;
}
Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NewDescriptor);
return Status;
}
}
ListEntry = ListEntry->Flink;
}
return Status;
} }
NTSTATUS NTSTATUS
@ -567,7 +735,7 @@ Return Value:
// Free the descriptor from the heap. // Free the descriptor from the heap.
// TODO: Use BlMmFreeHeap(). // TODO: Use BlMmFreeHeap().
// //
ConsolePrint(L"MmMdFreeDescriptor(): need BlMmFreeHeap() to free descriptor\r\n"); ConsolePrint(L"MmMdFreeDescriptor(): Heap not available\r\n");
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
// return BlMmFreeHeap(Descriptor); // return BlMmFreeHeap(Descriptor);
} }

View File

@ -139,8 +139,9 @@ Return Value:
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
} }
Status = MmMdAddDescriptorToList(&MmMdlReservedAllocated, NewDescriptor, 0x00); Status = MmMdAddDescriptorToList(&MmMdlReservedAllocated, NewDescriptor, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
MmMdFreeDescriptor(NewDescriptor);
return Status; return Status;
} }

View File

@ -105,63 +105,6 @@ Return Value:
return Status; return Status;
} }
//
// Print debug information.
// TODO: Remove this once the project is more stable?
//
#ifdef _DEBUG
DebugPrint(L"Boot device type: ");
switch (BlpBootDevice->Type) {
case BOOT_DEVICE_TYPE_PARTITION:
DebugPrint(L"partition\r\n");
BlockDevice = &BlpBootDevice->Partition.Parent;
break;
case BOOT_DEVICE_TYPE_PARTITION_EX:
DebugPrint(L"partition\r\n");
BlockDevice = &BlpBootDevice->PartitionEx.Parent;
break;
default:
DebugPrint(L"generic block device\r\n");
BlockDevice = &BlpBootDevice->Block;
break;
}
DebugPrint(L"Boot device parent type: ");
switch (BlockDevice->Type) {
case BOOT_BLOCK_DEVICE_TYPE_HARDDRIVE:
DebugPrint(L"hard drive\r\n");
break;
case BOOT_BLOCK_DEVICE_TYPE_CDROM:
DebugPrint(L"CD-ROM\r\n");
break;
case BOOT_BLOCK_DEVICE_TYPE_RAMDISK:
DebugPrint(L"RAM disk\r\n");
break;
default:
DebugPrint(L"generic block device\r\n");
break;
}
Option = &ApplicationEntry->Options;
for (ULONG Index = 0; !Option->IsInvalid; Index++) {
DebugPrintf(L"Boot entry option %x: ", Index);
if (Option->Type == BCDE_DATA_TYPE_APPLICATION_PATH) {
DebugPrint(L"application path \"");
DebugPrint((PWSTR)((PUCHAR)Option + Option->DataOffset));
DebugPrint(L"\"\r\n");
} else {
DebugPrintf(L"type %x, data size %x\r\n", Option->Type, Option->DataSize);
}
if (Option->NextOptionOffset == 0) {
break;
}
Option = (PBOOT_APPLICATION_OPTION)((PUCHAR)Option + Option->NextOptionOffset);
}
#endif
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }