[BOOTLIB]: Don't use PTE_BASE/PDE_BASE in bootlib. Use MmPteBase and MmPdeBase instead.
[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 #define PTE_BASE 0xC0000000
15
16 //
17 // Specific PDE/PTE macros to be used inside the boot library environment
18 //
19 #define MiAddressToPte(x) ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + (ULONG_PTR)MmPteBase))
20 #define MiAddressToPde(x) ((PMMPDE)(((((ULONG)(x)) >> 22) << 2) + (ULONG_PTR)MmPdeBase))
21 #define MiAddressToPteOffset(x) ((((ULONG)(x)) << 10) >> 22)
22 #define MiAddressToPdeOffset(x) (((ULONG)(x)) / (1024 * PAGE_SIZE))
23
24 /* DATA VARIABLES ************************************************************/
25
26 ULONG_PTR MmArchKsegBase;
27 ULONG_PTR MmArchKsegBias;
28 ULONG MmArchLargePageSize;
29 BL_ADDRESS_RANGE MmArchKsegAddressRange;
30 ULONG_PTR MmArchTopOfApplicationAddressSpace;
31 PHYSICAL_ADDRESS Mmx86SelfMapBase;
32 ULONG MmDeferredMappingCount;
33 PMMPTE MmPdpt;
34 PULONG MmArchReferencePage;
35 PVOID MmPteBase;
36 PVOID MmPdeBase;
37 ULONG MmArchReferencePageSize;
38
39 typedef VOID
40 (*PBL_MM_FLUSH_TLB) (
41 VOID
42 );
43
44 typedef VOID
45 (*PBL_MM_RELOCATE_SELF_MAP) (
46 VOID
47 );
48
49 typedef NTSTATUS
50 (*PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE) (
51 _In_ PVOID DestinationAddress,
52 _In_ PVOID SourceAddress,
53 _In_ ULONGLONG Size
54 );
55
56 typedef NTSTATUS
57 (*PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE) (
58 _In_ PVOID DestinationAddress,
59 _In_ ULONGLONG Size
60 );
61
62 typedef VOID
63 (*PBL_MM_DESTROY_SELF_MAP) (
64 VOID
65 );
66
67 typedef VOID
68 (*PBL_MM_FLUSH_TLB_ENTRY) (
69 _In_ PVOID VirtualAddress
70 );
71
72 typedef VOID
73 (*PBL_MM_FLUSH_TLB) (
74 VOID
75 );
76
77 typedef NTSTATUS
78 (*PBL_MM_UNMAP_VIRTUAL_ADDRESS) (
79 _In_ PVOID VirtualAddress,
80 _In_ ULONG Size
81 );
82
83 typedef NTSTATUS
84 (*PBL_MM_REMAP_VIRTUAL_ADDRESS) (
85 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
86 _Out_ PVOID VirtualAddress,
87 _In_ ULONG Size,
88 _In_ ULONG CacheAttributes
89 );
90
91 typedef NTSTATUS
92 (*PBL_MM_MAP_PHYSICAL_ADDRESS) (
93 _In_ PHYSICAL_ADDRESS PhysicalAddress,
94 _Out_ PVOID VirtualAddress,
95 _In_ ULONG Size,
96 _In_ ULONG CacheAttributes
97 );
98
99 typedef BOOLEAN
100 (*PBL_MM_TRANSLATE_VIRTUAL_ADDRESS) (
101 _In_ PVOID VirtualAddress,
102 _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
103 _Out_opt_ PULONG CacheAttributes
104 );
105
106 PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress;
107 PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress;
108 PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress;
109 PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress;
110 PBL_MM_FLUSH_TLB Mmx86FlushTlb;
111 PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry;
112 PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap;
113
114 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap;
115 PBL_MM_FLUSH_TLB BlMmFlushTlb;
116 PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange;
117 PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange;
118
119 PBL_MM_FLUSH_TLB Mmx86FlushTlb;
120
121 /* FUNCTIONS *****************************************************************/
122
123 BOOLEAN
124 BlMmIsTranslationEnabled (
125 VOID
126 )
127 {
128 /* Return if paging is on */
129 return ((CurrentExecutionContext) &&
130 (CurrentExecutionContext->Mode & BL_CONTEXT_PAGING_ON));
131 }
132
133 VOID
134 MmArchNullFunction (
135 VOID
136 )
137 {
138 /* Nothing to do */
139 return;
140 }
141
142 VOID
143 MmDefRelocateSelfMap (
144 VOID
145 )
146 {
147 if (MmPteBase != (PVOID)PTE_BASE)
148 {
149 EfiPrintf(L"Supposed to relocate CR3\r\n");
150 }
151 }
152
153 NTSTATUS
154 MmDefMoveVirtualAddressRange (
155 _In_ PVOID DestinationAddress,
156 _In_ PVOID SourceAddress,
157 _In_ ULONGLONG Size
158 )
159 {
160 EfiPrintf(L"Supposed to move shit\r\n");
161 return STATUS_NOT_IMPLEMENTED;
162 }
163
164 NTSTATUS
165 MmDefZeroVirtualAddressRange (
166 _In_ PVOID DestinationAddress,
167 _In_ ULONGLONG Size
168 )
169 {
170 EfiPrintf(L"Supposed to zero shit\r\n");
171 return STATUS_NOT_IMPLEMENTED;
172 }
173
174 NTSTATUS
175 Mmx86pMapMemoryRegions (
176 _In_ ULONG Phase,
177 _In_ PBL_MEMORY_DATA MemoryData
178 )
179 {
180 BOOLEAN DoDeferred;
181
182 /* In phase 1 we don't initialize deferred mappings*/
183 if (Phase == 1)
184 {
185 DoDeferred = 0;
186 }
187 else
188 {
189 /* Don't do anything if there's nothing to initialize */
190 if (!MmDeferredMappingCount)
191 {
192 return STATUS_SUCCESS;
193 }
194
195 DoDeferred = 1;
196 }
197
198 if (DoDeferred)
199 {
200 EfiPrintf(L"Deferred todo\r\n");
201 }
202
203 EfiPrintf(L"Phase 1 TODO\r\n");
204 return STATUS_NOT_IMPLEMENTED;
205 }
206
207 BOOLEAN
208 MmArchTranslateVirtualAddress (
209 _In_ PVOID VirtualAddress,
210 _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress,
211 _Out_opt_ PULONG CachingFlags
212 )
213 {
214 PBL_MEMORY_DESCRIPTOR Descriptor;
215
216 /* Check if paging is on */
217 if ((CurrentExecutionContext) &&
218 (CurrentExecutionContext->ContextFlags & BL_CONTEXT_PAGING_ON))
219 {
220 /* Yes -- we have to translate this from virtual */
221 return Mmx86TranslateVirtualAddress(VirtualAddress,
222 PhysicalAddress,
223 CachingFlags);
224 }
225
226 /* Look in all descriptors except truncated and firmware ones */
227 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_NO_FIRMWARE_MEMORY &
228 ~BL_MM_INCLUDE_TRUNCATED_MEMORY,
229 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
230 (ULONG_PTR)VirtualAddress >> PAGE_SHIFT);
231
232 /* Return the virtual address as the physical address */
233 if (PhysicalAddress)
234 {
235 PhysicalAddress->HighPart = 0;
236 PhysicalAddress->LowPart = (ULONG_PTR)VirtualAddress;
237 }
238
239 /* There's no caching on physical memory */
240 if (CachingFlags)
241 {
242 *CachingFlags = 0;
243 }
244
245 /* Success is if we found a descriptor */
246 return Descriptor != NULL;
247 }
248
249 VOID
250 MmDefpDestroySelfMap (
251 VOID
252 )
253 {
254 EfiPrintf(L"No destroy\r\n");
255 }
256
257 VOID
258 MmDefpFlushTlbEntry (
259 _In_ PVOID VirtualAddress
260 )
261 {
262 /* Flush the TLB */
263 __invlpg(VirtualAddress);
264 }
265
266 VOID
267 MmDefpFlushTlb (
268 VOID
269 )
270 {
271 /* Flush the TLB */
272 __writecr3(__readcr3());
273 }
274
275 NTSTATUS
276 MmDefpUnmapVirtualAddress (
277 _In_ PVOID VirtualAddress,
278 _In_ ULONG Size
279 )
280 {
281 EfiPrintf(L"No unmap\r\n");
282 return STATUS_NOT_IMPLEMENTED;
283 }
284
285 NTSTATUS
286 MmDefpRemapVirtualAddress (
287 _In_ PPHYSICAL_ADDRESS PhysicalAddress,
288 _Out_ PVOID VirtualAddress,
289 _In_ ULONG Size,
290 _In_ ULONG CacheAttributes
291 )
292 {
293 EfiPrintf(L"No remap\r\n");
294 return STATUS_NOT_IMPLEMENTED;
295 }
296
297 NTSTATUS
298 MmDefpMapPhysicalAddress (
299 _In_ PHYSICAL_ADDRESS PhysicalAddress,
300 _In_ PVOID VirtualAddress,
301 _In_ ULONG Size,
302 _In_ ULONG CacheAttributes
303 )
304 {
305 BOOLEAN Enabled;
306 ULONG i, PageCount, PdeOffset;
307 ULONGLONG CurrentAddress;
308 PMMPDE Pde;
309 PMMPTE Pte;
310 PMMPTE PageTable;
311 PHYSICAL_ADDRESS PageTableAddress;
312 NTSTATUS Status;
313
314 /* Check if paging is on yet */
315 Enabled = BlMmIsTranslationEnabled();
316
317 /* Get the physical address aligned */
318 CurrentAddress = (PhysicalAddress.QuadPart >> PAGE_SHIFT) << PAGE_SHIFT;
319
320 /* Get the number of pages and loop through each one */
321 PageCount = Size >> PAGE_SHIFT;
322 for (i = 0; i < PageCount; i++)
323 {
324 /* Check if translation already exists for this page */
325 if (Mmx86TranslateVirtualAddress(VirtualAddress, NULL, NULL))
326 {
327 /* Ignore it and move to the next one */
328 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
329 CurrentAddress += PAGE_SIZE;
330 continue;
331 }
332
333 /* Get the PDE offset */
334 PdeOffset = MiAddressToPdeOffset(VirtualAddress);
335
336 /* Check if paging is actually turned on */
337 if (Enabled)
338 {
339 /* Get the PDE entry using the self-map */
340 Pde = MiAddressToPde(VirtualAddress);
341 }
342 else
343 {
344 /* Get it using our physical mappings */
345 Pde = &MmPdpt[PdeOffset];
346 PageTable = (PMMPDE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT);
347 }
348
349 /* Check if we don't yet have a PDE */
350 if (!Pde->u.Hard.Valid)
351 {
352 /* Allocate a page table */
353 Status = MmPapAllocatePhysicalPagesInRange(&PageTableAddress,
354 BlLoaderPageDirectory,
355 1,
356 0,
357 0,
358 &MmMdlUnmappedAllocated,
359 0,
360 0);
361 if (!NT_SUCCESS(Status))
362 {
363 return STATUS_NO_MEMORY;
364 }
365
366 /* This is our page table */
367 PageTable = (PVOID)(ULONG_PTR)PageTableAddress.QuadPart;
368
369 /* Build the PDE for it */
370 Pde->u.Hard.PageFrameNumber = PageTableAddress.QuadPart >> PAGE_SHIFT;
371 Pde->u.Hard.Write = 1;
372 Pde->u.Hard.CacheDisable = 1;
373 Pde->u.Hard.WriteThrough = 1;
374 Pde->u.Hard.Valid = 1;
375
376 /* Check if paging is enabled */
377 if (Enabled)
378 {
379 /* Then actually, get the page table's virtual address */
380 PageTable = (PVOID)PAGE_ROUND_DOWN(MiAddressToPte(VirtualAddress));
381
382 /* Flush the TLB */
383 Mmx86FlushTlb();
384 }
385
386 /* Zero out the page table */
387 RtlZeroMemory(PageTable, PAGE_SIZE);
388
389 /* Reset caching attributes now */
390 Pde->u.Hard.CacheDisable = 0;
391 Pde->u.Hard.WriteThrough = 0;
392
393 /* Check for paging again */
394 if (Enabled)
395 {
396 /* Flush the TLB entry for the page table only */
397 Mmx86FlushTlbEntry(PageTable);
398 }
399 }
400
401 /* Add a reference to this page table */
402 MmArchReferencePage[PdeOffset]++;
403
404 /* Check if a physical address was given */
405 if (PhysicalAddress.QuadPart != -1)
406 {
407 /* Check if paging is turned on */
408 if (Enabled)
409 {
410 /* Get the PTE using the self-map */
411 Pte = MiAddressToPte(VirtualAddress);
412 }
413 else
414 {
415 /* Get the PTE using physical addressing */
416 Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)];
417 }
418
419 /* Build a valid PTE for it */
420 Pte->u.Hard.PageFrameNumber = CurrentAddress >> PAGE_SHIFT;
421 Pte->u.Hard.Write = 1;
422 Pte->u.Hard.Valid = 1;
423
424 /* Check if this is uncached */
425 if (CacheAttributes == BlMemoryUncached)
426 {
427 /* Set the flags */
428 Pte->u.Hard.CacheDisable = 1;
429 Pte->u.Hard.WriteThrough = 1;
430 }
431 else if (CacheAttributes == BlMemoryWriteThrough)
432 {
433 /* It's write-through, set the flag */
434 Pte->u.Hard.WriteThrough = 1;
435 }
436 }
437
438 /* Move to the next physical/virtual address */
439 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
440 CurrentAddress += PAGE_SIZE;
441 }
442
443 /* All done! */
444 return STATUS_SUCCESS;
445 }
446
447 BOOLEAN
448 MmDefpTranslateVirtualAddress (
449 _In_ PVOID VirtualAddress,
450 _Out_ PPHYSICAL_ADDRESS PhysicalAddress,
451 _Out_opt_ PULONG CacheAttributes
452 )
453 {
454 PMMPDE Pde;
455 PMMPTE Pte;
456 PMMPTE PageTable;
457 BOOLEAN Enabled;
458
459 /* Is there no page directory yet? */
460 if (!MmPdpt)
461 {
462 return FALSE;
463 }
464
465 /* Is paging enabled? */
466 Enabled = BlMmIsTranslationEnabled();
467
468 /* Check if paging is actually turned on */
469 if (Enabled)
470 {
471 /* Get the PDE entry using the self-map */
472 Pde = MiAddressToPde(VirtualAddress);
473 }
474 else
475 {
476 /* Get it using our physical mappings */
477 Pde = &MmPdpt[MiAddressToPdeOffset(VirtualAddress)];
478 }
479
480 /* Is the PDE valid? */
481 if (!Pde->u.Hard.Valid)
482 {
483 return FALSE;
484 }
485
486 /* Check if paging is turned on */
487 if (Enabled)
488 {
489 /* Get the PTE using the self-map */
490 Pte = MiAddressToPte(VirtualAddress);
491 }
492 else
493 {
494 /* Get the PTE using physical addressing */
495 PageTable = (PMMPTE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT);
496 Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)];
497 }
498
499 /* Is the PTE valid? */
500 if (!Pte->u.Hard.Valid)
501 {
502 return FALSE;
503 }
504
505 /* Does caller want the physical address? */
506 if (PhysicalAddress)
507 {
508 /* Return it */
509 PhysicalAddress->QuadPart = (Pte->u.Hard.PageFrameNumber << PAGE_SHIFT) +
510 BYTE_OFFSET(VirtualAddress);
511 }
512
513 /* Does caller want cache attributes? */
514 if (CacheAttributes)
515 {
516 /* Not yet -- lie and say it's cached */
517 EfiPrintf(L"Cache checking not yet enabled\r\n");
518 *CacheAttributes = BlMemoryWriteBack;
519 }
520
521 /* It exists! */
522 return TRUE;
523 }
524
525 NTSTATUS
526 MmSelectMappingAddress (
527 _Out_ PVOID* MappingAddress,
528 _In_ ULONGLONG Size,
529 _In_ ULONG AllocationAttributes,
530 _In_ ULONG Flags,
531 _In_ PHYSICAL_ADDRESS PhysicalAddress
532 )
533 {
534 /* Are we in physical mode? */
535 if (MmTranslationType == BlNone)
536 {
537 /* Just return the physical address as the mapping address */
538 *MappingAddress = (PVOID)PhysicalAddress.LowPart;
539 return STATUS_SUCCESS;
540 }
541
542 /* We don't support virtual memory yet @TODO */
543 #ifdef _MSC_VER // Fuck gcc.
544 EfiPrintf(L"not yet implemented in " __FUNCTION__ "\r\n");
545 EfiStall(1000000);
546 #endif
547 return STATUS_NOT_IMPLEMENTED;
548 }
549
550 NTSTATUS
551 MmMapPhysicalAddress (
552 _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr,
553 _Inout_ PVOID* VirtualAddressPtr,
554 _Inout_ PULONGLONG SizePtr,
555 _In_ ULONG CacheAttributes
556 )
557 {
558 ULONGLONG Size, TotalSize;
559 ULONGLONG PhysicalAddress;
560 PVOID VirtualAddress;
561 PHYSICAL_ADDRESS TranslatedAddress;
562 ULONG_PTR CurrentAddress, VirtualAddressEnd;
563 NTSTATUS Status;
564
565 /* Fail if any parameters are missing */
566 if (!(PhysicalAddressPtr) || !(VirtualAddressPtr) || !(SizePtr))
567 {
568 return STATUS_INVALID_PARAMETER;
569 }
570
571 /* Fail if the size is over 32-bits */
572 Size = *SizePtr;
573 if (Size > 0xFFFFFFFF)
574 {
575 return STATUS_INVALID_PARAMETER;
576 }
577
578 /* Nothing to do if we're in physical mode */
579 if (MmTranslationType == BlNone)
580 {
581 return STATUS_SUCCESS;
582 }
583
584 /* Can't use virtual memory in real mode */
585 if (CurrentExecutionContext->Mode == BlRealMode)
586 {
587 return STATUS_UNSUCCESSFUL;
588 }
589
590 /* Capture the current virtual and physical addresses */
591 VirtualAddress = *VirtualAddressPtr;
592 PhysicalAddress = PhysicalAddressPtr->QuadPart;
593
594 /* Check if a physical address was requested */
595 if (PhysicalAddress != 0xFFFFFFFF)
596 {
597 /* Round down the base addresses */
598 PhysicalAddress = PAGE_ROUND_DOWN(PhysicalAddress);
599 VirtualAddress = (PVOID)PAGE_ROUND_DOWN(VirtualAddress);
600
601 /* Round up the size */
602 TotalSize = ROUND_TO_PAGES(PhysicalAddressPtr->QuadPart -
603 PhysicalAddress +
604 Size);
605
606 /* Loop every virtual page */
607 CurrentAddress = (ULONG_PTR)VirtualAddress;
608 VirtualAddressEnd = CurrentAddress + TotalSize - 1;
609 while (CurrentAddress < VirtualAddressEnd)
610 {
611 /* Get the physical page of this virtual page */
612 if (MmArchTranslateVirtualAddress((PVOID)CurrentAddress,
613 &TranslatedAddress,
614 &CacheAttributes))
615 {
616 /* Make sure the physical page of the virtual page, matches our page */
617 if (TranslatedAddress.QuadPart !=
618 (PhysicalAddress +
619 (CurrentAddress - (ULONG_PTR)VirtualAddress)))
620 {
621 /* There is an existing virtual mapping for a different address */
622 EfiPrintf(L"Existing mapping exists: %lx vs %lx\r\n",
623 TranslatedAddress.QuadPart,
624 PhysicalAddress + (CurrentAddress - (ULONG_PTR)VirtualAddress));
625 return STATUS_INVALID_PARAMETER;
626 }
627 }
628
629 /* Try the next one */
630 CurrentAddress += PAGE_SIZE;
631 }
632 }
633
634 /* Aactually do the mapping */
635 TranslatedAddress.QuadPart = PhysicalAddress;
636 Status = Mmx86MapPhysicalAddress(TranslatedAddress,
637 VirtualAddress,
638 Size,
639 CacheAttributes);
640 if (!NT_SUCCESS(Status))
641 {
642 EfiPrintf(L"Failed to map!: %lx\r\n", Status);
643 return Status;
644 }
645
646 /* Return aligned/fixed up output parameters */
647 PhysicalAddressPtr->QuadPart = PhysicalAddress;
648 *VirtualAddressPtr = VirtualAddress;
649 *SizePtr = Size;
650
651 /* Flush the TLB if paging is enabled */
652 if (BlMmIsTranslationEnabled())
653 {
654 Mmx86FlushTlb();
655 }
656
657 /* All good! */
658 return STATUS_SUCCESS;
659 }
660
661 NTSTATUS
662 Mmx86MapInitStructure (
663 _In_ PVOID VirtualAddress,
664 _In_ ULONGLONG Size,
665 _In_ PHYSICAL_ADDRESS PhysicalAddress
666 )
667 {
668 NTSTATUS Status;
669
670 /* Make a virtual mapping for this physical address */
671 Status = MmMapPhysicalAddress(&PhysicalAddress, &VirtualAddress, &Size, 0);
672 if (!NT_SUCCESS(Status))
673 {
674 return Status;
675 }
676
677 /* Nothing else to do if we're not in paging mode */
678 if (MmTranslationType == BlNone)
679 {
680 return STATUS_SUCCESS;
681 }
682
683 /* Otherwise, remove this region from the list of free virtual ranges */
684 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
685 BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
686 (ULONG_PTR)VirtualAddress >> PAGE_SHIFT,
687 Size >> PAGE_SHIFT,
688 0);
689 if (!NT_SUCCESS(Status))
690 {
691 /* Unmap the address if that failed */
692 MmUnmapVirtualAddress(&VirtualAddress, &Size);
693 }
694
695 /* Return back to caller */
696 return Status;
697 }
698
699 NTSTATUS
700 Mmx86InitializeMemoryMap (
701 _In_ ULONG Phase,
702 _In_ PBL_MEMORY_DATA MemoryData
703 )
704 {
705 ULONG ImageSize;
706 PVOID ImageBase;
707 KDESCRIPTOR Gdt, Idt;
708 NTSTATUS Status;
709 PHYSICAL_ADDRESS PhysicalAddress;
710
711 /* If this is phase 2, map the memory regions */
712 if (Phase != 1)
713 {
714 return Mmx86pMapMemoryRegions(Phase, MemoryData);
715 }
716
717 /* Get the application image base/size */
718 Status = BlGetApplicationBaseAndSize(&ImageBase, &ImageSize);
719 if (!NT_SUCCESS(Status))
720 {
721 return Status;
722 }
723
724 /* Map the image back at the same place */
725 PhysicalAddress.QuadPart = (ULONG_PTR)ImageBase;
726 Status = Mmx86MapInitStructure(ImageBase, ImageSize, PhysicalAddress);
727 if (!NT_SUCCESS(Status))
728 {
729 return Status;
730 }
731
732 /* Map the first 4MB of memory */
733 PhysicalAddress.QuadPart = 0;
734 Status = Mmx86MapInitStructure(NULL, 4 * 1024 * 1024, PhysicalAddress);
735 if (!NT_SUCCESS(Status))
736 {
737 return Status;
738 }
739
740 /* Map the GDT */
741 _sgdt(&Gdt.Limit);
742 PhysicalAddress.QuadPart = Gdt.Base;
743 Status = Mmx86MapInitStructure((PVOID)Gdt.Base, Gdt.Limit + 1, PhysicalAddress);
744 if (!NT_SUCCESS(Status))
745 {
746 return Status;
747 }
748
749 /* Map the IDT */
750 __sidt(&Idt.Limit);
751 PhysicalAddress.QuadPart = Idt.Base;
752 Status = Mmx86MapInitStructure((PVOID)Idt.Base, Idt.Limit + 1, PhysicalAddress);
753 if (!NT_SUCCESS(Status))
754 {
755 return Status;
756 }
757
758 /* Map the reference page */
759 PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage;
760 Status = Mmx86MapInitStructure(MmArchReferencePage,
761 MmArchReferencePageSize,
762 PhysicalAddress);
763 if (!NT_SUCCESS(Status))
764 {
765 return Status;
766 }
767
768 /* More to do */
769 EfiPrintf(L"VM more work\r\n");
770 return STATUS_NOT_IMPLEMENTED;
771 }
772
773 NTSTATUS
774 MmDefInitializeTranslation (
775 _In_ PBL_MEMORY_DATA MemoryData,
776 _In_ BL_TRANSLATION_TYPE TranslationType
777 )
778 {
779 NTSTATUS Status;
780 PHYSICAL_ADDRESS PhysicalAddress;
781 ULONG PdeIndex;
782
783 /* Set the global function pointers for memory translation */
784 Mmx86TranslateVirtualAddress = MmDefpTranslateVirtualAddress;
785 Mmx86MapPhysicalAddress = MmDefpMapPhysicalAddress;
786 Mmx86UnmapVirtualAddress = MmDefpUnmapVirtualAddress;
787 Mmx86RemapVirtualAddress = MmDefpRemapVirtualAddress;
788 Mmx86FlushTlb = MmDefpFlushTlb;
789 Mmx86FlushTlbEntry = MmDefpFlushTlbEntry;
790 Mmx86DestroySelfMap = MmDefpDestroySelfMap;
791
792 /* Check what mode we're currently in */
793 if (TranslationType == BlVirtual)
794 {
795 EfiPrintf(L"Virtual->Virtual not yet supported\r\n");
796 return STATUS_NOT_IMPLEMENTED;
797 }
798 else if (TranslationType != BlNone)
799 {
800 /* Not even Windows supports PAE->Virtual downgrade */
801 return STATUS_NOT_IMPLEMENTED;
802 }
803
804 /* The None->Virtual case */
805 MmPdpt = NULL;
806 Mmx86SelfMapBase.QuadPart = 0;
807 MmArchReferencePage = NULL;
808
809 /* Truncate all memory above 4GB so that we don't use it @TODO: FIXME */
810 EfiPrintf(L"Warning: not truncating > 4GB memory. Don't boot with more than 4GB of RAM!\r\n");
811 //Status = MmPaTruncateMemory(0x100000);
812 Status = STATUS_SUCCESS;
813 if (!NT_SUCCESS(Status))
814 {
815 goto Quickie;
816 }
817
818 /* Allocate a page directory */
819 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
820 BlLoaderPageDirectory,
821 1,
822 0,
823 0,
824 &MmMdlUnmappedAllocated,
825 0,
826 0);
827 if (!NT_SUCCESS(Status))
828 {
829 goto Quickie;
830 }
831
832 /* Zero out the page directory */
833 MmPdpt = (PVOID)PhysicalAddress.LowPart;
834 RtlZeroMemory(MmPdpt, PAGE_SIZE);
835
836 /* Set the page size */
837 MmArchReferencePageSize = PAGE_SIZE;
838
839 /* Allocate the self-map page */
840 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
841 BlLoaderReferencePage,
842 1,
843 0,
844 0,
845 &MmMdlUnmappedAllocated,
846 0,
847 0);
848 if (!NT_SUCCESS(Status))
849 {
850 goto Quickie;
851 }
852
853 /* Set the reference page */
854 MmArchReferencePage = (PVOID)PhysicalAddress.LowPart;
855
856 /* Zero it out */
857 RtlZeroMemory(MmArchReferencePage, MmArchReferencePageSize);
858
859 /* Allocate 4MB worth of self-map pages */
860 Status = MmPaReserveSelfMapPages(&Mmx86SelfMapBase,
861 (4 * 1024 * 1024) >> PAGE_SHIFT,
862 (4 * 1024 * 1024) >> PAGE_SHIFT);
863 if (!NT_SUCCESS(Status))
864 {
865 goto Quickie;
866 }
867
868 /* Zero them out */
869 RtlZeroMemory((PVOID)Mmx86SelfMapBase.LowPart, 4 * 1024 * 1024);
870 EfiPrintf(L"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n",
871 MmPdpt, MmArchReferencePage, Mmx86SelfMapBase.LowPart);
872
873 /* Align PTE base to 4MB region */
874 MmPteBase = (PVOID)(Mmx86SelfMapBase.LowPart & ~0x3FFFFF);
875
876 /* The PDE is the PTE of the PTE base */
877 MmPdeBase = MiAddressToPte(MmPteBase);
878 PdeIndex = MiAddressToPdeOffset(MmPdeBase);
879 MmPdpt[PdeIndex].u.Hard.Valid = 1;
880 MmPdpt[PdeIndex].u.Hard.Write = 1;
881 MmPdpt[PdeIndex].u.Hard.PageFrameNumber = (ULONG_PTR)MmPdpt >> PAGE_SHIFT;
882 MmArchReferencePage[PdeIndex]++;
883
884 /* Remove PTE_BASE from free virtual memory */
885 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
886 BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
887 PTE_BASE >> PAGE_SHIFT,
888 (4 * 1024 * 1024) >> PAGE_SHIFT,
889 0);
890 if (!NT_SUCCESS(Status))
891 {
892 goto Quickie;
893 }
894
895 /* Remove HAL_HEAP from free virtual memory */
896 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
897 BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
898 MM_HAL_VA_START >> PAGE_SHIFT,
899 (4 * 1024 * 1024) >> PAGE_SHIFT,
900 0);
901 if (!NT_SUCCESS(Status))
902 {
903 goto Quickie;
904 }
905
906 /* Initialize the virtual->physical memory mappings */
907 Status = Mmx86InitializeMemoryMap(1, MemoryData);
908 if (!NT_SUCCESS(Status))
909 {
910 goto Quickie;
911 }
912
913 EfiPrintf(L"Ready to turn on motherfucking paging, brah!\r\n");
914 Status = STATUS_NOT_IMPLEMENTED;
915
916 Quickie:
917 /* Free reference page if we allocated it */
918 if (MmArchReferencePage)
919 {
920 PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage;
921 BlMmFreePhysicalPages(PhysicalAddress);
922 }
923
924 /* Free page directory if we allocated it */
925 if (MmPdpt)
926 {
927 PhysicalAddress.QuadPart = (ULONG_PTR)MmPdpt;
928 BlMmFreePhysicalPages(PhysicalAddress);
929 }
930
931 /* Free the self map if we allocated it */
932 if (Mmx86SelfMapBase.QuadPart)
933 {
934 MmPaReleaseSelfMapPages(Mmx86SelfMapBase);
935 }
936
937 /* All done */
938 return Status;
939 }
940
941 NTSTATUS
942 MmArchInitialize (
943 _In_ ULONG Phase,
944 _In_ PBL_MEMORY_DATA MemoryData,
945 _In_ BL_TRANSLATION_TYPE TranslationType,
946 _In_ BL_TRANSLATION_TYPE RequestedTranslationType
947 )
948 {
949 NTSTATUS Status;
950 ULONGLONG IncreaseUserVa, PerfCounter, CpuRandom;
951 INT CpuInfo[4];
952
953 /* For phase 2, just map deferred regions */
954 if (Phase != 1)
955 {
956 return Mmx86pMapMemoryRegions(2, MemoryData);
957 }
958
959 /* What translation type are we switching to? */
960 switch (RequestedTranslationType)
961 {
962 /* Physical memory */
963 case BlNone:
964
965 /* Initialize everything to default/null values */
966 MmArchLargePageSize = 1;
967 MmArchKsegBase = 0;
968 MmArchKsegBias = 0;
969 MmArchKsegAddressRange.Minimum = 0;
970 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
971 MmArchTopOfApplicationAddressSpace = 0;
972 Mmx86SelfMapBase.QuadPart = 0;
973
974 /* Set stub functions */
975 BlMmRelocateSelfMap = MmArchNullFunction;
976 BlMmFlushTlb = MmArchNullFunction;
977
978 /* Set success */
979 Status = STATUS_SUCCESS;
980 break;
981
982 case BlVirtual:
983
984 /* Set the large page size to 1024 pages (4MB) */
985 MmArchLargePageSize = (4 * 1024 * 1024) / PAGE_SIZE;
986
987 /* Check if /USERVA option was used */
988 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
989 BcdOSLoaderInteger_IncreaseUserVa,
990 &IncreaseUserVa);
991 if (NT_SUCCESS(Status) && (IncreaseUserVa))
992 {
993 /* Yes -- load the kernel at 0xE0000000 instead */
994 MmArchKsegBase = 0xE0000000;
995 }
996 else
997 {
998 /* Nope, load at the standard 2GB split */
999 MmArchKsegBase = 0x80000000;
1000 }
1001
1002 /* Check if CPUID 01h is supported */
1003 CpuRandom = 0;
1004 if (BlArchIsCpuIdFunctionSupported(1))
1005 {
1006 /* Call it */
1007 BlArchCpuId(1, 0, CpuInfo);
1008
1009 /* Check if RDRAND is supported */
1010 if (CpuInfo[2] & 0x40000000)
1011 {
1012 EfiPrintf(L"Your CPU can do RDRAND! Good for you!\r\n");
1013 CpuRandom = 0;
1014 }
1015 }
1016
1017 /* Read the TSC */
1018 PerfCounter = BlArchGetPerformanceCounter();
1019 PerfCounter >>= 4;
1020 _rotl16(PerfCounter, 5);
1021
1022 /* Set the address range */
1023 MmArchKsegAddressRange.Minimum = 0;
1024 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
1025
1026 /* Set the KASLR bias */
1027 MmArchKsegBias = ((PerfCounter ^ CpuRandom) & 0xFFF) << 12;
1028 MmArchKsegBias = 0;
1029 MmArchKsegBase += MmArchKsegBias;
1030
1031 /* Set the kernel range */
1032 MmArchKsegAddressRange.Minimum = MmArchKsegBase;
1033 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0;
1034
1035 /* Set the boot application top maximum */
1036 MmArchTopOfApplicationAddressSpace = 0x70000000;
1037
1038 /* Initialize virtual address space translation */
1039 Status = MmDefInitializeTranslation(MemoryData, TranslationType);
1040 if (NT_SUCCESS(Status))
1041 {
1042 /* Set stub functions */
1043 BlMmRelocateSelfMap = MmDefRelocateSelfMap;
1044 BlMmFlushTlb = Mmx86FlushTlb;
1045 BlMmMoveVirtualAddressRange = MmDefMoveVirtualAddressRange;
1046 BlMmZeroVirtualAddressRange = MmDefZeroVirtualAddressRange;
1047 }
1048 break;
1049
1050 case BlPae:
1051
1052 Status = STATUS_NOT_SUPPORTED;
1053 break;
1054
1055 default:
1056 Status = STATUS_INVALID_PARAMETER;
1057 break;
1058 }
1059
1060 return Status;
1061
1062 }