2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: boot/freeldr/freeldr/arch/amd64/winldr.c
5 * PURPOSE: Memory related routines
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES ***************************************************************/
16 //extern ULONG LoaderPagesSpanned;
18 DBG_DEFAULT_CHANNEL(WINDOWS
);
20 /* GLOBALS ***************************************************************/
22 PHARDWARE_PTE PxeBase
;
23 //PHARDWARE_PTE HalPageTable;
26 ULONG_PTR PcrBasePage
;
27 ULONG_PTR TssBasePage
;
29 /* FUNCTIONS **************************************************************/
32 MempAllocatePageTables(VOID
)
34 TRACE(">>> MempAllocatePageTables\n");
36 /* Allocate a page for the PML4 */
37 PxeBase
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
40 ERR("failed to allocate PML4\n");
44 // FIXME: Physical PTEs = FirmwareTemporary ?
47 RtlZeroMemory(PxeBase
, PAGE_SIZE
);
49 /* The page tables are located at 0xfffff68000000000
50 * We create a recursive self mapping through all 4 levels at
51 * virtual address 0xfffff6fb7dbedf68 */
52 PxeBase
[VAtoPXI(PXE_BASE
)].Valid
= 1;
53 PxeBase
[VAtoPXI(PXE_BASE
)].Write
= 1;
54 PxeBase
[VAtoPXI(PXE_BASE
)].PageFrameNumber
= PtrToPfn(PxeBase
);
56 // FIXME: map PDE's for hals memory mapping
58 TRACE(">>> leave MempAllocatePageTables\n");
64 MempGetOrCreatePageDir(PHARDWARE_PTE PdeBase
, ULONG Index
)
71 if (!PdeBase
[Index
].Valid
)
73 SubDir
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
76 RtlZeroMemory(SubDir
, PAGE_SIZE
);
77 PdeBase
[Index
].PageFrameNumber
= PtrToPfn(SubDir
);
78 PdeBase
[Index
].Valid
= 1;
79 PdeBase
[Index
].Write
= 1;
83 SubDir
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
89 MempMapSinglePage(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
)
91 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
94 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(VirtualAddress
));
95 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(VirtualAddress
));
96 PteBase
= MempGetOrCreatePageDir(PdeBase
, VAtoPDI(VirtualAddress
));
100 ERR("!!!No Dir %p, %p, %p, %p\n", PxeBase
, PpeBase
, PdeBase
, PteBase
);
104 Index
= VAtoPTI(VirtualAddress
);
105 if (PteBase
[Index
].Valid
)
107 ERR("!!!Already mapped %ld\n", Index
);
111 PteBase
[Index
].Valid
= 1;
112 PteBase
[Index
].Write
= 1;
113 PteBase
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
119 MempIsPageMapped(PVOID VirtualAddress
)
121 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
124 Index
= VAtoPXI(VirtualAddress
);
125 if (!PxeBase
[Index
].Valid
)
128 PpeBase
= (PVOID
)((ULONG64
)(PxeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
129 Index
= VAtoPPI(VirtualAddress
);
130 if (!PpeBase
[Index
].Valid
)
133 PdeBase
= (PVOID
)((ULONG64
)(PpeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
134 Index
= VAtoPDI(VirtualAddress
);
135 if (!PdeBase
[Index
].Valid
)
138 PteBase
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
139 Index
= VAtoPTI(VirtualAddress
);
140 if (!PteBase
[Index
].Valid
)
147 MempMapRangeOfPages(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
, PFN_NUMBER cPages
)
151 for (i
= 0; i
< cPages
; i
++)
153 if (!MempMapSinglePage(VirtualAddress
, PhysicalAddress
))
155 ERR("Failed to map page %ld from %p to %p\n",
156 i
, (PVOID
)VirtualAddress
, (PVOID
)PhysicalAddress
);
159 VirtualAddress
+= PAGE_SIZE
;
160 PhysicalAddress
+= PAGE_SIZE
;
166 MempSetupPaging(IN PFN_NUMBER StartPage
,
167 IN PFN_NUMBER NumberOfPages
,
168 IN BOOLEAN KernelMapping
)
170 TRACE(">>> MempSetupPaging(0x%lx, %ld, %p)\n",
171 StartPage
, NumberOfPages
, StartPage
* PAGE_SIZE
+ KSEG0_BASE
);
173 /* Identity mapping */
174 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
,
175 StartPage
* PAGE_SIZE
,
176 NumberOfPages
) != NumberOfPages
)
178 ERR("Failed to map pages %ld, %ld\n",
179 StartPage
, NumberOfPages
);
186 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
+ KSEG0_BASE
,
187 StartPage
* PAGE_SIZE
,
188 NumberOfPages
) != NumberOfPages
)
190 ERR("Failed to map pages %ld, %ld\n",
191 StartPage
, NumberOfPages
);
200 MempUnmapPage(PFN_NUMBER Page
)
202 // TRACE(">>> MempUnmapPage\n");
209 LARGE_INTEGER MsrValue
;
213 TRACE(">>> WinLdrpMapApic\n");
215 /* Check if we have a local APIC */
216 __cpuid((int*)CpuInfo
, 1);
217 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
219 /* If there is no APIC, just return */
222 WARN("No APIC found.\n");
226 /* Read the APIC Address */
227 MsrValue
.QuadPart
= __readmsr(0x1B);
228 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
230 TRACE("Local APIC detected at address 0x%x\n",
234 MempMapSinglePage(APIC_BASE
, APICAddress
);
238 WinLdrMapSpecialPages(VOID
)
240 PHARDWARE_PTE PpeBase
, PdeBase
;
242 /* Map the PCR page */
243 if (!MempMapSinglePage(KIP0PCRADDRESS
, PcrBasePage
* PAGE_SIZE
))
245 ERR("Could not map PCR @ %lx\n", PcrBasePage
);
249 /* Map KI_USER_SHARED_DATA */
250 if (!MempMapSinglePage(KI_USER_SHARED_DATA
, (PcrBasePage
+1) * PAGE_SIZE
))
252 ERR("Could not map KI_USER_SHARED_DATA\n");
256 /* Map the APIC page */
259 /* Map the page tables for 4 MB HAL address space. */
260 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(MM_HAL_VA_START
));
261 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(MM_HAL_VA_START
));
262 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
));
263 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
+ 2 * 1024 * 1024));
269 Amd64SetupGdt(PVOID GdtBase
, ULONG64 TssBase
)
273 TRACE("Amd64SetupGdt(GdtBase = %p, TssBase = %p)\n", GdtBase
, TssBase
);
275 /* Setup KGDT64_NULL */
276 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_NULL
);
277 *(PULONG64
)Entry
= 0x0000000000000000ULL
;
279 /* Setup KGDT64_R0_CODE */
280 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_CODE
);
281 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
283 /* Setup KGDT64_R0_DATA */
284 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_DATA
);
285 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
287 /* Setup KGDT64_R3_CMCODE */
288 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMCODE
);
289 *(PULONG64
)Entry
= 0x00cffb000000ffffULL
;
291 /* Setup KGDT64_R3_DATA */
292 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_DATA
);
293 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
295 /* Setup KGDT64_R3_CODE */
296 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CODE
);
297 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
299 /* Setup KGDT64_R3_CMTEB */
300 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMTEB
);
301 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
303 /* Setup TSS entry */
304 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_SYS_TSS
);
305 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
307 /* Setup GDT descriptor */
308 GdtDesc
.Base
= GdtBase
;
309 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
311 /* Set the new Gdt */
312 __lgdt(&GdtDesc
.Limit
);
313 TRACE("Leave Amd64SetupGdt()\n");
317 Amd64SetupIdt(PVOID IdtBase
)
319 KDESCRIPTOR IdtDesc
, OldIdt
;
321 TRACE("Amd64SetupIdt(IdtBase = %p)\n", IdtBase
);
324 __sidt(&OldIdt
.Limit
);
326 /* Copy the old IDT */
327 Size
= min(OldIdt
.Limit
+ 1, NUM_IDT
* sizeof(KIDTENTRY
));
328 //RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, Size);
330 /* Setup the new IDT descriptor */
331 IdtDesc
.Base
= IdtBase
;
332 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
334 /* Set the new IDT */
335 __lidt(&IdtDesc
.Limit
);
336 TRACE("Leave Amd64SetupIdt()\n");
340 WinLdrSetProcessorContext(void)
342 TRACE("WinLdrSetProcessorContext\n");
344 /* Disable Interrupts */
347 /* Re-initialize EFLAGS */
350 /* Set the new PML4 */
351 __writecr3((ULONG64
)PxeBase
);
353 /* Get kernel mode address of gdt / idt */
354 GdtIdt
= (PVOID
)((ULONG64
)GdtIdt
+ KSEG0_BASE
);
356 /* Create gdt entries and load gdtr */
357 Amd64SetupGdt(GdtIdt
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
359 /* Copy old Idt and set idtr */
360 Amd64SetupIdt((PVOID
)((ULONG64
)GdtIdt
+ NUM_GDT
* sizeof(KGDTENTRY
)));
366 __ltr(KGDT64_SYS_TSS
);
368 TRACE("leave WinLdrSetProcessorContext\n");
371 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock
)
375 ULONG BlockSize
, NumPages
;
377 LoaderBlock
->u
.I386
.CommonDataArea
= (PVOID
)DbgPrint
; // HACK
378 LoaderBlock
->u
.I386
.MachineType
= MACHINE_TYPE_ISA
;
380 /* Allocate 2 pages for PCR */
381 Pcr
= (ULONG_PTR
)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE
, LoaderStartupPcrPage
);
382 PcrBasePage
= Pcr
>> MM_PAGE_SHIFT
;
385 UiMessageBox("Can't allocate PCR.");
388 RtlZeroMemory((PVOID
)Pcr
, 2 * MM_PAGE_SIZE
);
391 BlockSize
= (sizeof(KTSS
) + MM_PAGE_SIZE
) & ~(MM_PAGE_SIZE
- 1);
392 Tss
= (ULONG_PTR
)MmAllocateMemoryWithType(BlockSize
, LoaderMemoryData
);
393 TssBasePage
= Tss
>> MM_PAGE_SHIFT
;
395 /* Allocate space for new GDT + IDT */
396 BlockSize
= NUM_GDT
* sizeof(KGDTENTRY
) + NUM_IDT
* sizeof(KIDTENTRY
);
397 NumPages
= (BlockSize
+ MM_PAGE_SIZE
- 1) >> MM_PAGE_SHIFT
;
398 GdtIdt
= (PKGDTENTRY
)MmAllocateMemoryWithType(NumPages
* MM_PAGE_SIZE
, LoaderMemoryData
);
401 UiMessageBox("Can't allocate pages for GDT+IDT!");
405 /* Zero newly prepared GDT+IDT */
406 RtlZeroMemory(GdtIdt
, NumPages
<< MM_PAGE_SHIFT
);
408 // Before we start mapping pages, create a block of memory, which will contain
410 if (MempAllocatePageTables() == FALSE
)
415 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
416 WinLdrMapSpecialPages();