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