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
);
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
);
199 MempUnmapPage(PFN_NUMBER Page
)
201 // TRACE(">>> MempUnmapPage\n");
208 LARGE_INTEGER MsrValue
;
212 TRACE(">>> WinLdrpMapApic\n");
214 /* Check if we have a local APIC */
215 __cpuid((int*)CpuInfo
, 1);
216 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
218 /* If there is no APIC, just return */
221 WARN("No APIC found.\n");
225 /* Read the APIC Address */
226 MsrValue
.QuadPart
= __readmsr(0x1B);
227 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
229 TRACE("Local APIC detected at address 0x%x\n",
233 MempMapSinglePage(APIC_BASE
, APICAddress
);
237 WinLdrMapSpecialPages()
239 PHARDWARE_PTE PpeBase
, PdeBase
;
241 /* Map the PCR page */
242 if (!MempMapSinglePage(KIP0PCRADDRESS
, PcrBasePage
* PAGE_SIZE
))
244 ERR("Could not map PCR @ %lx\n", PcrBasePage
);
248 /* Map KI_USER_SHARED_DATA */
249 if (!MempMapSinglePage(KI_USER_SHARED_DATA
, (PcrBasePage
+1) * PAGE_SIZE
))
251 ERR("Could not map KI_USER_SHARED_DATA\n");
255 /* Map the APIC page */
258 /* Map the page tables for 4 MB HAL address space. */
259 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(MM_HAL_VA_START
));
260 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(MM_HAL_VA_START
));
261 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
));
262 MempGetOrCreatePageDir(PdeBase
, VAtoPDI(MM_HAL_VA_START
+ 2 * 1024 * 1024));
268 Amd64SetupGdt(PVOID GdtBase
, ULONG64 TssBase
)
272 TRACE("Amd64SetupGdt(GdtBase = %p, TssBase = %p)\n", GdtBase
, TssBase
);
274 /* Setup KGDT64_NULL */
275 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_NULL
);
276 *(PULONG64
)Entry
= 0x0000000000000000ULL
;
278 /* Setup KGDT64_R0_CODE */
279 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_CODE
);
280 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
282 /* Setup KGDT64_R0_DATA */
283 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R0_DATA
);
284 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
286 /* Setup KGDT64_R3_CMCODE */
287 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMCODE
);
288 *(PULONG64
)Entry
= 0x00cffb000000ffffULL
;
290 /* Setup KGDT64_R3_DATA */
291 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_DATA
);
292 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
294 /* Setup KGDT64_R3_CODE */
295 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CODE
);
296 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
298 /* Setup KGDT64_R3_CMTEB */
299 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_R3_CMTEB
);
300 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
302 /* Setup TSS entry */
303 Entry
= KiGetGdtEntry(GdtBase
, KGDT64_SYS_TSS
);
304 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
306 /* Setup GDT descriptor */
307 GdtDesc
.Base
= GdtBase
;
308 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
310 /* Set the new Gdt */
311 __lgdt(&GdtDesc
.Limit
);
312 TRACE("Leave Amd64SetupGdt()\n");
316 Amd64SetupIdt(PVOID IdtBase
)
318 KDESCRIPTOR IdtDesc
, OldIdt
;
320 TRACE("Amd64SetupIdt(IdtBase = %p)\n", IdtBase
);
323 __sidt(&OldIdt
.Limit
);
325 /* Copy the old IDT */
326 Size
= min(OldIdt
.Limit
+ 1, NUM_IDT
* sizeof(KIDTENTRY
));
327 //RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, Size);
329 /* Setup the new IDT descriptor */
330 IdtDesc
.Base
= IdtBase
;
331 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
333 /* Set the new IDT */
334 __lidt(&IdtDesc
.Limit
);
335 TRACE("Leave Amd64SetupIdt()\n");
339 WinLdrSetProcessorContext(void)
341 TRACE("WinLdrSetProcessorContext\n");
343 /* Disable Interrupts */
346 /* Re-initalize EFLAGS */
349 /* Set the new PML4 */
350 __writecr3((ULONG64
)PxeBase
);
352 /* Get kernel mode address of gdt / idt */
353 GdtIdt
= (PVOID
)((ULONG64
)GdtIdt
+ KSEG0_BASE
);
355 /* Create gdt entries and load gdtr */
356 Amd64SetupGdt(GdtIdt
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
358 /* Copy old Idt and set idtr */
359 Amd64SetupIdt((PVOID
)((ULONG64
)GdtIdt
+ NUM_GDT
* sizeof(KGDTENTRY
)));
365 __ltr(KGDT64_SYS_TSS
);
367 TRACE("leave WinLdrSetProcessorContext\n");
370 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock
)
374 ULONG BlockSize
, NumPages
;
376 LoaderBlock
->u
.I386
.CommonDataArea
= (PVOID
)DbgPrint
; // HACK
377 LoaderBlock
->u
.I386
.MachineType
= MACHINE_TYPE_ISA
;
379 /* Allocate 2 pages for PCR */
380 Pcr
= (ULONG_PTR
)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE
, LoaderStartupPcrPage
);
381 PcrBasePage
= Pcr
>> MM_PAGE_SHIFT
;
384 UiMessageBox("Can't allocate PCR\n");
387 RtlZeroMemory((PVOID
)Pcr
, 2 * MM_PAGE_SIZE
);
390 BlockSize
= (sizeof(KTSS
) + MM_PAGE_SIZE
) & ~(MM_PAGE_SIZE
- 1);
391 Tss
= (ULONG_PTR
)MmAllocateMemoryWithType(BlockSize
, LoaderMemoryData
);
392 TssBasePage
= Tss
>> MM_PAGE_SHIFT
;
394 /* Allocate space for new GDT + IDT */
395 BlockSize
= NUM_GDT
* sizeof(KGDTENTRY
) + NUM_IDT
* sizeof(KIDTENTRY
);
396 NumPages
= (BlockSize
+ MM_PAGE_SIZE
- 1) >> MM_PAGE_SHIFT
;
397 GdtIdt
= (PKGDTENTRY
)MmAllocateMemoryWithType(NumPages
* MM_PAGE_SIZE
, LoaderMemoryData
);
400 UiMessageBox("Can't allocate pages for GDT+IDT!\n");
404 /* Zero newly prepared GDT+IDT */
405 RtlZeroMemory(GdtIdt
, NumPages
<< MM_PAGE_SHIFT
);
407 // Before we start mapping pages, create a block of memory, which will contain
409 if (MempAllocatePageTables() == FALSE
)
414 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
415 WinLdrMapSpecialPages();