2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/mm.c
5 * PURPOSE: Boot Library Memory Manager Core
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 /* DATA VARIABLES ************************************************************/
16 /* This is a bug in Windows, but is required for MmTrInitialize to load */
17 BL_TRANSLATION_TYPE MmTranslationType
= BlMax
;
18 BL_TRANSLATION_TYPE MmOriginalTranslationType
;
19 ULONG MmDescriptorCallTreeCount
;
21 /* FUNCTIONS *****************************************************************/
24 TrpGenerateMappingTracker (
25 _In_ PVOID VirtualAddress
,
27 _In_ LARGE_INTEGER PhysicalAddress
,
31 PBL_MEMORY_DESCRIPTOR Descriptor
, NextDescriptor
;
32 PLIST_ENTRY ListHead
, NextEntry
;
34 /* Increment descriptor call count */
35 MmDescriptorCallTreeCount
++;
37 /* Initialize a descriptor for this allocation */
38 Descriptor
= MmMdInitByteGranularDescriptor(Flags
,
40 PhysicalAddress
.QuadPart
,
41 (ULONG_PTR
)VirtualAddress
,
44 /* Loop the current tracker list */
45 ListHead
= MmMdlMappingTrackers
.First
;
46 NextEntry
= ListHead
->Flink
;
47 if (IsListEmpty(ListHead
))
49 /* If it's empty, just add the descriptor at the end */
50 InsertTailList(ListHead
, &Descriptor
->ListEntry
);
54 /* Otherwise, go to the last descriptor */
55 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
58 while (NextDescriptor
->VirtualPage
< Descriptor
->VirtualPage
)
61 NextEntry
= NextEntry
->Flink
;
62 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
66 /* If we hit the end of the list, just add it at the end */
67 if (NextEntry
== ListHead
)
72 /* Otherwise, add it right after this descriptor */
73 InsertTailList(&NextDescriptor
->ListEntry
, &Descriptor
->ListEntry
);
77 /* Release any global descriptors allocated */
78 MmMdFreeGlobalDescriptors();
79 --MmDescriptorCallTreeCount
;
80 return STATUS_SUCCESS
;
88 PBL_MEMORY_DESCRIPTOR Descriptor
;
90 PLIST_ENTRY NextEntry
;
92 /* Nothing to track if we're using physical memory */
93 if (MmTranslationType
== BlNone
)
95 return STATUS_SUCCESS
;
98 /* Initialize all the virtual lists */
99 MmMdInitializeListHead(&MmMdlMappingTrackers
);
100 MmMdlMappingTrackers
.Type
= BlMdTracker
;
101 MmMdInitializeListHead(&MmMdlFreeVirtual
);
102 MmMdlFreeVirtual
.Type
= BlMdVirtual
;
104 /* Initialize a 4GB free descriptor */
105 Descriptor
= MmMdInitByteGranularDescriptor(0,
106 BlConventionalMemory
,
109 ((ULONGLONG
)4 * 1024 * 1024 * 1024) >>
113 Status
= STATUS_NO_MEMORY
;
117 /* Add this 4GB region to the free virtual address space list */
118 Status
= MmMdAddDescriptorToList(&MmMdlFreeVirtual
,
120 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
);
121 if (!NT_SUCCESS(Status
))
123 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
127 /* Remove any reserved regions of virtual address space */
128 NextEntry
= MmMdlReservedAllocated
.First
->Flink
;
129 while (NextEntry
!= MmMdlReservedAllocated
.First
)
131 /* Grab the descriptor and see if it's mapped */
132 Descriptor
= CONTAINING_RECORD(NextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
133 if (Descriptor
->VirtualPage
)
135 EfiPrintf(L
"Need to handle reserved allocation: %llx %llx\r\n",
136 Descriptor
->VirtualPage
, Descriptor
->PageCount
);
138 Status
= STATUS_NOT_IMPLEMENTED
;
143 NextEntry
= NextEntry
->Flink
;
146 /* Set success if we made it */
147 Status
= STATUS_SUCCESS
;
150 /* Return back to caller */
155 BlMmRemoveBadMemory (
162 ULONGLONG BadPageCount
;
164 /* First check if bad memory access is allowed */
166 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
167 BcdLibraryBoolean_AllowBadMemoryAccess
,
169 if ((NT_SUCCESS(Status
)) && (AllowBad
))
171 /* No point checking the list if it is */
172 return STATUS_SUCCESS
;
175 /* Otherwise, check if there's a persisted bad page list */
176 Status
= BlpGetBootOptionIntegerList(BlpApplicationEntry
.BcdData
,
177 BcdLibraryIntegerList_BadMemoryList
,
181 if (NT_SUCCESS(Status
))
183 EfiPrintf(L
"Persistent bad page list not supported\r\n");
184 return STATUS_NOT_IMPLEMENTED
;
188 return STATUS_SUCCESS
;
192 BlMmMapPhysicalAddressEx (
193 _In_ PVOID
* VirtualAddress
,
196 _In_ PHYSICAL_ADDRESS PhysicalAddress
200 PVOID MappingAddress
;
201 PHYSICAL_ADDRESS MappedAddress
;
204 UCHAR CacheAttributes
;
205 ULONGLONG BasePage
, EndPage
, MappedPage
, FoundBasePage
;
206 ULONGLONG PageOffset
, FoundPageCount
;
207 PBL_MEMORY_DESCRIPTOR Descriptor
, NewDescriptor
;
208 PBL_MEMORY_DESCRIPTOR_LIST List
;
211 /* Increase call depth */
212 ++MmDescriptorCallTreeCount
;
214 /* Check if any parameters are missing */
215 if (!(VirtualAddress
) || !(Size
))
217 Status
= STATUS_INVALID_PARAMETER
;
221 /* Check for fixed allocation without an actual address */
222 if ((Flags
& BlMemoryFixed
) &&
223 (PhysicalAddress
.QuadPart
== -1) &&
226 Status
= STATUS_INVALID_PARAMETER
;
230 /* Check for invalid requirement flag, if one is present */
231 if (((Flags
& BlMemoryValidAllocationAttributes
) != BlMemoryFixed
) &&
232 ((Flags
& BlMemoryValidAllocationAttributes
) != BlMemoryKernelRange
) &&
233 (Flags
& BlMemoryValidAllocationAttributes
))
235 Status
= STATUS_INVALID_PARAMETER
;
239 /* Check for invalid cache attribute flags */
240 if (((Flags
& BlMemoryValidCacheAttributeMask
) - 1) &
241 (Flags
& BlMemoryValidCacheAttributeMask
))
243 Status
= STATUS_INVALID_PARAMETER
;
247 /* Select an address to map this at */
248 Status
= MmSelectMappingAddress(&MappingAddress
,
251 Flags
& BlMemoryValidAllocationAttributes
,
254 if (!NT_SUCCESS(Status
))
259 /* Map the selected address, using the appropriate caching attributes */
260 MappedAddress
= PhysicalAddress
;
262 CacheAttributes
= ((Flags
& BlMemoryValidCacheAttributeMask
) != 0x20) ?
263 (Flags
& BlMemoryValidCacheAttributeMask
) : 0;
264 Status
= MmMapPhysicalAddress(&MappedAddress
,
268 if (!NT_SUCCESS(Status
))
273 /* Compute the final address where the mapping was made */
274 MappedBase
= (PVOID
)(ULONG_PTR
)((ULONG_PTR
)MappingAddress
+
275 PhysicalAddress
.QuadPart
-
276 MappedAddress
.QuadPart
);
277 MappedAddress
.QuadPart
= (ULONG_PTR
)MappedBase
;
279 /* Check if we're in physical or virtual mode */
280 if (MmTranslationType
== BlNone
)
282 /* We are in physical mode -- just return this address directly */
283 Status
= STATUS_SUCCESS
;
284 *VirtualAddress
= MappedBase
;
288 /* Remove the mapping address from the list of free virtual memory */
289 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
290 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
291 (ULONG_PTR
)MappingAddress
>> PAGE_SHIFT
,
292 MapSize
>> PAGE_SHIFT
,
294 if (NT_SUCCESS(Status
))
296 /* And then add an entry for the fact we mapped it */
297 Status
= TrpGenerateMappingTracker(MappedBase
,
303 /* Abandon if we didn't update the memory map successfully */
304 if (!NT_SUCCESS(Status
))
306 /* Unmap the virtual address so it can be used later */
307 MmUnmapVirtualAddress(MappingAddress
, &MapSize
);
311 /* Check if no real mapping into RAM was made */
312 if (PhysicalAddress
.QuadPart
== -1)
314 /* Then we're done here */
315 Status
= STATUS_SUCCESS
;
316 *VirtualAddress
= MappedBase
;
321 /* Loop over the entire allocation */
322 BasePage
= MappedAddress
.QuadPart
>> PAGE_SHIFT
;
323 EndPage
= (MappedAddress
.QuadPart
+ MapSize
) >> PAGE_SHIFT
;
324 MappedPage
= (ULONG_PTR
)MappingAddress
>> PAGE_SHIFT
;
327 /* Start with the unmapped allocated list */
328 List
= &MmMdlUnmappedAllocated
;
329 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_ALLOCATED
,
330 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
334 /* Try persistent next */
335 List
= &MmMdlPersistentMemory
;
336 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_PERSISTENT_MEMORY
,
337 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
342 /* Try unmapped, unallocated, next */
343 List
= &MmMdlUnmappedUnallocated
;
344 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED
,
345 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
350 /* Try reserved next */
351 List
= &MmMdlReservedAllocated
;
352 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_RESERVED_ALLOCATED
,
353 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
357 /* Check if we have a descriptor */
360 /* Remove it from its list */
361 MmMdRemoveDescriptorFromList(List
, Descriptor
);
363 /* Check if it starts before our allocation */
364 FoundBasePage
= Descriptor
->BasePage
;
365 if (FoundBasePage
< BasePage
)
367 /* Create a new descriptor to cover the gap before our allocation */
368 PageOffset
= BasePage
- FoundBasePage
;
369 NewDescriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
376 MmMdAddDescriptorToList(List
, NewDescriptor
, 0);
378 /* Adjust ours to ignore that piece */
379 Descriptor
->PageCount
-= PageOffset
;
380 Descriptor
->BasePage
= BasePage
;
383 /* Check if it goes beyond our allocation */
384 FoundPageCount
= Descriptor
->PageCount
;
385 if (EndPage
< (FoundPageCount
+ Descriptor
->BasePage
))
387 /* Create a new descriptor to cover the range after our allocation */
388 PageOffset
= EndPage
- BasePage
;
389 NewDescriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
397 MmMdAddDescriptorToList(List
, NewDescriptor
, 0);
399 /* Adjust ours to ignore that piece */
400 Descriptor
->PageCount
= PageOffset
;
403 /* Update the descriptor to be mapepd at this virtual page */
404 Descriptor
->VirtualPage
= MappedPage
;
406 /* Check if this was one of the regular lists */
407 if ((List
!= &MmMdlReservedAllocated
) &&
408 (List
!= &MmMdlPersistentMemory
))
410 /* Was it allocated, or unallocated? */
411 if (List
!= &MmMdlUnmappedAllocated
)
413 /* In which case use the unallocated mapped list */
414 List
= &MmMdlMappedUnallocated
;
418 /* Insert it into the mapped list */
419 List
= &MmMdlMappedAllocated
;
423 /* Add the descriptor that was removed, into the right list */
424 MmMdAddDescriptorToList(List
, Descriptor
, 0);
426 /* Add the pages this descriptor had */
427 AddPages
= Descriptor
->PageCount
;
431 /* Nope, so just add one page */
435 /* Increment the number of pages the descriptor had */
436 MappedPage
+= AddPages
;
437 BasePage
+= AddPages
;
439 while (BasePage
< EndPage
);
441 /* We're done -- returned the address */
442 Status
= STATUS_SUCCESS
;
443 *VirtualAddress
= MappedBase
;
446 /* Cleanup descriptors and reduce depth */
447 MmMdFreeGlobalDescriptors();
448 --MmDescriptorCallTreeCount
;
453 MmUnmapVirtualAddress (
454 _Inout_ PVOID
* VirtualAddress
,
455 _Inout_ PULONGLONG Size
460 /* Make sure parameters were passed in and are valid */
461 if ((VirtualAddress
) && (Size
) && (*Size
<= 0xFFFFFFFF))
463 /* Nothing to do if translation isn't active */
464 if (MmTranslationType
== BlNone
)
466 Status
= STATUS_SUCCESS
;
470 /* We don't support virtual memory yet @TODO */
471 EfiPrintf(L
"unmap not yet implemented in %S\r\n", __FUNCTION__
);
473 Status
= STATUS_NOT_IMPLEMENTED
;
479 Status
= STATUS_INVALID_PARAMETER
;
487 BlMmUnmapVirtualAddressEx (
488 _In_ PVOID VirtualAddress
,
494 /* Increment call depth */
495 ++MmDescriptorCallTreeCount
;
497 /* Make sure all parameters are there */
498 if ((VirtualAddress
) && (Size
))
500 /* Unmap the virtual address */
501 Status
= MmUnmapVirtualAddress(&VirtualAddress
, &Size
);
503 /* Check if we actually had a virtual mapping active */
504 if ((NT_SUCCESS(Status
)) && (MmTranslationType
!= BlNone
))
506 /* We don't support virtual memory yet @TODO */
507 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
509 Status
= STATUS_NOT_IMPLEMENTED
;
515 Status
= STATUS_INVALID_PARAMETER
;
518 /* Cleanup descriptors and reduce depth */
519 MmMdFreeGlobalDescriptors();
520 --MmDescriptorCallTreeCount
;
525 BlMmTranslateVirtualAddress (
526 _In_ PVOID VirtualAddress
,
527 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
530 /* Make sure arguments are present */
531 if (!(VirtualAddress
) || !(PhysicalAddress
))
536 /* Do the architecture-specific translation */
537 return MmArchTranslateVirtualAddress(VirtualAddress
, PhysicalAddress
, NULL
);
542 _In_ PBL_MEMORY_DATA MemoryData
,
543 _In_ BL_TRANSLATION_TYPE TranslationType
,
544 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
549 /* Take a reference */
550 MmDescriptorCallTreeCount
= 1;
552 /* Only support valid translation types */
553 if ((TranslationType
> BlPae
) || (LibraryParameters
->TranslationType
> BlPae
))
556 EfiPrintf(L
"Invalid translation types present\r\n");
557 Status
= STATUS_INVALID_PARAMETER
;
561 /* Initialize memory descriptors */
562 MmMdInitialize(0, LibraryParameters
);
564 /* Remember the page type we came in with */
565 MmOriginalTranslationType
= TranslationType
;
567 /* Initialize the physical page allocator */
568 Status
= MmPaInitialize(MemoryData
,
569 LibraryParameters
->MinimumAllocationCount
);
570 if (!NT_SUCCESS(Status
))
575 /* Initialize the memory tracker */
576 Status
= MmTrInitialize();
577 if (!NT_SUCCESS(Status
))
579 EfiPrintf(L
"TR Mm init failed: %lx\r\n", Status
);
585 /* Initialize paging, large pages, self-mapping, PAE, if needed */
586 Status
= MmArchInitialize(1,
589 LibraryParameters
->TranslationType
);
590 if (NT_SUCCESS(Status
))
592 /* Save the newly active transation type */
593 MmTranslationType
= LibraryParameters
->TranslationType
;
595 /* Initialize the heap allocator now */
596 Status
= MmHaInitialize(LibraryParameters
->MinimumHeapSize
,
597 LibraryParameters
->HeapAllocationAttributes
);
600 /* If Phase 1 init failed, bail out */
601 if (!NT_SUCCESS(Status
))
603 /* Kill everything set setup so far */
604 EfiPrintf(L
"Phase 1 Mm init failed: %lx\r\n", Status
);
612 /* Do we have too many descriptors? */
613 if (LibraryParameters
->DescriptorCount
> 512)
615 /* Switch to using a dynamic buffer instead */
616 EfiPrintf(L
"Warning: too many descriptors\r\n");
617 Status
= STATUS_NOT_IMPLEMENTED
;
619 //MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
622 /* Remove memory that the BCD says is bad */
623 BlMmRemoveBadMemory();
625 /* Now map all the memory regions as needed */
626 Status
= MmArchInitialize(2,
629 LibraryParameters
->TranslationType
);
630 if (NT_SUCCESS(Status
))
632 /* Initialize the block allocator */
633 Status
= MmBaInitialize();
636 /* Check if anything in phase 2 failed */
637 if (!NT_SUCCESS(Status
))
639 /* Go back to static descriptors and kill the heap */
640 EfiPrintf(L
"Phase 2 Mm init failed: %lx\r\n", Status
);
641 //MmMdpSwitchToStaticDescriptors();
642 //HapInitializationStatus = 0;
643 //++MmDescriptorCallTreeCount;
645 /* Destroy the Phase 1 initialization */
653 /* Free the memory descriptors and return the initialization state */
654 MmMdFreeGlobalDescriptors();
655 --MmDescriptorCallTreeCount
;