[BOOT:MM] Finish MmMdRemoveRegionFromMdlEx()

This commit is contained in:
Quinn Stephens 2024-09-01 16:49:19 -04:00
parent 3aae765c9c
commit 65e33fdad5
2 changed files with 130 additions and 23 deletions

View File

@ -611,7 +611,7 @@ Return Value:
//
// 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)) {
MmMdFreeDescriptor(NtDescriptor);
goto exit;

View File

@ -515,7 +515,7 @@ Return Value:
NTSTATUS
MmMdRemoveRegionFromMdlEx (
IN PMEMORY_DESCRIPTOR_LIST Mdl,
IN ULONGLONG FirstPage,
IN ULONGLONG RemoveStart,
IN ULONGLONG PageCount,
IN ULONG Flags,
OUT PMEMORY_DESCRIPTOR_LIST Unused
@ -531,46 +531,153 @@ Arguments:
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.
Flags - MDL_OPERATION_FLAGS_*.
MDL_OPERATION_FLAGS_PHYSICAL if the region is physical.
MDL_OPERATION_FLAGS_VIRTUAL if the region is virtual.
Unused - Unused.
Return Value:
None.
STATUS_SUCCESS if successful,
STATUS_INVALID_PARAMETER if Flags value is invalid.
--*/
{
ULONGLONG RemoveEnd, DescriptorEnd;
PLIST_ENTRY Entry;
PMEMORY_DESCRIPTOR Descriptor;
MEMORY_DESCRIPTOR RemovedDescriptor;
NTSTATUS Status;
ULONG Offset;
BOOLEAN Mapped;
ULONGLONG RemoveEnd;
PLIST_ENTRY ListEntry;
ULONGLONG DescriptorStart, DescriptorEnd;
PMEMORY_DESCRIPTOR Descriptor, NewDescriptor;
(VOID)Flags;
(VOID)Unused;
RemoveEnd = FirstPage + PageCount;
Entry = Mdl->Head->Flink;
while (Entry != Mdl->Head) {
Descriptor = (PMEMORY_DESCRIPTOR)Entry;
DescriptorEnd = Descriptor->FirstPage + Descriptor->PageCount;
RtlCopyMemory(&RemovedDescriptor, Descriptor, sizeof(MEMORY_DESCRIPTOR));
// if (FirstPage <= Descriptor->FirstPage && Descriptor->FirstPage < RemoveEnd) {
// }
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) {
return STATUS_INVALID_PARAMETER;
}
}
//
// TODO: Implement the rest of this routine.
//
RemoveEnd = RemoveStart + PageCount;
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