[BOOTLIB]: Don't use __getcallerseflags() in Archx86IsCpuidSupported -- __readeflags...
[reactos.git] / reactos / boot / environ / lib / mm / i386 / mmx86.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12 #include "bcd.h"
13
14 /* DATA VARIABLES ************************************************************/
15
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;
23 PVOID MmPdpt;
24 PVOID MmArchReferencePage;
25 PVOID MmPteBase;
26 ULONG MmArchReferencePageSize;
27
28 typedef VOID
29 (*PBL_MM_FLUSH_TLB) (
30 VOID
31 );
32
33 typedef VOID
34 (*PBL_MM_RELOCATE_SELF_MAP) (
35 VOID
36 );
37
38 typedef NTSTATUS
39 (*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE) (
40 _In_ PVOID DestinationAddress,
41 _In_ PVOID SourceAddress,
42 _In_ ULONGLONG Size
43 );
44
45 typedef NTSTATUS
46 (*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE) (
47 _In_ PVOID DestinationAddress,
48 _In_ ULONGLONG Size
49 );
50
51 typedef VOID
52 (*PBL_MM_DESTROY_SELF_MAP) (
53 VOID
54 );
55
56 typedef VOID
57 (*PBL_MM_FLUSH_TLB_ENTRY) (
58 _In_ PVOID VirtualAddress
59 );
60
61 typedef VOID
62 (*PBL_MM_FLUSH_TLB) (
63 VOID
64 );
65
66 typedef NTSTATUS
67 (*PBL_MM_UNMAP_VIRTUAL_ADDRESS) (
68 _In_ PVOID VirtualAddress,
69 _In_ ULONG Size
70 );
71
72 typedef NTSTATUS
73 (*PBL_MM_REMAP_VIRTUAL_ADDRESS) (
74 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
75 _Out_ PVOID VirtualAddress,
76 _In_ ULONG Size,
77 _In_ ULONG CacheAttributes
78 );
79
80 typedef NTSTATUS
81 (*PBL_MM_MAP_PHYSICAL_ADDRESS) (
82 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
83 _Out_ PVOID VirtualAddress,
84 _In_ ULONG Size,
85 _In_ ULONG CacheAttributes
86 );
87
88 typedef BOOLEAN
89 (*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS) (
90 _In_ PVOID VirtualAddress,
91 _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
92 _Out_opt_ PULONG CacheAttributes
93 );
94
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;
102
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;
107
108 PBL_MM_FLUSH_TLB Mmx86FlushTlb;
109
110 #define PTE_BASE (PVOID)0xC0000000
111
112 /* FUNCTIONS *****************************************************************/
113
114 VOID
115 MmArchNullFunction (
116 VOID
117 )
118 {
119 /* Nothing to do */
120 return;
121 }
122
123 VOID
124 MmDefRelocateSelfMap (
125 VOID
126 )
127 {
128 if (MmPteBase != PTE_BASE)
129 {
130 EfiPrintf(L"Supposed to relocate CR3\r\n");
131 }
132 }
133
134 NTSTATUS
135 MmDefMoveVirtualAddressRange (
136 _In_ PVOID DestinationAddress,
137 _In_ PVOID SourceAddress,
138 _In_ ULONGLONG Size
139 )
140 {
141 EfiPrintf(L"Supposed to move shit\r\n");
142 return STATUS_NOT_IMPLEMENTED;
143 }
144
145 NTSTATUS
146 MmDefZeroVirtualAddressRange (
147 _In_ PVOID DestinationAddress,
148 _In_ ULONGLONG Size
149 )
150 {
151 EfiPrintf(L"Supposed to zero shit\r\n");
152 return STATUS_NOT_IMPLEMENTED;
153 }
154
155 NTSTATUS
156 Mmx86pMapMemoryRegions (
157 _In_ ULONG Phase,
158 _In_ PBL_MEMORY_DATA MemoryData
159 )
160 {
161 BOOLEAN DoDeferred;
162
163 /* In phase 1 we don't initialize deferred mappings*/
164 if (Phase == 1)
165 {
166 DoDeferred = 0;
167 }
168 else
169 {
170 /* Don't do anything if there's nothing to initialize */
171 if (!MmDeferredMappingCount)
172 {
173 return STATUS_SUCCESS;
174 }
175
176 DoDeferred = 1;
177 }
178
179 if (DoDeferred)
180 {
181 EfiPrintf(L"Deferred todo\r\n");
182 }
183
184 EfiPrintf(L"Phase 1 TODO\r\n");
185 return STATUS_NOT_IMPLEMENTED;
186 }
187
188 BOOLEAN
189 MmArchTranslateVirtualAddress (
190 _In_ PVOID VirtualAddress,
191 _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress,
192 _Out_opt_ PULONG CachingFlags
193 )
194 {
195 PBL_MEMORY_DESCRIPTOR Descriptor;
196
197 /* Check if paging is on */
198 if ((CurrentExecutionContext) &&
199 (CurrentExecutionContext->ContextFlags & BL_CONTEXT_PAGING_ON))
200 {
201 /* Yes -- we have to translate this from virtual */
202 return Mmx86TranslateVirtualAddress(VirtualAddress,
203 PhysicalAddress,
204 CachingFlags);
205 }
206
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);
212
213 /* Return the virtual address as the physical address */
214 if (PhysicalAddress)
215 {
216 PhysicalAddress->HighPart = 0;
217 PhysicalAddress->LowPart = (ULONG_PTR)VirtualAddress;
218 }
219
220 /* There's no caching on physical memory */
221 if (CachingFlags)
222 {
223 *CachingFlags = 0;
224 }
225
226 /* Success is if we found a descriptor */
227 return Descriptor != NULL;
228 }
229
230 VOID
231 MmDefpDestroySelfMap (
232 VOID
233 )
234 {
235 EfiPrintf(L"No destroy\r\n");
236 }
237
238 VOID
239 MmDefpFlushTlbEntry (
240 _In_ PVOID VirtualAddress
241 )
242 {
243 /* Flush the TLB */
244 __invlpg(VirtualAddress);
245 }
246
247 VOID
248 MmDefpFlushTlb (
249 VOID
250 )
251 {
252 /* Flush the TLB */
253 __writecr3(__readcr3());
254 }
255
256 NTSTATUS
257 MmDefpUnmapVirtualAddress (
258 _In_ PVOID VirtualAddress,
259 _In_ ULONG Size
260 )
261 {
262 EfiPrintf(L"No unmap\r\n");
263 return STATUS_NOT_IMPLEMENTED;
264 }
265
266 NTSTATUS
267 MmDefpRemapVirtualAddress (
268 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
269 _Out_ PVOID VirtualAddress,
270 _In_ ULONG Size,
271 _In_ ULONG CacheAttributes
272 )
273 {
274 EfiPrintf(L"No remap\r\n");
275 return STATUS_NOT_IMPLEMENTED;
276 }
277
278 NTSTATUS
279 MmDefpMapPhysicalAddress (
280 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
281 _Out_ PVOID VirtualAddress,
282 _In_ ULONG Size,
283 _In_ ULONG CacheAttributes
284 )
285 {
286 EfiPrintf(L"No map\r\n");
287 return STATUS_NOT_IMPLEMENTED;
288 }
289
290 BOOLEAN
291 MmDefpTranslateVirtualAddress (
292 _In_ PVOID VirtualAddress,
293 _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
294 _Out_opt_ PULONG CacheAttributes
295 )
296 {
297 EfiPrintf(L"No translate\r\n");
298 return FALSE;
299 }
300
301 NTSTATUS
302 MmDefInitializeTranslation (
303 _In_ PBL_MEMORY_DATA MemoryData,
304 _In_ BL_TRANSLATION_TYPE TranslationType
305 )
306 {
307 NTSTATUS Status;
308 PHYSICAL_ADDRESS PhysicalAddress;
309
310 /* Set the global function pointers for memory translation */
311 Mmx86TranslateVirtualAddress = MmDefpTranslateVirtualAddress;
312 Mmx86MapPhysicalAddress = MmDefpMapPhysicalAddress;
313 Mmx86UnmapVirtualAddress = MmDefpUnmapVirtualAddress;
314 Mmx86RemapVirtualAddress = MmDefpRemapVirtualAddress;
315 Mmx86FlushTlb = MmDefpFlushTlb;
316 Mmx86FlushTlbEntry = MmDefpFlushTlbEntry;
317 Mmx86DestroySelfMap = MmDefpDestroySelfMap;
318
319 /* Check what mode we're currently in */
320 if (TranslationType == BlVirtual)
321 {
322 EfiPrintf(L"Virtual->Virtual not yet supported\r\n");
323 return STATUS_NOT_IMPLEMENTED;
324 }
325 else if (TranslationType != BlNone)
326 {
327 /* Not even Windows supports PAE->Virtual downgrade */
328 return STATUS_NOT_IMPLEMENTED;
329 }
330
331 /* The None->Virtual case */
332 MmPdpt = NULL;
333 Mmx86SelfMapBase.QuadPart = 0;
334 MmArchReferencePage = NULL;
335
336 /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
337 EfiPrintf(L"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
338 //Status = MmPaTruncateMemory(0x100000);
339 Status = STATUS_SUCCESS;
340 if (!NT_SUCCESS(Status))
341 {
342 goto Quickie;
343 }
344
345 /* Allocate a page directory */
346 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
347 BlLoaderPageDirectory,
348 1,
349 0,
350 0,
351 &MmMdlUnmappedAllocated,
352 0,
353 0);
354 if (!NT_SUCCESS(Status))
355 {
356 goto Quickie;
357 }
358
359 /* Zero out the page directory */
360 MmPdpt = (PVOID)PhysicalAddress.LowPart;
361 RtlZeroMemory(MmPdpt, PAGE_SIZE);
362
363 /* Set the page size */
364 MmArchReferencePageSize = PAGE_SIZE;
365
366 /* Allocate the self-map page */
367 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
368 BlLoaderReferencePage,
369 1,
370 0,
371 0,
372 &MmMdlUnmappedAllocated,
373 0,
374 0);
375 if (!NT_SUCCESS(Status))
376 {
377 goto Quickie;
378 }
379
380 /* Set the reference page */
381 MmArchReferencePage = (PVOID)PhysicalAddress.LowPart;
382
383 /* Zero it out */
384 RtlZeroMemory(MmArchReferencePage, MmArchReferencePageSize);
385
386 /* Allocate 4MB worth of self-map pages */
387 Status = MmPaReserveSelfMapPages(&Mmx86SelfMapBase,
388 (4 * 1024 * 1024) >> PAGE_SHIFT,
389 (4 * 1024 * 1024) >> PAGE_SHIFT);
390 if (!NT_SUCCESS(Status))
391 {
392 goto Quickie;
393 }
394
395 /* Zero them out */
396 RtlZeroMemory((PVOID)Mmx86SelfMapBase.LowPart, 4 * 1024 * 1024);
397
398 EfiPrintf(L"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
399 MmPdpt, MmArchReferencePage, Mmx86SelfMapBase.LowPart);
400 Status = STATUS_NOT_IMPLEMENTED;
401
402 //MmPteBase = Mmx86SelfMapBase.LowPart & 0xFFC00000;
403
404 Quickie:
405 /* Free reference page if we allocated it */
406 if (MmArchReferencePage)
407 {
408 PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage;
409 BlMmFreePhysicalPages(PhysicalAddress);
410 }
411
412 /* Free page directory if we allocated it */
413 if (MmPdpt)
414 {
415 PhysicalAddress.QuadPart = (ULONG_PTR)MmPdpt;
416 BlMmFreePhysicalPages(PhysicalAddress);
417 }
418
419 /* Free the self map if we allocated it */
420 if (Mmx86SelfMapBase.QuadPart)
421 {
422 MmPaReleaseSelfMapPages(Mmx86SelfMapBase);
423 }
424
425 /* All done */
426 return Status;
427 }
428
429 NTSTATUS
430 MmArchInitialize (
431 _In_ ULONG Phase,
432 _In_ PBL_MEMORY_DATA MemoryData,
433 _In_ BL_TRANSLATION_TYPE TranslationType,
434 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
435 )
436 {
437 NTSTATUS Status;
438 ULONGLONG IncreaseUserVa, PerfCounter, CpuRandom;
439 INT CpuInfo[4];
440
441 /* For phase 2, just map deferred regions */
442 if (Phase != 1)
443 {
444 return Mmx86pMapMemoryRegions(2, MemoryData);
445 }
446
447 /* What translation type are we switching to? */
448 switch (RequestedTranslationType)
449 {
450 /* Physical memory */
451 case BlNone:
452
453 /* Initialize everything to default/null values */
454 MmArchLargePageSize = 1;
455 MmArchKsegBase = 0;
456 MmArchKsegBias = 0;
457 MmArchKsegAddressRange.Minimum = 0;
458 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
459 MmArchTopOfApplicationAddressSpace = 0;
460 Mmx86SelfMapBase.QuadPart = 0;
461
462 /* Set stub functions */
463 BlMmRelocateSelfMap = MmArchNullFunction;
464 BlMmFlushTlb = MmArchNullFunction;
465
466 /* Set success */
467 Status = STATUS_SUCCESS;
468 break;
469
470 case BlVirtual:
471
472 /* Set the large page size to 1024 pages (4MB) */
473 MmArchLargePageSize = (4 * 1024 * 1024) / PAGE_SIZE;
474
475 /* Check if /USERVA option was used */
476 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
477 BcdOSLoaderInteger_IncreaseUserVa,
478 &IncreaseUserVa);
479 if (NT_SUCCESS(Status) && (IncreaseUserVa))
480 {
481 /* Yes -- load the kernel at 0xE0000000 instead */
482 MmArchKsegBase = 0xE0000000;
483 }
484 else
485 {
486 /* Nope, load at the standard 2GB split */
487 MmArchKsegBase = 0x80000000;
488 }
489
490 /* Check if CPUID 01h is supported */
491 CpuRandom = 0;
492 if (BlArchIsCpuIdFunctionSupported(1))
493 {
494 /* Call it */
495 BlArchCpuId(1, 0, CpuInfo);
496
497 /* Check if RDRAND is supported */
498 if (CpuInfo[2] & 0x40000000)
499 {
500 EfiPrintf(L"Your CPU can do RDRAND! Good for you!\r\n");
501 CpuRandom = 0;
502 }
503 }
504
505 /* Read the TSC */
506 PerfCounter = BlArchGetPerformanceCounter();
507 PerfCounter >>= 4;
508 _rotl16(PerfCounter, 5);
509
510 /* Set the address range */
511 MmArchKsegAddressRange.Minimum = 0;
512 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
513
514 /* Set the KASLR bias */
515 MmArchKsegBias = ((PerfCounter ^ CpuRandom) & 0xFFF) << 12;
516 MmArchKsegBias = 0;
517 MmArchKsegBase += MmArchKsegBias;
518
519 /* Set the kernel range */
520 MmArchKsegAddressRange.Minimum = MmArchKsegBase;
521 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
522
523 /* Set the boot application top maximum */
524 MmArchTopOfApplicationAddressSpace = 0x70000000;
525
526 /* Initialize virtual address space translation */
527 Status = MmDefInitializeTranslation(MemoryData, TranslationType);
528 if (NT_SUCCESS(Status))
529 {
530 /* Set stub functions */
531 BlMmRelocateSelfMap = MmDefRelocateSelfMap;
532 BlMmFlushTlb = Mmx86FlushTlb;
533 BlMmMoveVirtualAddressRange = MmDefMoveVirtualAddressRange;
534 BlMmZeroVirtualAddressRange = MmDefZeroVirtualAddressRange;
535 }
536 break;
537
538 case BlPae:
539
540 Status = STATUS_NOT_SUPPORTED;
541 break;
542
543 default:
544 Status = STATUS_INVALID_PARAMETER;
545 break;
546 }
547
548 return Status;
549
550 }