2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/i386/mmx86.c
5 * PURPOSE: Boot Library Memory Manager x86-Specific Code
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 #include "../../../../../ntoskrnl/include/internal/i386/mm.h"
15 /* DATA VARIABLES ************************************************************/
17 ULONG_PTR MmArchKsegBase
;
18 ULONG_PTR MmArchKsegBias
;
19 ULONG MmArchLargePageSize
;
20 BL_ADDRESS_RANGE MmArchKsegAddressRange
;
21 ULONG_PTR MmArchTopOfApplicationAddressSpace
;
22 PHYSICAL_ADDRESS Mmx86SelfMapBase
;
23 ULONG MmDeferredMappingCount
;
25 PULONG MmArchReferencePage
;
28 ULONG MmArchReferencePageSize
;
36 (*PBL_MM_RELOCATE_SELF_MAP
) (
41 (*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE
) (
42 _In_ PVOID DestinationAddress
,
43 _In_ PVOID SourceAddress
,
48 (*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE
) (
49 _In_ PVOID DestinationAddress
,
54 (*PBL_MM_DESTROY_SELF_MAP
) (
59 (*PBL_MM_FLUSH_TLB_ENTRY
) (
60 _In_ PVOID VirtualAddress
69 (*PBL_MM_UNMAP_VIRTUAL_ADDRESS
) (
70 _In_ PVOID VirtualAddress
,
75 (*PBL_MM_REMAP_VIRTUAL_ADDRESS
) (
76 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
77 _Out_ PVOID VirtualAddress
,
79 _In_ ULONG CacheAttributes
83 (*PBL_MM_MAP_PHYSICAL_ADDRESS
) (
84 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
85 _Out_ PVOID VirtualAddress
,
87 _In_ ULONG CacheAttributes
91 (*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS
) (
92 _In_ PVOID VirtualAddress
,
93 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
94 _Out_opt_ PULONG CacheAttributes
97 PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress
;
98 PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress
;
99 PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress
;
100 PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress
;
101 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
102 PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry
;
103 PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap
;
105 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap
;
106 PBL_MM_FLUSH_TLB BlMmFlushTlb
;
107 PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange
;
108 PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange
;
110 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
112 /* FUNCTIONS *****************************************************************/
124 MmDefRelocateSelfMap (
128 if (MmPteBase
!= (PVOID
)PTE_BASE
)
130 EfiPrintf(L
"Supposed to relocate CR3\r\n");
135 MmDefMoveVirtualAddressRange (
136 _In_ PVOID DestinationAddress
,
137 _In_ PVOID SourceAddress
,
141 EfiPrintf(L
"Supposed to move shit\r\n");
142 return STATUS_NOT_IMPLEMENTED
;
146 MmDefZeroVirtualAddressRange (
147 _In_ PVOID DestinationAddress
,
151 EfiPrintf(L
"Supposed to zero shit\r\n");
152 return STATUS_NOT_IMPLEMENTED
;
156 Mmx86pMapMemoryRegions (
158 _In_ PBL_MEMORY_DATA MemoryData
163 /* In phase 1 we don't initialize deferred mappings*/
170 /* Don't do anything if there's nothing to initialize */
171 if (!MmDeferredMappingCount
)
173 return STATUS_SUCCESS
;
181 EfiPrintf(L
"Deferred todo\r\n");
184 EfiPrintf(L
"Phase 1 TODO\r\n");
185 return STATUS_NOT_IMPLEMENTED
;
189 MmArchTranslateVirtualAddress (
190 _In_ PVOID VirtualAddress
,
191 _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress
,
192 _Out_opt_ PULONG CachingFlags
195 PBL_MEMORY_DESCRIPTOR Descriptor
;
197 /* Check if paging is on */
198 if ((CurrentExecutionContext
) &&
199 (CurrentExecutionContext
->ContextFlags
& BL_CONTEXT_PAGING_ON
))
201 /* Yes -- we have to translate this from virtual */
202 return Mmx86TranslateVirtualAddress(VirtualAddress
,
207 /* Look in all descriptors except truncated and firmware ones */
208 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_NO_FIRMWARE_MEMORY
&
209 ~BL_MM_INCLUDE_TRUNCATED_MEMORY
,
210 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
211 (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
);
213 /* Return the virtual address as the physical address */
216 PhysicalAddress
->HighPart
= 0;
217 PhysicalAddress
->LowPart
= (ULONG_PTR
)VirtualAddress
;
220 /* There's no caching on physical memory */
226 /* Success is if we found a descriptor */
227 return Descriptor
!= NULL
;
231 MmDefpDestroySelfMap (
235 EfiPrintf(L
"No destroy\r\n");
239 MmDefpFlushTlbEntry (
240 _In_ PVOID VirtualAddress
244 __invlpg(VirtualAddress
);
253 __writecr3(__readcr3());
257 MmDefpUnmapVirtualAddress (
258 _In_ PVOID VirtualAddress
,
262 EfiPrintf(L
"No unmap\r\n");
263 return STATUS_NOT_IMPLEMENTED
;
267 MmDefpRemapVirtualAddress (
268 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
269 _Out_ PVOID VirtualAddress
,
271 _In_ ULONG CacheAttributes
274 EfiPrintf(L
"No remap\r\n");
275 return STATUS_NOT_IMPLEMENTED
;
279 MmDefpMapPhysicalAddress (
280 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
281 _Out_ PVOID VirtualAddress
,
283 _In_ ULONG CacheAttributes
286 EfiPrintf(L
"No map\r\n");
287 return STATUS_NOT_IMPLEMENTED
;
291 MmDefpTranslateVirtualAddress (
292 _In_ PVOID VirtualAddress
,
293 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
294 _Out_opt_ PULONG CacheAttributes
297 EfiPrintf(L
"No translate\r\n");
302 Mmx86MapInitStructure (
303 _In_ PVOID VirtualAddress
,
305 _In_ PHYSICAL_ADDRESS PhysicalAddress
310 /* Make a virtual mapping for this physical address */
311 Status
= MmMapPhysicalAddress(&PhysicalAddress
, &VirtualAddress
, &Size
, 0);
312 if (!NT_SUCCESS(Status
))
317 /* Nothing else to do if we're not in paging mode */
318 if (MmTranslationType
== BlNone
)
320 return STATUS_SUCCESS
;
323 /* Otherwise, remove this region from the list of free virtual ranges */
324 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
325 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
326 (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
,
329 if (!NT_SUCCESS(Status
))
331 /* Unmap the address if that failed */
332 MmUnmapVirtualAddress(&VirtualAddress
, &Size
);
335 /* Return back to caller */
340 Mmx86InitializeMemoryMap (
342 _In_ PBL_MEMORY_DATA MemoryData
347 KDESCRIPTOR Gdt
, Idt
;
349 PHYSICAL_ADDRESS PhysicalAddress
;
351 /* If this is phase 2, map the memory regions */
354 return Mmx86pMapMemoryRegions(Phase
, MemoryData
);
357 /* Get the application image base/size */
358 Status
= BlGetApplicationBaseAndSize(&ImageBase
, &ImageSize
);
359 if (!NT_SUCCESS(Status
))
364 /* Map the image back at the same place */
365 PhysicalAddress
.QuadPart
= (ULONG_PTR
)ImageBase
;
366 Status
= Mmx86MapInitStructure(ImageBase
, ImageSize
, PhysicalAddress
);
367 if (!NT_SUCCESS(Status
))
372 /* Map the first 4MB of memory */
373 PhysicalAddress
.QuadPart
= 0;
374 Status
= Mmx86MapInitStructure(NULL
, 4 * 1024 * 1024, PhysicalAddress
);
375 if (!NT_SUCCESS(Status
))
382 PhysicalAddress
.QuadPart
= Gdt
.Base
;
383 Status
= Mmx86MapInitStructure((PVOID
)Gdt
.Base
, Gdt
.Limit
+ 1, PhysicalAddress
);
384 if (!NT_SUCCESS(Status
))
391 PhysicalAddress
.QuadPart
= Idt
.Base
;
392 Status
= Mmx86MapInitStructure((PVOID
)Idt
.Base
, Idt
.Limit
+ 1, PhysicalAddress
);
393 if (!NT_SUCCESS(Status
))
398 /* Map the reference page */
399 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
400 Status
= Mmx86MapInitStructure(MmArchReferencePage
,
401 MmArchReferencePageSize
,
403 if (!NT_SUCCESS(Status
))
409 EfiPrintf(L
"VM more work\r\n");
410 return STATUS_NOT_IMPLEMENTED
;
414 MmDefInitializeTranslation (
415 _In_ PBL_MEMORY_DATA MemoryData
,
416 _In_ BL_TRANSLATION_TYPE TranslationType
420 PHYSICAL_ADDRESS PhysicalAddress
;
423 /* Set the global function pointers for memory translation */
424 Mmx86TranslateVirtualAddress
= MmDefpTranslateVirtualAddress
;
425 Mmx86MapPhysicalAddress
= MmDefpMapPhysicalAddress
;
426 Mmx86UnmapVirtualAddress
= MmDefpUnmapVirtualAddress
;
427 Mmx86RemapVirtualAddress
= MmDefpRemapVirtualAddress
;
428 Mmx86FlushTlb
= MmDefpFlushTlb
;
429 Mmx86FlushTlbEntry
= MmDefpFlushTlbEntry
;
430 Mmx86DestroySelfMap
= MmDefpDestroySelfMap
;
432 /* Check what mode we're currently in */
433 if (TranslationType
== BlVirtual
)
435 EfiPrintf(L
"Virtual->Virtual not yet supported\r\n");
436 return STATUS_NOT_IMPLEMENTED
;
438 else if (TranslationType
!= BlNone
)
440 /* Not even Windows supports PAE->Virtual downgrade */
441 return STATUS_NOT_IMPLEMENTED
;
444 /* The None->Virtual case */
446 Mmx86SelfMapBase
.QuadPart
= 0;
447 MmArchReferencePage
= NULL
;
449 /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
450 EfiPrintf(L
"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
451 //Status = MmPaTruncateMemory(0x100000);
452 Status
= STATUS_SUCCESS
;
453 if (!NT_SUCCESS(Status
))
458 /* Allocate a page directory */
459 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
460 BlLoaderPageDirectory
,
464 &MmMdlUnmappedAllocated
,
467 if (!NT_SUCCESS(Status
))
472 /* Zero out the page directory */
473 MmPdpt
= (PVOID
)PhysicalAddress
.LowPart
;
474 RtlZeroMemory(MmPdpt
, PAGE_SIZE
);
476 /* Set the page size */
477 MmArchReferencePageSize
= PAGE_SIZE
;
479 /* Allocate the self-map page */
480 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
481 BlLoaderReferencePage
,
485 &MmMdlUnmappedAllocated
,
488 if (!NT_SUCCESS(Status
))
493 /* Set the reference page */
494 MmArchReferencePage
= (PVOID
)PhysicalAddress
.LowPart
;
497 RtlZeroMemory(MmArchReferencePage
, MmArchReferencePageSize
);
499 /* Allocate 4MB worth of self-map pages */
500 Status
= MmPaReserveSelfMapPages(&Mmx86SelfMapBase
,
501 (4 * 1024 * 1024) >> PAGE_SHIFT
,
502 (4 * 1024 * 1024) >> PAGE_SHIFT
);
503 if (!NT_SUCCESS(Status
))
509 RtlZeroMemory((PVOID
)Mmx86SelfMapBase
.LowPart
, 4 * 1024 * 1024);
510 EfiPrintf(L
"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
511 MmPdpt
, MmArchReferencePage
, Mmx86SelfMapBase
.LowPart
);
513 /* Align PTE base to 4MB region */
514 MmPteBase
= (PVOID
)(Mmx86SelfMapBase
.LowPart
& ~0x3FFFFF);
516 /* The PDE is the PTE of the PTE base */
517 MmPdeBase
= MiAddressToPte(MmPteBase
);
518 PdeIndex
= MiGetPdeOffset(MmPdeBase
);
519 MmPdpt
[PdeIndex
].u
.Hard
.Valid
= 1;
520 MmPdpt
[PdeIndex
].u
.Hard
.Write
= 1;
521 MmPdpt
[PdeIndex
].u
.Hard
.PageFrameNumber
= (ULONG_PTR
)MmPdpt
>> PAGE_SHIFT
;
522 MmArchReferencePage
[PdeIndex
]++;
524 /* Remove PTE_BASE from free virtual memory */
525 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
526 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
527 PTE_BASE
>> PAGE_SHIFT
,
528 (4 * 1024 * 1024) >> PAGE_SHIFT
,
530 if (!NT_SUCCESS(Status
))
535 /* Remove HAL_HEAP from free virtual memory */
536 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
537 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
538 MM_HAL_VA_START
>> PAGE_SHIFT
,
539 (4 * 1024 * 1024) >> PAGE_SHIFT
,
541 if (!NT_SUCCESS(Status
))
546 /* Initialize the virtual->physical memory mappings */
547 Status
= Mmx86InitializeMemoryMap(1, MemoryData
);
548 if (!NT_SUCCESS(Status
))
553 EfiPrintf(L
"Ready to turn on motherfucking paging, brah!\r\n");
554 Status
= STATUS_NOT_IMPLEMENTED
;
557 /* Free reference page if we allocated it */
558 if (MmArchReferencePage
)
560 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
561 BlMmFreePhysicalPages(PhysicalAddress
);
564 /* Free page directory if we allocated it */
567 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmPdpt
;
568 BlMmFreePhysicalPages(PhysicalAddress
);
571 /* Free the self map if we allocated it */
572 if (Mmx86SelfMapBase
.QuadPart
)
574 MmPaReleaseSelfMapPages(Mmx86SelfMapBase
);
584 _In_ PBL_MEMORY_DATA MemoryData
,
585 _In_ BL_TRANSLATION_TYPE TranslationType
,
586 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
590 ULONGLONG IncreaseUserVa
, PerfCounter
, CpuRandom
;
593 /* For phase 2, just map deferred regions */
596 return Mmx86pMapMemoryRegions(2, MemoryData
);
599 /* What translation type are we switching to? */
600 switch (RequestedTranslationType
)
602 /* Physical memory */
605 /* Initialize everything to default/null values */
606 MmArchLargePageSize
= 1;
609 MmArchKsegAddressRange
.Minimum
= 0;
610 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
611 MmArchTopOfApplicationAddressSpace
= 0;
612 Mmx86SelfMapBase
.QuadPart
= 0;
614 /* Set stub functions */
615 BlMmRelocateSelfMap
= MmArchNullFunction
;
616 BlMmFlushTlb
= MmArchNullFunction
;
619 Status
= STATUS_SUCCESS
;
624 /* Set the large page size to 1024 pages (4MB) */
625 MmArchLargePageSize
= (4 * 1024 * 1024) / PAGE_SIZE
;
627 /* Check if /USERVA option was used */
628 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
629 BcdOSLoaderInteger_IncreaseUserVa
,
631 if (NT_SUCCESS(Status
) && (IncreaseUserVa
))
633 /* Yes -- load the kernel at 0xE0000000 instead */
634 MmArchKsegBase
= 0xE0000000;
638 /* Nope, load at the standard 2GB split */
639 MmArchKsegBase
= 0x80000000;
642 /* Check if CPUID 01h is supported */
644 if (BlArchIsCpuIdFunctionSupported(1))
647 BlArchCpuId(1, 0, CpuInfo
);
649 /* Check if RDRAND is supported */
650 if (CpuInfo
[2] & 0x40000000)
652 EfiPrintf(L
"Your CPU can do RDRAND! Good for you!\r\n");
658 PerfCounter
= BlArchGetPerformanceCounter();
660 _rotl16(PerfCounter
, 5);
662 /* Set the address range */
663 MmArchKsegAddressRange
.Minimum
= 0;
664 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
666 /* Set the KASLR bias */
667 MmArchKsegBias
= ((PerfCounter
^ CpuRandom
) & 0xFFF) << 12;
669 MmArchKsegBase
+= MmArchKsegBias
;
671 /* Set the kernel range */
672 MmArchKsegAddressRange
.Minimum
= MmArchKsegBase
;
673 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
675 /* Set the boot application top maximum */
676 MmArchTopOfApplicationAddressSpace
= 0x70000000;
678 /* Initialize virtual address space translation */
679 Status
= MmDefInitializeTranslation(MemoryData
, TranslationType
);
680 if (NT_SUCCESS(Status
))
682 /* Set stub functions */
683 BlMmRelocateSelfMap
= MmDefRelocateSelfMap
;
684 BlMmFlushTlb
= Mmx86FlushTlb
;
685 BlMmMoveVirtualAddressRange
= MmDefMoveVirtualAddressRange
;
686 BlMmZeroVirtualAddressRange
= MmDefZeroVirtualAddressRange
;
692 Status
= STATUS_NOT_SUPPORTED
;
696 Status
= STATUS_INVALID_PARAMETER
;