[THEMES]
[reactos.git] / reactos / boot / freeldr / freeldr / arch / amd64 / winldr.c
1 /*
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)
7 */
8
9 /* INCLUDES ***************************************************************/
10
11 #include <freeldr.h>
12
13 #include <ndk/asm.h>
14 #include <debug.h>
15
16 //extern ULONG LoaderPagesSpanned;
17
18 #define HYPER_SPACE_ENTRY 0x1EE
19
20 DBG_DEFAULT_CHANNEL(WINDOWS);
21
22 /* GLOBALS ***************************************************************/
23
24 PHARDWARE_PTE PxeBase;
25 //PHARDWARE_PTE HalPageTable;
26
27 PVOID GdtIdt;
28 ULONG_PTR PcrBasePage;
29 ULONG_PTR TssBasePage;
30
31 /* FUNCTIONS **************************************************************/
32
33 BOOLEAN
34 MempAllocatePageTables()
35 {
36 TRACE(">>> MempAllocatePageTables\n");
37
38 /* Allocate a page for the PML4 */
39 PxeBase = MmAllocateMemoryWithType(PAGE_SIZE, LoaderMemoryData);
40 if (!PxeBase)
41 {
42 ERR("failed to allocate PML4\n");
43 return FALSE;
44 }
45
46 // FIXME: Physical PTEs = FirmwareTemporary ?
47
48 /* Zero the PML4 */
49 RtlZeroMemory(PxeBase, PAGE_SIZE);
50
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);
57
58 // FIXME: map PDE's for hals memory mapping
59
60 TRACE(">>> leave MempAllocatePageTables\n");
61
62 return TRUE;
63 }
64
65 PHARDWARE_PTE
66 MempGetOrCreatePageDir(PHARDWARE_PTE PdeBase, ULONG Index)
67 {
68 PHARDWARE_PTE SubDir;
69
70 if (!PdeBase)
71 return NULL;
72
73 if (!PdeBase[Index].Valid)
74 {
75 SubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderMemoryData);
76 if (!SubDir)
77 return NULL;
78 RtlZeroMemory(SubDir, PAGE_SIZE);
79 PdeBase[Index].PageFrameNumber = PtrToPfn(SubDir);
80 PdeBase[Index].Valid = 1;
81 PdeBase[Index].Write = 1;
82 }
83 else
84 {
85 SubDir = (PVOID)((ULONG64)(PdeBase[Index].PageFrameNumber) * PAGE_SIZE);
86 }
87 return SubDir;
88 }
89
90 BOOLEAN
91 MempMapSinglePage(ULONG64 VirtualAddress, ULONG64 PhysicalAddress)
92 {
93 PHARDWARE_PTE PpeBase, PdeBase, PteBase;
94 ULONG Index;
95
96 PpeBase = MempGetOrCreatePageDir(PxeBase, VAtoPXI(VirtualAddress));
97 PdeBase = MempGetOrCreatePageDir(PpeBase, VAtoPPI(VirtualAddress));
98 PteBase = MempGetOrCreatePageDir(PdeBase, VAtoPDI(VirtualAddress));
99
100 if (!PteBase)
101 {
102 ERR("!!!No Dir %p, %p, %p, %p\n", PxeBase, PpeBase, PdeBase, PteBase);
103 return FALSE;
104 }
105
106 Index = VAtoPTI(VirtualAddress);
107 if (PteBase[Index].Valid)
108 {
109 ERR("!!!Already mapped %ld\n", Index);
110 return FALSE;
111 }
112
113 PteBase[Index].Valid = 1;
114 PteBase[Index].Write = 1;
115 PteBase[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
116
117 return TRUE;
118 }
119
120 BOOLEAN
121 MempIsPageMapped(PVOID VirtualAddress)
122 {
123 PHARDWARE_PTE PpeBase, PdeBase, PteBase;
124 ULONG Index;
125
126 Index = VAtoPXI(VirtualAddress);
127 if (!PxeBase[Index].Valid)
128 return FALSE;
129
130 PpeBase = (PVOID)((ULONG64)(PxeBase[Index].PageFrameNumber) * PAGE_SIZE);
131 Index = VAtoPPI(VirtualAddress);
132 if (!PpeBase[Index].Valid)
133 return FALSE;
134
135 PdeBase = (PVOID)((ULONG64)(PpeBase[Index].PageFrameNumber) * PAGE_SIZE);
136 Index = VAtoPDI(VirtualAddress);
137 if (!PdeBase[Index].Valid)
138 return FALSE;
139
140 PteBase = (PVOID)((ULONG64)(PdeBase[Index].PageFrameNumber) * PAGE_SIZE);
141 Index = VAtoPTI(VirtualAddress);
142 if (!PteBase[Index].Valid)
143 return FALSE;
144
145 return TRUE;
146 }
147
148 PFN_NUMBER
149 MempMapRangeOfPages(ULONG64 VirtualAddress, ULONG64 PhysicalAddress, PFN_NUMBER cPages)
150 {
151 PFN_NUMBER i;
152
153 for (i = 0; i < cPages; i++)
154 {
155 if (!MempMapSinglePage(VirtualAddress, PhysicalAddress))
156 {
157 ERR("Failed to map page %ld from %p to %p\n",
158 i, (PVOID)VirtualAddress, (PVOID)PhysicalAddress);
159 return i;
160 }
161 VirtualAddress += PAGE_SIZE;
162 PhysicalAddress += PAGE_SIZE;
163 }
164 return i;
165 }
166
167 BOOLEAN
168 MempSetupPaging(IN PFN_NUMBER StartPage,
169 IN PFN_NUMBER NumberOfPages,
170 IN BOOLEAN KernelMapping)
171 {
172 TRACE(">>> MempSetupPaging(0x%lx, %ld, %p)\n",
173 StartPage, NumberOfPages, StartPage * PAGE_SIZE + KSEG0_BASE);
174
175 /* Identity mapping */
176 if (MempMapRangeOfPages(StartPage * PAGE_SIZE,
177 StartPage * PAGE_SIZE,
178 NumberOfPages) != NumberOfPages)
179 {
180 ERR("Failed to map pages %ld, %ld\n",
181 StartPage, NumberOfPages);
182 return FALSE;
183 }
184
185 /* Kernel mapping */
186 if (KernelMapping)
187 {
188 if (MempMapRangeOfPages(StartPage * PAGE_SIZE + KSEG0_BASE,
189 StartPage * PAGE_SIZE,
190 NumberOfPages) != NumberOfPages)
191 {
192 ERR("Failed to map pages %ld, %ld\n",
193 StartPage, NumberOfPages);
194 return FALSE;
195 }
196 }
197
198 return TRUE;
199 }
200
201 VOID
202 MempUnmapPage(PFN_NUMBER Page)
203 {
204 // TRACE(">>> MempUnmapPage\n");
205 }
206
207 VOID
208 WinLdrpMapApic()
209 {
210 BOOLEAN LocalAPIC;
211 LARGE_INTEGER MsrValue;
212 ULONG CpuInfo[4];
213 ULONG64 APICAddress;
214
215 TRACE(">>> WinLdrpMapApic\n");
216
217 /* Check if we have a local APIC */
218 __cpuid((int*)CpuInfo, 1);
219 LocalAPIC = (((CpuInfo[3] >> 9) & 1) != 0);
220
221 /* If there is no APIC, just return */
222 if (!LocalAPIC)
223 {
224 WARN("No APIC found.\n");
225 return;
226 }
227
228 /* Read the APIC Address */
229 MsrValue.QuadPart = __readmsr(0x1B);
230 APICAddress = (MsrValue.LowPart & 0xFFFFF000);
231
232 TRACE("Local APIC detected at address 0x%x\n",
233 APICAddress);
234
235 /* Map it */
236 MempMapSinglePage(APIC_BASE, APICAddress);
237 }
238
239 BOOLEAN
240 WinLdrMapSpecialPages()
241 {
242 PHARDWARE_PTE PpeBase, PdeBase;
243
244 /* Map the PCR page */
245 if (!MempMapSinglePage(KIP0PCRADDRESS, PcrBasePage * PAGE_SIZE))
246 {
247 ERR("Could not map PCR @ %lx\n", PcrBasePage);
248 return FALSE;
249 }
250
251 /* Map KI_USER_SHARED_DATA */
252 if (!MempMapSinglePage(KI_USER_SHARED_DATA, (PcrBasePage+1) * PAGE_SIZE))
253 {
254 ERR("Could not map KI_USER_SHARED_DATA\n");
255 return FALSE;
256 }
257
258 /* Map the APIC page */
259 WinLdrpMapApic();
260
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));
266
267 return TRUE;
268 }
269
270 VOID
271 Amd64SetupGdt(PVOID GdtBase, ULONG64 TssBase)
272 {
273 PKGDTENTRY64 Entry;
274 KDESCRIPTOR GdtDesc;
275 TRACE("Amd64SetupGdt(GdtBase = %p, TssBase = %p)\n", GdtBase, TssBase);
276
277 /* Setup KGDT64_NULL */
278 Entry = KiGetGdtEntry(GdtBase, KGDT64_NULL);
279 *(PULONG64)Entry = 0x0000000000000000ULL;
280
281 /* Setup KGDT64_R0_CODE */
282 Entry = KiGetGdtEntry(GdtBase, KGDT64_R0_CODE);
283 *(PULONG64)Entry = 0x00209b0000000000ULL;
284
285 /* Setup KGDT64_R0_DATA */
286 Entry = KiGetGdtEntry(GdtBase, KGDT64_R0_DATA);
287 *(PULONG64)Entry = 0x00cf93000000ffffULL;
288
289 /* Setup KGDT64_R3_CMCODE */
290 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CMCODE);
291 *(PULONG64)Entry = 0x00cffb000000ffffULL;
292
293 /* Setup KGDT64_R3_DATA */
294 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_DATA);
295 *(PULONG64)Entry = 0x00cff3000000ffffULL;
296
297 /* Setup KGDT64_R3_CODE */
298 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CODE);
299 *(PULONG64)Entry = 0x0020fb0000000000ULL;
300
301 /* Setup KGDT64_R3_CMTEB */
302 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CMTEB);
303 *(PULONG64)Entry = 0xff40f3fd50003c00ULL;
304
305 /* Setup TSS entry */
306 Entry = KiGetGdtEntry(GdtBase, KGDT64_SYS_TSS);
307 KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
308
309 /* Setup GDT descriptor */
310 GdtDesc.Base = GdtBase;
311 GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
312
313 /* Set the new Gdt */
314 __lgdt(&GdtDesc.Limit);
315 TRACE("Leave Amd64SetupGdt()\n");
316 }
317
318 VOID
319 Amd64SetupIdt(PVOID IdtBase)
320 {
321 KDESCRIPTOR IdtDesc, OldIdt;
322 ULONG Size;
323 TRACE("Amd64SetupIdt(IdtBase = %p)\n", IdtBase);
324
325 /* Get old IDT */
326 __sidt(&OldIdt.Limit);
327
328 /* Copy the old IDT */
329 Size = min(OldIdt.Limit + 1, NUM_IDT * sizeof(KIDTENTRY));
330 //RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, Size);
331
332 /* Setup the new IDT descriptor */
333 IdtDesc.Base = IdtBase;
334 IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
335
336 /* Set the new IDT */
337 __lidt(&IdtDesc.Limit);
338 TRACE("Leave Amd64SetupIdt()\n");
339 }
340
341 VOID
342 WinLdrSetProcessorContext(void)
343 {
344 TRACE("WinLdrSetProcessorContext\n");
345
346 /* Disable Interrupts */
347 _disable();
348
349 /* Re-initalize EFLAGS */
350 __writeeflags(0);
351
352 /* Set the new PML4 */
353 __writecr3((ULONG64)PxeBase);
354
355 /* Get kernel mode address of gdt / idt */
356 GdtIdt = (PVOID)((ULONG64)GdtIdt + KSEG0_BASE);
357
358 /* Create gdt entries and load gdtr */
359 Amd64SetupGdt(GdtIdt, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
360
361 /* Copy old Idt and set idtr */
362 Amd64SetupIdt((PVOID)((ULONG64)GdtIdt + NUM_GDT * sizeof(KGDTENTRY)));
363
364 /* LDT is unused */
365 // __lldt(0);
366
367 /* Load TSR */
368 __ltr(KGDT64_SYS_TSS);
369
370 TRACE("leave WinLdrSetProcessorContext\n");
371 }
372
373 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock)
374 {
375 ULONG_PTR Pcr = 0;
376 ULONG_PTR Tss = 0;
377 ULONG BlockSize, NumPages;
378
379 LoaderBlock->u.I386.CommonDataArea = (PVOID)DbgPrint; // HACK
380 LoaderBlock->u.I386.MachineType = MACHINE_TYPE_ISA;
381
382 /* Allocate 2 pages for PCR */
383 Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage);
384 PcrBasePage = Pcr >> MM_PAGE_SHIFT;
385 if (Pcr == 0)
386 {
387 UiMessageBox("Can't allocate PCR\n");
388 return;
389 }
390 RtlZeroMemory((PVOID)Pcr, 2 * MM_PAGE_SIZE);
391
392 /* Allocate TSS */
393 BlockSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1);
394 Tss = (ULONG_PTR)MmAllocateMemoryWithType(BlockSize, LoaderMemoryData);
395 TssBasePage = Tss >> MM_PAGE_SHIFT;
396
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);
401 if (GdtIdt == NULL)
402 {
403 UiMessageBox("Can't allocate pages for GDT+IDT!\n");
404 return;
405 }
406
407 /* Zero newly prepared GDT+IDT */
408 RtlZeroMemory(GdtIdt, NumPages << MM_PAGE_SHIFT);
409
410 // Before we start mapping pages, create a block of memory, which will contain
411 // PDE and PTEs
412 if (MempAllocatePageTables() == FALSE)
413 {
414 // FIXME: bugcheck
415 }
416
417 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
418 WinLdrMapSpecialPages();
419 }
420
421
422 VOID
423 MempDump()
424 {
425 }
426