3e3288a682a9aa3c0c4b569fde0a83cd44638d18
[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 KGDT_64_R0_CODE */
256 Entry = KiGetGdtEntry(GdtBase, KGDT_64_R0_CODE);
257 *(PULONG64)Entry = 0x00209b0000000000ULL;
258
259 /* Setup KGDT_64_R0_SS */
260 Entry = KiGetGdtEntry(GdtBase, KGDT_64_R0_SS);
261 *(PULONG64)Entry = 0x00cf93000000ffffULL;
262
263 /* Setup KGDT_64_DATA */
264 Entry = KiGetGdtEntry(GdtBase, KGDT_64_DATA);
265 *(PULONG64)Entry = 0x00cff3000000ffffULL;
266
267 /* Setup KGDT_64_R3_CODE */
268 Entry = KiGetGdtEntry(GdtBase, KGDT_64_R3_CODE);
269 *(PULONG64)Entry = 0x0020fb0000000000ULL;
270
271 /* Setup KGDT_32_R3_TEB */
272 Entry = KiGetGdtEntry(GdtBase, KGDT_32_R3_TEB);
273 *(PULONG64)Entry = 0xff40f3fd50003c00ULL;
274
275 /* Setup TSS entry */
276 Entry = KiGetGdtEntry(GdtBase, KGDT_TSS);
277 KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
278
279 /* Setup GDT descriptor */
280 GdtDesc.Base = GdtBase;
281 GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
282
283 /* Set the new Gdt */
284 __lgdt(&GdtDesc.Limit);
285 DbgPrint("Gdtr.Base = %p, num = %ld\n", GdtDesc.Base, NUM_GDT);
286
287 }
288
289 VOID
290 WinLdrSetupIdt(PVOID IdtBase)
291 {
292 KDESCRIPTOR IdtDesc, OldIdt;
293
294 /* Get old IDT */
295 __sidt(&OldIdt);
296
297 /* Copy the old IDT */
298 RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, OldIdt.Limit + 1);
299
300 /* Setup the new IDT descriptor */
301 IdtDesc.Base = IdtBase;
302 IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
303
304 /* Set the new IDT */
305 __lidt(&IdtDesc.Limit);
306 DbgPrint("Idtr.Base = %p\n", IdtDesc.Base);
307
308 }
309
310 VOID
311 WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG64 Pcr, IN ULONG64 Tss)
312 {
313 DPRINTM(DPRINT_WINDOWS, "WinLdrSetProcessorContext %p\n", Pcr);
314
315 /* Disable Interrupts */
316 _disable();
317
318 /* Re-initalize EFLAGS */
319 __writeeflags(0);
320
321 /* Set the new PML4 */
322 __writecr3((ULONG64)PxeBase);
323
324 /* Get kernel mode address of gdt / idt */
325 GdtIdt = (PVOID)((ULONG64)GdtIdt + KSEG0_BASE);
326
327 /* Create gdt entries and load gdtr */
328 WinLdrSetupGdt(GdtIdt, Tss);
329
330 /* Copy old Idt and set idtr */
331 WinLdrSetupIdt((PVOID)((ULONG64)GdtIdt + 2048)); // HACK!
332
333 /* LDT is unused */
334 // __lldt(0);
335
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
342
343 /* Load TSR */
344 __ltr(KGDT_TSS);
345
346 DPRINTM(DPRINT_WINDOWS, "leave WinLdrSetProcessorContext\n");
347 }
348
349 VOID
350 MempDump()
351 {
352 }
353