[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / windows / amd64 / wlmemory.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 /* GLOBALS ***************************************************************/
21
22 PHARDWARE_PTE PxeBase;
23 //PHARDWARE_PTE HalPageTable;
24
25
26 /* FUNCTIONS **************************************************************/
27
28 BOOLEAN
29 MempAllocatePageTables()
30 {
31 DPRINTM(DPRINT_WINDOWS,">>> MempAllocatePageTables\n");
32
33 /* Allocate a page for the PML4 */
34 PxeBase = MmAllocateMemoryWithType(PAGE_SIZE, LoaderMemoryData);
35 if (!PxeBase)
36 {
37 DPRINTM(DPRINT_WINDOWS,"failed to allocate PML4\n");
38 return FALSE;
39 }
40
41 // FIXME: Physical PTEs = FirmwareTemporary ?
42
43 /* Zero the PML4 */
44 RtlZeroMemory(PxeBase, PAGE_SIZE);
45
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);
52
53 // FIXME: map PDE's for hals memory mapping
54
55 DPRINTM(DPRINT_WINDOWS,">>> leave MempAllocatePageTables\n");
56
57 return TRUE;
58 }
59
60 PHARDWARE_PTE
61 MempGetOrCreatePageDir(PHARDWARE_PTE PdeBase, ULONG Index)
62 {
63 PHARDWARE_PTE SubDir;
64
65 if (!PdeBase)
66 return NULL;
67
68 if (!PdeBase[Index].Valid)
69 {
70 SubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderMemoryData);
71 if (!SubDir)
72 return NULL;
73 RtlZeroMemory(SubDir, PAGE_SIZE);
74 PdeBase[Index].PageFrameNumber = PtrToPfn(SubDir);
75 PdeBase[Index].Valid = 1;
76 PdeBase[Index].Write = 1;
77 }
78 else
79 {
80 SubDir = (PVOID)((ULONG64)(PdeBase[Index].PageFrameNumber) * PAGE_SIZE);
81 }
82 return SubDir;
83 }
84
85 BOOLEAN
86 MempMapSinglePage(ULONG64 VirtualAddress, ULONG64 PhysicalAddress)
87 {
88 PHARDWARE_PTE PpeBase, PdeBase, PteBase;
89 ULONG Index;
90
91 PpeBase = MempGetOrCreatePageDir(PxeBase, VAtoPXI(VirtualAddress));
92 PdeBase = MempGetOrCreatePageDir(PpeBase, VAtoPPI(VirtualAddress));
93 PteBase = MempGetOrCreatePageDir(PdeBase, VAtoPDI(VirtualAddress));
94
95 if (!PteBase)
96 {
97 DPRINTM(DPRINT_WINDOWS,"!!!No Dir %p, %p, %p, %p\n", PxeBase, PpeBase, PdeBase, PteBase);
98 return FALSE;
99 }
100
101 Index = VAtoPTI(VirtualAddress);
102 if (PteBase[Index].Valid)
103 {
104 DPRINTM(DPRINT_WINDOWS,"!!!Already mapped %ld\n", Index);
105 return FALSE;
106 }
107
108 PteBase[Index].Valid = 1;
109 PteBase[Index].Write = 1;
110 PteBase[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
111
112 return TRUE;
113 }
114
115 BOOLEAN
116 MempIsPageMapped(PVOID VirtualAddress)
117 {
118 PHARDWARE_PTE PpeBase, PdeBase, PteBase;
119 ULONG Index;
120
121 Index = VAtoPXI(VirtualAddress);
122 if (!PxeBase[Index].Valid)
123 return FALSE;
124
125 PpeBase = (PVOID)((ULONG64)(PxeBase[Index].PageFrameNumber) * PAGE_SIZE);
126 Index = VAtoPPI(VirtualAddress);
127 if (!PpeBase[Index].Valid)
128 return FALSE;
129
130 PdeBase = (PVOID)((ULONG64)(PpeBase[Index].PageFrameNumber) * PAGE_SIZE);
131 Index = VAtoPDI(VirtualAddress);
132 if (!PdeBase[Index].Valid)
133 return FALSE;
134
135 PteBase = (PVOID)((ULONG64)(PdeBase[Index].PageFrameNumber) * PAGE_SIZE);
136 Index = VAtoPTI(VirtualAddress);
137 if (!PteBase[Index].Valid)
138 return FALSE;
139
140 return TRUE;
141 }
142
143 ULONG
144 MempMapRangeOfPages(ULONG64 VirtualAddress, ULONG64 PhysicalAddress, ULONG cPages)
145 {
146 ULONG i;
147
148 for (i = 0; i < cPages; i++)
149 {
150 if (!MempMapSinglePage(VirtualAddress, PhysicalAddress))
151 {
152 return i;
153 }
154 VirtualAddress += PAGE_SIZE;
155 PhysicalAddress += PAGE_SIZE;
156 }
157 return i;
158 }
159
160 BOOLEAN
161 MempSetupPaging(IN ULONG StartPage,
162 IN ULONG NumberOfPages)
163 {
164 DPRINTM(DPRINT_WINDOWS,">>> MempSetupPaging(0x%lx, %ld, %p)\n",
165 StartPage, NumberOfPages, StartPage * PAGE_SIZE + KSEG0_BASE);
166
167 /* Identity mapping */
168 if (MempMapRangeOfPages(StartPage * PAGE_SIZE,
169 StartPage * PAGE_SIZE,
170 NumberOfPages) != NumberOfPages)
171 {
172 DPRINTM(DPRINT_WINDOWS,"Failed to map pages 1\n");
173 return FALSE;
174 }
175
176 /* Kernel mapping */
177 if (MempMapRangeOfPages(StartPage * PAGE_SIZE + KSEG0_BASE,
178 StartPage * PAGE_SIZE,
179 NumberOfPages) != NumberOfPages)
180 {
181 DPRINTM(DPRINT_WINDOWS,"Failed to map pages 2\n");
182 return FALSE;
183 }
184
185 return TRUE;
186 }
187
188 VOID
189 MempUnmapPage(ULONG Page)
190 {
191 // DPRINTM(DPRINT_WINDOWS,">>> MempUnmapPage\n");
192 }
193
194 VOID
195 WinLdrpMapApic()
196 {
197 BOOLEAN LocalAPIC;
198 LARGE_INTEGER MsrValue;
199 ULONG CpuInfo[4];
200 ULONG64 APICAddress;
201
202 DPRINTM(DPRINT_WINDOWS,">>> WinLdrpMapApic\n");
203
204 /* Check if we have a local APIC */
205 __cpuid((int*)CpuInfo, 1);
206 LocalAPIC = (((CpuInfo[3] >> 9) & 1) != 0);
207
208 /* If there is no APIC, just return */
209 if (!LocalAPIC)
210 {
211 DPRINTM(DPRINT_WINDOWS,"No APIC found.\n");
212 return;
213 }
214
215 /* Read the APIC Address */
216 MsrValue.QuadPart = __readmsr(0x1B);
217 APICAddress = (MsrValue.LowPart & 0xFFFFF000);
218
219 DPRINTM(DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
220 APICAddress);
221
222 /* Map it */
223 MempMapSinglePage(APIC_BASE, APICAddress);
224 }
225
226 BOOLEAN
227 WinLdrMapSpecialPages(ULONG PcrBasePage)
228 {
229 /* Map the PCR page */
230 if (!MempMapSinglePage(KIP0PCRADDRESS, PcrBasePage * PAGE_SIZE))
231 {
232 DPRINTM(DPRINT_WINDOWS, "Could not map PCR @ %lx\n", PcrBasePage);
233 return FALSE;
234 }
235
236 /* Map KI_USER_SHARED_DATA */
237 if (!MempMapSinglePage(KI_USER_SHARED_DATA, (PcrBasePage+1) * PAGE_SIZE))
238 {
239 DPRINTM(DPRINT_WINDOWS, "Could not map KI_USER_SHARED_DATA\n");
240 return FALSE;
241 }
242
243 /* Map the APIC page */
244 WinLdrpMapApic();
245
246 return TRUE;
247 }
248
249 VOID
250 WinLdrSetupGdt(PVOID GdtBase, ULONG64 TssBase)
251 {
252 PKGDTENTRY64 Entry;
253 KDESCRIPTOR GdtDesc;
254
255 /* Setup KGDT64_NULL */
256 Entry = KiGetGdtEntry(GdtBase, KGDT64_NULL);
257 *(PULONG64)Entry = 0x0000000000000000ULL;
258
259 /* Setup KGDT64_R0_CODE */
260 Entry = KiGetGdtEntry(GdtBase, KGDT64_R0_CODE);
261 *(PULONG64)Entry = 0x00209b0000000000ULL;
262
263 /* Setup KGDT64_R0_DATA */
264 Entry = KiGetGdtEntry(GdtBase, KGDT64_R0_DATA);
265 *(PULONG64)Entry = 0x00cf93000000ffffULL;
266
267 /* Setup KGDT64_R3_CMCODE */
268 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CMCODE);
269 *(PULONG64)Entry = 0x00cffb000000ffffULL;
270
271 /* Setup KGDT64_R3_DATA */
272 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_DATA);
273 *(PULONG64)Entry = 0x00cff3000000ffffULL;
274
275 /* Setup KGDT64_R3_CODE */
276 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CODE);
277 *(PULONG64)Entry = 0x0020fb0000000000ULL;
278
279 /* Setup KGDT64_R3_CMTEB */
280 Entry = KiGetGdtEntry(GdtBase, KGDT64_R3_CMTEB);
281 *(PULONG64)Entry = 0xff40f3fd50003c00ULL;
282
283 /* Setup TSS entry */
284 Entry = KiGetGdtEntry(GdtBase, KGDT64_SYS_TSS);
285 KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
286
287 /* Setup GDT descriptor */
288 GdtDesc.Base = GdtBase;
289 GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
290
291 /* Set the new Gdt */
292 __lgdt(&GdtDesc.Limit);
293 DbgPrint("Gdtr.Base = %p, num = %ld\n", GdtDesc.Base, NUM_GDT);
294
295 }
296
297 VOID
298 WinLdrSetupIdt(PVOID IdtBase)
299 {
300 KDESCRIPTOR IdtDesc, OldIdt;
301
302 /* Get old IDT */
303 __sidt(&OldIdt);
304
305 /* Copy the old IDT */
306 RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, OldIdt.Limit + 1);
307
308 /* Setup the new IDT descriptor */
309 IdtDesc.Base = IdtBase;
310 IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
311
312 /* Set the new IDT */
313 __lidt(&IdtDesc.Limit);
314 DbgPrint("Idtr.Base = %p\n", IdtDesc.Base);
315
316 }
317
318 VOID
319 WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG64 Pcr, IN ULONG64 Tss)
320 {
321 DPRINTM(DPRINT_WINDOWS, "WinLdrSetProcessorContext %p\n", Pcr);
322
323 /* Disable Interrupts */
324 _disable();
325
326 /* Re-initalize EFLAGS */
327 __writeeflags(0);
328
329 /* Set the new PML4 */
330 __writecr3((ULONG64)PxeBase);
331
332 /* Get kernel mode address of gdt / idt */
333 GdtIdt = (PVOID)((ULONG64)GdtIdt + KSEG0_BASE);
334
335 /* Create gdt entries and load gdtr */
336 WinLdrSetupGdt(GdtIdt, Tss);
337
338 /* Copy old Idt and set idtr */
339 WinLdrSetupIdt((PVOID)((ULONG64)GdtIdt + 2048)); // HACK!
340
341 /* LDT is unused */
342 // __lldt(0);
343
344 /* Load TSR */
345 __ltr(KGDT64_SYS_TSS);
346
347 DPRINTM(DPRINT_WINDOWS, "leave WinLdrSetProcessorContext\n");
348 }
349
350 VOID
351 MempDump()
352 {
353 }
354