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 **************************************************************/
33 MempAllocatePageTables(VOID
)
35 TRACE(">>> MempAllocatePageTables\n");
37 /* Allocate a page for the PML4 */
38 PxeBase
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
41 ERR("failed to allocate PML4\n");
45 // FIXME: Physical PTEs = FirmwareTemporary ?
48 RtlZeroMemory(PxeBase
, PAGE_SIZE
);
50 /* The page tables are located at 0xfffff68000000000
51 * We create a recursive self mapping through all 4 levels at
52 * virtual address 0xfffff6fb7dbedf68 */
53 PxeBase
[VAtoPXI(PXE_BASE
)].Valid
= 1;
54 PxeBase
[VAtoPXI(PXE_BASE
)].Write
= 1;
55 PxeBase
[VAtoPXI(PXE_BASE
)].PageFrameNumber
= PtrToPfn(PxeBase
);
57 // FIXME: map PDE's for hals memory mapping
59 TRACE(">>> leave MempAllocatePageTables\n");
66 MempGetOrCreatePageDir(PHARDWARE_PTE PdeBase
, ULONG Index
)
73 if (!PdeBase
[Index
].Valid
)
75 SubDir
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
78 RtlZeroMemory(SubDir
, PAGE_SIZE
);
79 PdeBase
[Index
].PageFrameNumber
= PtrToPfn(SubDir
);
80 PdeBase
[Index
].Valid
= 1;
81 PdeBase
[Index
].Write
= 1;
85 SubDir
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
92 MempMapSinglePage(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
)
94 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
97 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(VirtualAddress
));
98 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(VirtualAddress
));
99 PteBase
= MempGetOrCreatePageDir(PdeBase
, VAtoPDI(VirtualAddress
));
103 ERR("!!!No Dir %p, %p, %p, %p\n", PxeBase
, PpeBase
, PdeBase
, PteBase
);
107 Index
= VAtoPTI(VirtualAddress
);
108 if (PteBase
[Index
].Valid
)
110 ERR("!!!Already mapped %ld\n", Index
);
114 PteBase
[Index
].Valid
= 1;
115 PteBase
[Index
].Write
= 1;
116 PteBase
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
122 MempIsPageMapped(PVOID VirtualAddress
)
124 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
127 Index
= VAtoPXI(VirtualAddress
);
128 if (!PxeBase
[Index
].Valid
)
131 PpeBase
= (PVOID
)((ULONG64
)(PxeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
132 Index
= VAtoPPI(VirtualAddress
);
133 if (!PpeBase
[Index
].Valid
)
136 PdeBase
= (PVOID
)((ULONG64
)(PpeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
137 Index
= VAtoPDI(VirtualAddress
);
138 if (!PdeBase
[Index
].Valid
)
141 PteBase
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
142 Index
= VAtoPTI(VirtualAddress
);
143 if (!PteBase
[Index
].Valid
)
151 MempMapRangeOfPages(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
, PFN_NUMBER cPages
)
155 for (i
= 0; i
< cPages
; i
++)
157 if (!MempMapSinglePage(VirtualAddress
, PhysicalAddress
))
159 ERR("Failed to map page %ld from %p to %p\n",
160 i
, (PVOID
)VirtualAddress
, (PVOID
)PhysicalAddress
);
163 VirtualAddress
+= PAGE_SIZE
;
164 PhysicalAddress
+= PAGE_SIZE
;
170 MempSetupPaging(IN PFN_NUMBER StartPage
,
171 IN PFN_NUMBER NumberOfPages
,
172 IN BOOLEAN KernelMapping
)
174 TRACE(">>> MempSetupPaging(0x%lx, %ld, %p)\n",
175 StartPage
, NumberOfPages
, StartPage
* PAGE_SIZE
+ KSEG0_BASE
);
177 /* Identity mapping */
178 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
,
179 StartPage
* PAGE_SIZE
,
180 NumberOfPages
) != NumberOfPages
)
182 ERR("Failed to map pages %ld, %ld\n",
183 StartPage
, NumberOfPages
);
190 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
+ KSEG0_BASE
,
191 StartPage
* PAGE_SIZE
,
192 NumberOfPages
) != NumberOfPages
)
194 ERR("Failed to map pages %ld, %ld\n",
195 StartPage
, NumberOfPages
);
204 MempUnmapPage(PFN_NUMBER Page
)
206 // TRACE(">>> MempUnmapPage\n");
214 LARGE_INTEGER MsrValue
;
218 TRACE(">>> WinLdrpMapApic\n");
220 /* Check if we have a local APIC */
221 __cpuid((int*)CpuInfo
, 1);
222 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
224 /* If there is no APIC, just return */
227 WARN("No APIC found.\n");
231 /* Read the APIC Address */
232 MsrValue
.QuadPart
= __readmsr(0x1B);
233 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
235 TRACE("Local APIC detected at address 0x%x\n",
239 MempMapSinglePage(APIC_BASE
, APICAddress
);
244 WinLdrMapSpecialPages(VOID
)
246 PHARDWARE_PTE PpeBase
, PdeBase
;
248 /* Map the PCR page */
249 if (!MempMapSinglePage(KIP0PCRADDRESS
, PcrBasePage
* PAGE_SIZE
))
251 ERR("Could not map PCR @ %lx\n", PcrBasePage
);
255 /* Map KI_USER_SHARED_DATA */
256 if (!MempMapSinglePage(KI_USER_SHARED_DATA
, (PcrBasePage
+1) * PAGE_SIZE
))
258 ERR("Could not map KI_USER_SHARED_DATA\n");
262 /* Map the APIC page */
265 /* Map the page tables for 4 MB HAL address space. */
266 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(MM_HAL_VA_START
));
267 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(MM_HAL_VA_START
));
268 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
));
269 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
+ 2 * 1024 * 1024));
276 Amd64SetupGdt(PVOID GdtBase
, ULONG64 TssBase
)
280 TRACE("Amd64SetupGdt(GdtBase = %p, TssBase = %p)\n", GdtBase
, TssBase
);
282 /* Setup KGDT64_NULL */
283 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_NULL
);
284 *(PULONG64
)Entry
= 0x0000000000000000ULL
;
286 /* Setup KGDT64_R0_CODE */
287 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_CODE
);
288 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
290 /* Setup KGDT64_R0_DATA */
291 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_DATA
);
292 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
294 /* Setup KGDT64_R3_CMCODE */
295 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMCODE
);
296 *(PULONG64
)Entry
= 0x00cffb000000ffffULL
;
298 /* Setup KGDT64_R3_DATA */
299 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_DATA
);
300 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
302 /* Setup KGDT64_R3_CODE */
303 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CODE
);
304 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
306 /* Setup KGDT64_R3_CMTEB */
307 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMTEB
);
308 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
310 /* Setup TSS entry */
311 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_SYS_TSS
);
312 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
314 /* Setup GDT descriptor */
315 GdtDesc
.Base
= GdtBase
;
316 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
318 /* Set the new Gdt */
319 __lgdt(&GdtDesc
.Limit
);
320 TRACE("Leave Amd64SetupGdt()\n");
325 Amd64SetupIdt(PVOID IdtBase
)
327 KDESCRIPTOR IdtDesc
, OldIdt
;
329 TRACE("Amd64SetupIdt(IdtBase = %p)\n", IdtBase
);
332 __sidt(&OldIdt
.Limit
);
334 /* Copy the old IDT */
335 Size
= min(OldIdt
.Limit
+ 1, NUM_IDT
* sizeof(KIDTENTRY
));
336 //RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, Size);
338 /* Setup the new IDT descriptor */
339 IdtDesc
.Base
= IdtBase
;
340 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
342 /* Set the new IDT */
343 __lidt(&IdtDesc
.Limit
);
344 TRACE("Leave Amd64SetupIdt()\n");
348 WinLdrSetProcessorContext(void)
350 TRACE("WinLdrSetProcessorContext\n");
352 /* Disable Interrupts */
355 /* Re-initialize EFLAGS */
358 /* Set the new PML4 */
359 __writecr3((ULONG64
)PxeBase
);
361 /* Get kernel mode address of gdt / idt */
362 GdtIdt
= (PVOID
)((ULONG64
)GdtIdt
+ KSEG0_BASE
);
364 /* Create gdt entries and load gdtr */
365 Amd64SetupGdt(GdtIdt
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
367 /* Copy old Idt and set idtr */
368 Amd64SetupIdt((PVOID
)((ULONG64
)GdtIdt
+ NUM_GDT
* sizeof(KGDTENTRY
)));
374 __ltr(KGDT64_SYS_TSS
);
376 TRACE("leave WinLdrSetProcessorContext\n");
379 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock
)
383 ULONG BlockSize
, NumPages
;
385 LoaderBlock
->u
.I386
.CommonDataArea
= (PVOID
)DbgPrint
; // HACK
386 LoaderBlock
->u
.I386
.MachineType
= MACHINE_TYPE_ISA
;
388 /* Allocate 2 pages for PCR */
389 Pcr
= (ULONG_PTR
)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE
, LoaderStartupPcrPage
);
390 PcrBasePage
= Pcr
>> MM_PAGE_SHIFT
;
393 UiMessageBox("Can't allocate PCR.");
396 RtlZeroMemory((PVOID
)Pcr
, 2 * MM_PAGE_SIZE
);
399 BlockSize
= (sizeof(KTSS
) + MM_PAGE_SIZE
) & ~(MM_PAGE_SIZE
- 1);
400 Tss
= (ULONG_PTR
)MmAllocateMemoryWithType(BlockSize
, LoaderMemoryData
);
401 TssBasePage
= Tss
>> MM_PAGE_SHIFT
;
403 /* Allocate space for new GDT + IDT */
404 BlockSize
= NUM_GDT
* sizeof(KGDTENTRY
) + NUM_IDT
* sizeof(KIDTENTRY
);
405 NumPages
= (BlockSize
+ MM_PAGE_SIZE
- 1) >> MM_PAGE_SHIFT
;
406 GdtIdt
= (PKGDTENTRY
)MmAllocateMemoryWithType(NumPages
* MM_PAGE_SIZE
, LoaderMemoryData
);
409 UiMessageBox("Can't allocate pages for GDT+IDT!");
413 /* Zero newly prepared GDT+IDT */
414 RtlZeroMemory(GdtIdt
, NumPages
<< MM_PAGE_SHIFT
);
416 // Before we start mapping pages, create a block of memory, which will contain
418 if (MempAllocatePageTables() == FALSE
)
423 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
424 WinLdrMapSpecialPages();