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 ******************************************************************/
14 /* DATA VARIABLES ************************************************************/
16 ULONG_PTR MmArchKsegBase
;
17 ULONG_PTR MmArchKsegBias
;
18 ULONG MmArchLargePageSize
;
19 BL_ADDRESS_RANGE MmArchKsegAddressRange
;
20 ULONG_PTR MmArchTopOfApplicationAddressSpace
;
21 PHYSICAL_ADDRESS Mmx86SelfMapBase
;
22 ULONG MmDeferredMappingCount
;
24 PVOID MmArchReferencePage
;
26 ULONG MmArchReferencePageSize
;
34 (*PBL_MM_RELOCATE_SELF_MAP
) (
39 (*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE
) (
40 _In_ PVOID DestinationAddress
,
41 _In_ PVOID SourceAddress
,
46 (*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE
) (
47 _In_ PVOID DestinationAddress
,
52 (*PBL_MM_DESTROY_SELF_MAP
) (
57 (*PBL_MM_FLUSH_TLB_ENTRY
) (
58 _In_ PVOID VirtualAddress
67 (*PBL_MM_UNMAP_VIRTUAL_ADDRESS
) (
68 _In_ PVOID VirtualAddress
,
73 (*PBL_MM_REMAP_VIRTUAL_ADDRESS
) (
74 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
75 _Out_ PVOID VirtualAddress
,
77 _In_ ULONG CacheAttributes
81 (*PBL_MM_MAP_PHYSICAL_ADDRESS
) (
82 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
83 _Out_ PVOID VirtualAddress
,
85 _In_ ULONG CacheAttributes
89 (*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS
) (
90 _In_ PVOID VirtualAddress
,
91 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
92 _Out_opt_ PULONG CacheAttributes
95 PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress
;
96 PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress
;
97 PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress
;
98 PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress
;
99 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
100 PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry
;
101 PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap
;
103 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap
;
104 PBL_MM_FLUSH_TLB BlMmFlushTlb
;
105 PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange
;
106 PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange
;
108 PBL_MM_FLUSH_TLB Mmx86FlushTlb
;
110 #define PTE_BASE (PVOID)0xC0000000
112 /* FUNCTIONS *****************************************************************/
124 MmDefRelocateSelfMap (
128 if (MmPteBase
!= 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 Archx86IsCpuidSupported (
235 ULONG CallerFlags
, Flags
;
237 /* Read the original flags, and add the CPUID bit */
238 CallerFlags
= __getcallerseflags() ^ 0x200000;
239 __writeeflags(CallerFlags
);
241 /* Read our flags now */
242 Flags
= __readeflags();
244 /* Check if the bit stuck */
245 return (((CallerFlags
^ Flags
) >> 21) & 1) ^ 1;
249 BlArchIsCpuIdFunctionSupported (
256 /* Check if the CPU supports this instruction */
257 Supported
= Archx86IsCpuidSupported();
263 /* Check if it's the extended function */
264 if (Function
>= 0x80000000)
266 /* Check if extended functions are supported */
267 __cpuid(CpuInfo
, 0x80000000);
268 if ((CpuInfo
[0] & 0xFFFFFF00) != 0x80000000)
276 /* It's a regular function, get the maximum one supported */
280 /* Check if our function is within bounds */
281 if (Function
<= CpuInfo
[0])
293 _In_ ULONG SubFunction
,
297 /* Use the intrinsic */
298 __cpuidex(Result
, Function
, SubFunction
);
302 BlArchGetPerformanceCounter (
308 /* Serialize with CPUID, if it exists */
309 if (Archx86IsCpuidSupported())
311 BlArchCpuId(0, 0, CpuInfo
);
319 MmDefpDestroySelfMap (
323 EfiPrintf(L
"No destroy\r\n");
327 MmDefpFlushTlbEntry (
328 _In_ PVOID VirtualAddress
332 __invlpg(VirtualAddress
);
341 __writecr3(__readcr3());
345 MmDefpUnmapVirtualAddress (
346 _In_ PVOID VirtualAddress
,
350 EfiPrintf(L
"No unmap\r\n");
351 return STATUS_NOT_IMPLEMENTED
;
355 MmDefpRemapVirtualAddress (
356 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
357 _Out_ PVOID VirtualAddress
,
359 _In_ ULONG CacheAttributes
362 EfiPrintf(L
"No remap\r\n");
363 return STATUS_NOT_IMPLEMENTED
;
367 MmDefpMapPhysicalAddress (
368 _In_ PPHYSICAL_ADDRESS PhysicalAddress
,
369 _Out_ PVOID VirtualAddress
,
371 _In_ ULONG CacheAttributes
374 EfiPrintf(L
"No map\r\n");
375 return STATUS_NOT_IMPLEMENTED
;
379 MmDefpTranslateVirtualAddress (
380 _In_ PVOID VirtualAddress
,
381 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
,
382 _Out_opt_ PULONG CacheAttributes
385 EfiPrintf(L
"No translate\r\n");
390 MmDefInitializeTranslation (
391 _In_ PBL_MEMORY_DATA MemoryData
,
392 _In_ BL_TRANSLATION_TYPE TranslationType
396 PHYSICAL_ADDRESS PhysicalAddress
;
398 /* Set the global function pointers for memory translation */
399 Mmx86TranslateVirtualAddress
= MmDefpTranslateVirtualAddress
;
400 Mmx86MapPhysicalAddress
= MmDefpMapPhysicalAddress
;
401 Mmx86UnmapVirtualAddress
= MmDefpUnmapVirtualAddress
;
402 Mmx86RemapVirtualAddress
= MmDefpRemapVirtualAddress
;
403 Mmx86FlushTlb
= MmDefpFlushTlb
;
404 Mmx86FlushTlbEntry
= MmDefpFlushTlbEntry
;
405 Mmx86DestroySelfMap
= MmDefpDestroySelfMap
;
407 /* Check what mode we're currently in */
408 if (TranslationType
== BlVirtual
)
410 EfiPrintf(L
"Virtual->Virtual not yet supported\r\n");
411 return STATUS_NOT_IMPLEMENTED
;
413 else if (TranslationType
!= BlNone
)
415 /* Not even Windows supports PAE->Virtual downgrade */
416 return STATUS_NOT_IMPLEMENTED
;
419 /* The None->Virtual case */
421 Mmx86SelfMapBase
.QuadPart
= 0;
422 MmArchReferencePage
= NULL
;
424 /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
425 EfiPrintf(L
"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
426 //Status = MmPaTruncateMemory(0x100000);
427 Status
= STATUS_SUCCESS
;
428 if (!NT_SUCCESS(Status
))
433 /* Allocate a page directory */
434 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
435 BlLoaderPageDirectory
,
439 &MmMdlUnmappedAllocated
,
442 if (!NT_SUCCESS(Status
))
447 /* Zero out the page directory */
448 MmPdpt
= (PVOID
)PhysicalAddress
.LowPart
;
449 RtlZeroMemory(MmPdpt
, PAGE_SIZE
);
451 /* Set the page size */
452 MmArchReferencePageSize
= PAGE_SIZE
;
454 /* Allocate the self-map page */
455 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
456 BlLoaderReferencePage
,
460 &MmMdlUnmappedAllocated
,
463 if (!NT_SUCCESS(Status
))
468 /* Set the reference page */
469 MmArchReferencePage
= (PVOID
)PhysicalAddress
.LowPart
;
472 RtlZeroMemory(MmArchReferencePage
, MmArchReferencePageSize
);
474 /* Allocate 4MB worth of self-map pages */
475 Status
= MmPaReserveSelfMapPages(&Mmx86SelfMapBase
,
476 (4 * 1024 * 1024) >> PAGE_SHIFT
,
477 (4 * 1024 * 1024) >> PAGE_SHIFT
);
478 if (!NT_SUCCESS(Status
))
484 RtlZeroMemory((PVOID
)Mmx86SelfMapBase
.LowPart
, 4 * 1024 * 1024);
486 EfiPrintf(L
"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
487 MmPdpt
, MmArchReferencePage
, Mmx86SelfMapBase
.LowPart
);
488 Status
= STATUS_NOT_IMPLEMENTED
;
490 //MmPteBase = Mmx86SelfMapBase.LowPart & 0xFFC00000;
493 /* Free reference page if we allocated it */
494 if (MmArchReferencePage
)
496 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmArchReferencePage
;
497 BlMmFreePhysicalPages(PhysicalAddress
);
500 /* Free page directory if we allocated it */
503 PhysicalAddress
.QuadPart
= (ULONG_PTR
)MmPdpt
;
504 BlMmFreePhysicalPages(PhysicalAddress
);
507 /* Free the self map if we allocated it */
508 if (Mmx86SelfMapBase
.QuadPart
)
510 MmPaReleaseSelfMapPages(Mmx86SelfMapBase
);
520 _In_ PBL_MEMORY_DATA MemoryData
,
521 _In_ BL_TRANSLATION_TYPE TranslationType
,
522 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
526 ULONGLONG IncreaseUserVa
, PerfCounter
, CpuRandom
;
529 /* For phase 2, just map deferred regions */
532 return Mmx86pMapMemoryRegions(2, MemoryData
);
535 /* What translation type are we switching to? */
536 switch (RequestedTranslationType
)
538 /* Physical memory */
541 /* Initialize everything to default/null values */
542 MmArchLargePageSize
= 1;
545 MmArchKsegAddressRange
.Minimum
= 0;
546 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
547 MmArchTopOfApplicationAddressSpace
= 0;
548 Mmx86SelfMapBase
.QuadPart
= 0;
550 /* Set stub functions */
551 BlMmRelocateSelfMap
= MmArchNullFunction
;
552 BlMmFlushTlb
= MmArchNullFunction
;
555 Status
= STATUS_SUCCESS
;
560 /* Set the large page size to 1024 pages (4MB) */
561 MmArchLargePageSize
= (4 * 1024 * 1024) / PAGE_SIZE
;
563 /* Check if /USERVA option was used */
564 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
565 BcdOSLoaderInteger_IncreaseUserVa
,
567 if (NT_SUCCESS(Status
) && (IncreaseUserVa
))
569 /* Yes -- load the kernel at 0xE0000000 instead */
570 MmArchKsegBase
= 0xE0000000;
574 /* Nope, load at the standard 2GB split */
575 MmArchKsegBase
= 0x80000000;
578 /* Check if CPUID 01h is supported */
580 if (BlArchIsCpuIdFunctionSupported(1))
583 BlArchCpuId(1, 0, CpuInfo
);
585 /* Check if RDRAND is supported */
586 if (CpuInfo
[2] & 0x40000000)
588 EfiPrintf(L
"Your CPU can do RDRAND! Good for you!\r\n");
594 PerfCounter
= BlArchGetPerformanceCounter();
596 _rotl16(PerfCounter
, 5);
598 /* Set the address range */
599 MmArchKsegAddressRange
.Minimum
= 0;
600 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
602 /* Set the KASLR bias */
603 MmArchKsegBias
= ((PerfCounter
^ CpuRandom
) & 0xFFF) << 12;
605 MmArchKsegBase
+= MmArchKsegBias
;
607 /* Set the kernel range */
608 MmArchKsegAddressRange
.Minimum
= MmArchKsegBase
;
609 MmArchKsegAddressRange
.Maximum
= (ULONGLONG
)~0;
611 /* Set the boot application top maximum */
612 MmArchTopOfApplicationAddressSpace
= 0x70000000;
614 /* Initialize virtual address space translation */
615 Status
= MmDefInitializeTranslation(MemoryData
, TranslationType
);
616 if (NT_SUCCESS(Status
))
618 /* Set stub functions */
619 BlMmRelocateSelfMap
= MmDefRelocateSelfMap
;
620 BlMmFlushTlb
= Mmx86FlushTlb
;
621 BlMmMoveVirtualAddressRange
= MmDefMoveVirtualAddressRange
;
622 BlMmZeroVirtualAddressRange
= MmDefZeroVirtualAddressRange
;
628 Status
= STATUS_NOT_SUPPORTED
;
632 Status
= STATUS_INVALID_PARAMETER
;