3e3288a682a9aa3c0c4b569fde0a83cd44638d18
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 /* GLOBALS ***************************************************************/
22 PHARDWARE_PTE PxeBase
;
23 //PHARDWARE_PTE HalPageTable;
26 /* FUNCTIONS **************************************************************/
29 MempAllocatePageTables()
31 DPRINTM(DPRINT_WINDOWS
,">>> MempAllocatePageTables\n");
33 /* Allocate a page for the PML4 */
34 PxeBase
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
37 DPRINTM(DPRINT_WINDOWS
,"failed to allocate PML4\n");
41 // FIXME: Physical PTEs = FirmwareTemporary ?
44 RtlZeroMemory(PxeBase
, PAGE_SIZE
);
46 /* The page tables are located at 0xfffff68000000000
47 * We create a recursive self mapping through all 4 levels at
48 * virtual address 0xfffff6fb7dbedf68 */
49 PxeBase
[VAtoPXI(PXE_BASE
)].Valid
= 1;
50 PxeBase
[VAtoPXI(PXE_BASE
)].Write
= 1;
51 PxeBase
[VAtoPXI(PXE_BASE
)].PageFrameNumber
= PtrToPfn(PxeBase
);
53 // FIXME: map PDE's for hals memory mapping
55 DPRINTM(DPRINT_WINDOWS
,">>> leave MempAllocatePageTables\n");
61 MempGetOrCreatePageDir(PHARDWARE_PTE PdeBase
, ULONG Index
)
68 if (!PdeBase
[Index
].Valid
)
70 SubDir
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderMemoryData
);
73 RtlZeroMemory(SubDir
, PAGE_SIZE
);
74 PdeBase
[Index
].PageFrameNumber
= PtrToPfn(SubDir
);
75 PdeBase
[Index
].Valid
= 1;
76 PdeBase
[Index
].Write
= 1;
80 SubDir
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
86 MempMapSinglePage(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
)
88 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
91 PpeBase
= MempGetOrCreatePageDir(PxeBase
, VAtoPXI(VirtualAddress
));
92 PdeBase
= MempGetOrCreatePageDir(PpeBase
, VAtoPPI(VirtualAddress
));
93 PteBase
= MempGetOrCreatePageDir(PdeBase
, VAtoPDI(VirtualAddress
));
97 DPRINTM(DPRINT_WINDOWS
,"!!!No Dir %p, %p, %p, %p\n", PxeBase
, PpeBase
, PdeBase
, PteBase
);
101 Index
= VAtoPTI(VirtualAddress
);
102 if (PteBase
[Index
].Valid
)
104 DPRINTM(DPRINT_WINDOWS
,"!!!Already mapped %ld\n", Index
);
108 PteBase
[Index
].Valid
= 1;
109 PteBase
[Index
].Write
= 1;
110 PteBase
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
116 MempIsPageMapped(PVOID VirtualAddress
)
118 PHARDWARE_PTE PpeBase
, PdeBase
, PteBase
;
121 Index
= VAtoPXI(VirtualAddress
);
122 if (!PxeBase
[Index
].Valid
)
125 PpeBase
= (PVOID
)((ULONG64
)(PxeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
126 Index
= VAtoPPI(VirtualAddress
);
127 if (!PpeBase
[Index
].Valid
)
130 PdeBase
= (PVOID
)((ULONG64
)(PpeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
131 Index
= VAtoPDI(VirtualAddress
);
132 if (!PdeBase
[Index
].Valid
)
135 PteBase
= (PVOID
)((ULONG64
)(PdeBase
[Index
].PageFrameNumber
) * PAGE_SIZE
);
136 Index
= VAtoPTI(VirtualAddress
);
137 if (!PteBase
[Index
].Valid
)
144 MempMapRangeOfPages(ULONG64 VirtualAddress
, ULONG64 PhysicalAddress
, ULONG cPages
)
148 for (i
= 0; i
< cPages
; i
++)
150 if (!MempMapSinglePage(VirtualAddress
, PhysicalAddress
))
154 VirtualAddress
+= PAGE_SIZE
;
155 PhysicalAddress
+= PAGE_SIZE
;
161 MempSetupPaging(IN ULONG StartPage
,
162 IN ULONG NumberOfPages
)
164 DPRINTM(DPRINT_WINDOWS
,">>> MempSetupPaging(0x%lx, %ld, %p)\n",
165 StartPage
, NumberOfPages
, StartPage
* PAGE_SIZE
+ KSEG0_BASE
);
167 /* Identity mapping */
168 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
,
169 StartPage
* PAGE_SIZE
,
170 NumberOfPages
) != NumberOfPages
)
172 DPRINTM(DPRINT_WINDOWS
,"Failed to map pages 1\n");
177 if (MempMapRangeOfPages(StartPage
* PAGE_SIZE
+ KSEG0_BASE
,
178 StartPage
* PAGE_SIZE
,
179 NumberOfPages
) != NumberOfPages
)
181 DPRINTM(DPRINT_WINDOWS
,"Failed to map pages 2\n");
189 MempUnmapPage(ULONG Page
)
191 // DPRINTM(DPRINT_WINDOWS,">>> MempUnmapPage\n");
198 LARGE_INTEGER MsrValue
;
202 DPRINTM(DPRINT_WINDOWS
,">>> WinLdrpMapApic\n");
204 /* Check if we have a local APIC */
205 __cpuid((int*)CpuInfo
, 1);
206 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
208 /* If there is no APIC, just return */
211 DPRINTM(DPRINT_WINDOWS
,"No APIC found.\n");
215 /* Read the APIC Address */
216 MsrValue
.QuadPart
= __readmsr(0x1B);
217 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
219 DPRINTM(DPRINT_WINDOWS
, "Local APIC detected at address 0x%x\n",
223 MempMapSinglePage(APIC_BASE
, APICAddress
);
227 WinLdrMapSpecialPages(ULONG PcrBasePage
)
229 /* Map the PCR page */
230 if (!MempMapSinglePage(KIP0PCRADDRESS
, PcrBasePage
* PAGE_SIZE
))
232 DPRINTM(DPRINT_WINDOWS
, "Could not map PCR @ %lx\n", PcrBasePage
);
236 /* Map KI_USER_SHARED_DATA */
237 if (!MempMapSinglePage(KI_USER_SHARED_DATA
, (PcrBasePage
+1) * PAGE_SIZE
))
239 DPRINTM(DPRINT_WINDOWS
, "Could not map KI_USER_SHARED_DATA\n");
243 /* Map the APIC page */
250 WinLdrSetupGdt(PVOID GdtBase
, ULONG64 TssBase
)
255 /* Setup KGDT_64_R0_CODE */
256 Entry
= KiGetGdtEntry(GdtBase
, KGDT_64_R0_CODE
);
257 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
259 /* Setup KGDT_64_R0_SS */
260 Entry
= KiGetGdtEntry(GdtBase
, KGDT_64_R0_SS
);
261 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
263 /* Setup KGDT_64_DATA */
264 Entry
= KiGetGdtEntry(GdtBase
, KGDT_64_DATA
);
265 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
267 /* Setup KGDT_64_R3_CODE */
268 Entry
= KiGetGdtEntry(GdtBase
, KGDT_64_R3_CODE
);
269 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
271 /* Setup KGDT_32_R3_TEB */
272 Entry
= KiGetGdtEntry(GdtBase
, KGDT_32_R3_TEB
);
273 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
275 /* Setup TSS entry */
276 Entry
= KiGetGdtEntry(GdtBase
, KGDT_TSS
);
277 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
279 /* Setup GDT descriptor */
280 GdtDesc
.Base
= GdtBase
;
281 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
283 /* Set the new Gdt */
284 __lgdt(&GdtDesc
.Limit
);
285 DbgPrint("Gdtr.Base = %p, num = %ld\n", GdtDesc
.Base
, NUM_GDT
);
290 WinLdrSetupIdt(PVOID IdtBase
)
292 KDESCRIPTOR IdtDesc
, OldIdt
;
297 /* Copy the old IDT */
298 RtlCopyMemory(IdtBase
, (PVOID
)OldIdt
.Base
, OldIdt
.Limit
+ 1);
300 /* Setup the new IDT descriptor */
301 IdtDesc
.Base
= IdtBase
;
302 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
304 /* Set the new IDT */
305 __lidt(&IdtDesc
.Limit
);
306 DbgPrint("Idtr.Base = %p\n", IdtDesc
.Base
);
311 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG64 Pcr
, IN ULONG64 Tss
)
313 DPRINTM(DPRINT_WINDOWS
, "WinLdrSetProcessorContext %p\n", Pcr
);
315 /* Disable Interrupts */
318 /* Re-initalize EFLAGS */
321 /* Set the new PML4 */
322 __writecr3((ULONG64
)PxeBase
);
324 /* Get kernel mode address of gdt / idt */
325 GdtIdt
= (PVOID
)((ULONG64
)GdtIdt
+ KSEG0_BASE
);
327 /* Create gdt entries and load gdtr */
328 WinLdrSetupGdt(GdtIdt
, Tss
);
330 /* Copy old Idt and set idtr */
331 WinLdrSetupIdt((PVOID
)((ULONG64
)GdtIdt
+ 2048)); // HACK!
336 /* Load selectors for DS/ES/FS/GS/SS */
337 Ke386SetDs(KGDT_64_DATA
| RPL_MASK
); // 0x2b
338 Ke386SetEs(KGDT_64_DATA
| RPL_MASK
); // 0x2b
339 Ke386SetFs(KGDT_32_R3_TEB
| RPL_MASK
); // 0x53
340 Ke386SetGs(KGDT_64_DATA
| RPL_MASK
); // 0x2b
341 Ke386SetSs(KGDT_64_R0_SS
); // 0x18
346 DPRINTM(DPRINT_WINDOWS
, "leave WinLdrSetProcessorContext\n");