2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: freeldr/amd64/wlmemory.c
5 * PURPOSE: Memory related routines
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES ***************************************************************/
16 //extern ULONG LoaderPagesSpanned;
18 #define HYPER_SPACE_ENTRY 0x1EE
20 DBG_DEFAULT_CHANNEL(WINDOWS
);
22 /* GLOBALS ***************************************************************/
24 PHARDWARE_PTE PxeBase
;
25 //PHARDWARE_PTE HalPageTable;
28 ULONG_PTR PcrBasePage
;
29 ULONG_PTR TssBasePage
;
31 /* FUNCTIONS **************************************************************/
34 MempAllocatePageTables()
36 TRACE(">>> MempAllocatePageTables\n");
38 /* Allocate a page for the PML4 */
39 PxeBase
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
42 ERR("failed to allocate PML4\n");
46 // FIXME: Physical PTEs = FirmwareTemporary ?
49 RtlZeroMemory(PxeBase
, PAGE_SIZE
);
51 /* The page tables are located at 0xfffff68000000000
52 * We create a recursive self mapping through all 4 levels at
53 * virtual address 0xfffff6fb7dbedf68 */
54 PxeBase
[VAtoPXI(PXE_BASE
)].Valid
= 1;
55 PxeBase
[VAtoPXI(PXE_BASE
)].Write
= 1;
56 PxeBase
[VAtoPXI(PXE_BASE
)].PageFrameNumber
= PtrToPfn(PxeBase
);
58 // FIXME: map PDE's for hals memory mapping
60 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
);
91 MempMapSinglePage(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
)
93 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
96 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(VirtualAddress
));
97 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(VirtualAddress
));
98 PteBase
= MempGetOrCreatePageDir(PdeBase
, VAtoPDI(VirtualAddress
));
102 ERR("!!!No Dir %p, %p, %p, %p\n", PxeBase
, PpeBase
, PdeBase
, PteBase
);
106 Index
= VAtoPTI(VirtualAddress
);
107 if (PteBase
[Index
].Valid
)
109 ERR("!!!Already mapped %ld\n", Index
);
113 PteBase
[Index
].Valid
= 1;
114 PteBase
[Index
].Write
= 1;
115 PteBase
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
121 MempIsPageMapped(PVOID VirtualAddress
)
123 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
126 Index
= VAtoPXI(VirtualAddress
);
127 if (!PxeBase
[Index
].Valid
)
130 PpeBase
= (PVOID
)((ULONG64
)(PxeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
131 Index
= VAtoPPI(VirtualAddress
);
132 if (!PpeBase
[Index
].Valid
)
135 PdeBase
= (PVOID
)((ULONG64
)(PpeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
136 Index
= VAtoPDI(VirtualAddress
);
137 if (!PdeBase
[Index
].Valid
)
140 PteBase
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
141 Index
= VAtoPTI(VirtualAddress
);
142 if (!PteBase
[Index
].Valid
)
149 MempMapRangeOfPages(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
, PFN_NUMBER cPages
)
153 for (i
= 0; i
< cPages
; i
++)
155 if (!MempMapSinglePage(VirtualAddress
, PhysicalAddress
))
157 ERR("Failed to map page %ld from %p to %p\n",
158 i
, (PVOID
)VirtualAddress
, (PVOID
)PhysicalAddress
);
161 VirtualAddress
+= PAGE_SIZE
;
162 PhysicalAddress
+= PAGE_SIZE
;
168 MempSetupPaging(IN PFN_NUMBER StartPage
,
169 IN PFN_NUMBER NumberOfPages
,
170 IN BOOLEAN KernelMapping
)
172 TRACE(">>> MempSetupPaging(0x%lx, %ld, %p)\n",
173 StartPage
, NumberOfPages
, StartPage
* PAGE_SIZE
+ KSEG0_BASE
);
175 /* Identity mapping */
176 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
,
177 StartPage
* PAGE_SIZE
,
178 NumberOfPages
) != NumberOfPages
)
180 ERR("Failed to map pages %ld, %ld\n",
181 StartPage
, NumberOfPages
);
188 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
+ KSEG0_BASE
,
189 StartPage
* PAGE_SIZE
,
190 NumberOfPages
) != NumberOfPages
)
192 ERR("Failed to map pages %ld, %ld\n",
193 StartPage
, NumberOfPages
);
202 MempUnmapPage(PFN_NUMBER Page
)
204 // TRACE(">>> MempUnmapPage\n");
211 LARGE_INTEGER MsrValue
;
215 TRACE(">>> WinLdrpMapApic\n");
217 /* Check if we have a local APIC */
218 __cpuid((int*)CpuInfo
, 1);
219 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
221 /* If there is no APIC, just return */
224 WARN("No APIC found.\n");
228 /* Read the APIC Address */
229 MsrValue
.QuadPart
= __readmsr(0x1B);
230 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
232 TRACE("Local APIC detected at address 0x%x\n",
236 MempMapSinglePage(APIC_BASE
, APICAddress
);
240 WinLdrMapSpecialPages()
242 PHARDWARE_PTE PpeBase
, PdeBase
;
244 /* Map the PCR page */
245 if (!MempMapSinglePage(KIP0PCRADDRESS
, PcrBasePage
* PAGE_SIZE
))
247 ERR("Could not map PCR @ %lx\n", PcrBasePage
);
251 /* Map KI_USER_SHARED_DATA */
252 if (!MempMapSinglePage(KI_USER_SHARED_DATA
, (PcrBasePage
+1) * PAGE_SIZE
))
254 ERR("Could not map KI_USER_SHARED_DATA\n");
258 /* Map the APIC page */
261 /* Map the page tables for 4 MB HAL address space. */
262 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(MM_HAL_VA_START
));
263 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(MM_HAL_VA_START
));
264 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
));
265 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
+ 2 * 1024 * 1024));
271 Amd64SetupGdt(PVOID GdtBase
, ULONG64 TssBase
)
275 TRACE("Amd64SetupGdt(GdtBase = %p, TssBase = %p)\n", GdtBase
, TssBase
);
277 /* Setup KGDT64_NULL */
278 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_NULL
);
279 *(PULONG64
)Entry
= 0x0000000000000000ULL
;
281 /* Setup KGDT64_R0_CODE */
282 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_CODE
);
283 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
285 /* Setup KGDT64_R0_DATA */
286 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_DATA
);
287 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
289 /* Setup KGDT64_R3_CMCODE */
290 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMCODE
);
291 *(PULONG64
)Entry
= 0x00cffb000000ffffULL
;
293 /* Setup KGDT64_R3_DATA */
294 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_DATA
);
295 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
297 /* Setup KGDT64_R3_CODE */
298 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CODE
);
299 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
301 /* Setup KGDT64_R3_CMTEB */
302 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMTEB
);
303 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
305 /* Setup TSS entry */
306 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_SYS_TSS
);
307 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
309 /* Setup GDT descriptor */
310 GdtDesc
.Base
= GdtBase
;
311 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
313 /* Set the new Gdt */
314 __lgdt(&GdtDesc
.Limit
);
315 TRACE("Leave Amd64SetupGdt()\n");
319 Amd64SetupIdt(PVOID IdtBase
)
321 KDESCRIPTOR IdtDesc
, OldIdt
;
323 TRACE("Amd64SetupIdt(IdtBase = %p)\n", IdtBase
);
326 __sidt(&OldIdt
.Limit
);
328 /* Copy the old IDT */
329 Size
= min(OldIdt
.Limit
+ 1, NUM_IDT
* sizeof(KIDTENTRY
));
330 //RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, Size);
332 /* Setup the new IDT descriptor */
333 IdtDesc
.Base
= IdtBase
;
334 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
336 /* Set the new IDT */
337 __lidt(&IdtDesc
.Limit
);
338 TRACE("Leave Amd64SetupIdt()\n");
342 WinLdrSetProcessorContext(void)
344 TRACE("WinLdrSetProcessorContext\n");
346 /* Disable Interrupts */
349 /* Re-initalize EFLAGS */
352 /* Set the new PML4 */
353 __writecr3((ULONG64
)PxeBase
);
355 /* Get kernel mode address of gdt / idt */
356 GdtIdt
= (PVOID
)((ULONG64
)GdtIdt
+ KSEG0_BASE
);
358 /* Create gdt entries and load gdtr */
359 Amd64SetupGdt(GdtIdt
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
361 /* Copy old Idt and set idtr */
362 Amd64SetupIdt((PVOID
)((ULONG64
)GdtIdt
+ NUM_GDT
* sizeof(KGDTENTRY
)));
368 __ltr(KGDT64_SYS_TSS
);
370 TRACE("leave WinLdrSetProcessorContext\n");
373 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock
)
377 ULONG BlockSize
, NumPages
;
379 LoaderBlock
->u
.I386
.CommonDataArea
= (PVOID
)DbgPrint
; // HACK
380 LoaderBlock
->u
.I386
.MachineType
= MACHINE_TYPE_ISA
;
382 /* Allocate 2 pages for PCR */
383 Pcr
= (ULONG_PTR
)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE
, LoaderStartupPcrPage
);
384 PcrBasePage
= Pcr
>> MM_PAGE_SHIFT
;
387 UiMessageBox("Can't allocate PCR\n");
390 RtlZeroMemory((PVOID
)Pcr
, 2 * MM_PAGE_SIZE
);
393 BlockSize
= (sizeof(KTSS
) + MM_PAGE_SIZE
) & ~(MM_PAGE_SIZE
- 1);
394 Tss
= (ULONG_PTR
)MmAllocateMemoryWithType(BlockSize
, LoaderMemoryData
);
395 TssBasePage
= Tss
>> MM_PAGE_SHIFT
;
397 /* Allocate space for new GDT + IDT */
398 BlockSize
= NUM_GDT
* sizeof(KGDTENTRY
) + NUM_IDT
* sizeof(KIDTENTRY
);
399 NumPages
= (BlockSize
+ MM_PAGE_SIZE
- 1) >> MM_PAGE_SHIFT
;
400 GdtIdt
= (PKGDTENTRY
)MmAllocateMemoryWithType(NumPages
* MM_PAGE_SIZE
, LoaderMemoryData
);
403 UiMessageBox("Can't allocate pages for GDT+IDT!\n");
407 /* Zero newly prepared GDT+IDT */
408 RtlZeroMemory(GdtIdt
, NumPages
<< MM_PAGE_SHIFT
);
410 // Before we start mapping pages, create a block of memory, which will contain
412 if (MempAllocatePageTables() == FALSE
)
417 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
418 WinLdrMapSpecialPages();