59a78aaf16568bae301737447db0318fd38d22bd
[reactos.git] / reactos / boot / freeldr / freeldr / arch / amd64 / loader.c
1 /*
2 * FreeLoader
3 * Copyright (C) 2008 - 2009 Timo Kreuzer (timo.kreuzer@reactor.org)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #define _NTSYSTEM_
20 #include <freeldr.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /* Page Directory and Tables for non-PAE Systems */
26 extern ULONG_PTR NextModuleBase;
27 extern ULONG_PTR KernelBase;
28 ULONG_PTR GdtBase, IdtBase, TssBase;
29 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
30
31 PPAGE_DIRECTORY_AMD64 pPML4;
32 PVOID pIdt, pGdt;
33
34 /* FUNCTIONS *****************************************************************/
35
36 void
37 EnableA20()
38 {
39 /* Already done */
40 }
41
42 void
43 DumpLoaderBlock()
44 {
45 DbgPrint("LoaderBlock @ %p.\n", &LoaderBlock);
46 DbgPrint("Flags = 0x%x.\n", LoaderBlock.Flags);
47 DbgPrint("MemLower = 0x%p.\n", (PVOID)LoaderBlock.MemLower);
48 DbgPrint("MemHigher = 0x%p.\n", (PVOID)LoaderBlock.MemHigher);
49 DbgPrint("BootDevice = 0x%x.\n", LoaderBlock.BootDevice);
50 DbgPrint("CommandLine = %s.\n", LoaderBlock.CommandLine);
51 DbgPrint("ModsCount = 0x%x.\n", LoaderBlock.ModsCount);
52 DbgPrint("ModsAddr = 0x%p.\n", LoaderBlock.ModsAddr);
53 DbgPrint("Syms = 0x%s.\n", LoaderBlock.Syms);
54 DbgPrint("MmapLength = 0x%x.\n", LoaderBlock.MmapLength);
55 DbgPrint("MmapAddr = 0x%p.\n", (PVOID)LoaderBlock.MmapAddr);
56 DbgPrint("RdLength = 0x%x.\n", LoaderBlock.RdLength);
57 DbgPrint("RdAddr = 0x%p.\n", (PVOID)LoaderBlock.RdAddr);
58 DbgPrint("DrivesCount = 0x%x.\n", LoaderBlock.DrivesCount);
59 DbgPrint("DrivesAddr = 0x%p.\n", (PVOID)LoaderBlock.DrivesAddr);
60 DbgPrint("ConfigTable = 0x%x.\n", LoaderBlock.ConfigTable);
61 DbgPrint("BootLoaderName = 0x%x.\n", LoaderBlock.BootLoaderName);
62 DbgPrint("PageDirectoryStart = 0x%p.\n", (PVOID)LoaderBlock.PageDirectoryStart);
63 DbgPrint("PageDirectoryEnd = 0x%p.\n", (PVOID)LoaderBlock.PageDirectoryEnd);
64 DbgPrint("KernelBase = 0x%p.\n", (PVOID)LoaderBlock.KernelBase);
65 DbgPrint("ArchExtra = 0x%p.\n", (PVOID)LoaderBlock.ArchExtra);
66
67 }
68
69 /*++
70 * FrLdrStartup
71 * INTERNAL
72 *
73 * Prepares the system for loading the Kernel.
74 *
75 * Params:
76 * Magic - Multiboot Magic
77 *
78 * Returns:
79 * None.
80 *
81 * Remarks:
82 * None.
83 *
84 *--*/
85 VOID
86 NTAPI
87 FrLdrStartup(ULONG Magic)
88 {
89 /* Disable Interrupts */
90 _disable();
91
92 /* Re-initalize EFLAGS */
93 KeAmd64EraseFlags();
94
95 /* Initialize the page directory */
96 FrLdrSetupPageDirectory();
97
98 /* Set the new PML4 */
99 __writecr3((ULONGLONG)pPML4);
100
101 FrLdrSetupGdtIdt();
102
103 LoaderBlock.FrLdrDbgPrint = DbgPrint;
104
105 // DumpLoaderBlock();
106
107 DbgPrint("Jumping to kernel @ %p.\n", KernelEntryPoint);
108
109 /* Jump to Kernel */
110 (*KernelEntryPoint)(Magic, &LoaderBlock);
111
112 }
113
114 PPAGE_DIRECTORY_AMD64
115 FrLdrGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir, ULONG Index)
116 {
117 PPAGE_DIRECTORY_AMD64 pSubDir;
118
119 if (!pDir)
120 return NULL;
121
122 if (!pDir->Pde[Index].Valid)
123 {
124 pSubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
125 if (!pSubDir)
126 return NULL;
127 RtlZeroMemory(pSubDir, PAGE_SIZE);
128 pDir->Pde[Index].PageFrameNumber = PtrToPfn(pSubDir);
129 pDir->Pde[Index].Valid = 1;
130 pDir->Pde[Index].Write = 1;
131 }
132 else
133 {
134 pSubDir = (PPAGE_DIRECTORY_AMD64)((ULONGLONG)(pDir->Pde[Index].PageFrameNumber) * PAGE_SIZE);
135 }
136 return pSubDir;
137 }
138
139 BOOLEAN
140 FrLdrMapSinglePage(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress)
141 {
142 PPAGE_DIRECTORY_AMD64 pDir3, pDir2, pDir1;
143 ULONG Index;
144
145 pDir3 = FrLdrGetOrCreatePageDir(pPML4, VAtoPXI(VirtualAddress));
146 pDir2 = FrLdrGetOrCreatePageDir(pDir3, VAtoPPI(VirtualAddress));
147 pDir1 = FrLdrGetOrCreatePageDir(pDir2, VAtoPDI(VirtualAddress));
148
149 if (!pDir1)
150 return FALSE;
151
152 Index = VAtoPTI(VirtualAddress);
153 if (pDir1->Pde[Index].Valid)
154 {
155 return FALSE;
156 }
157
158 pDir1->Pde[Index].Valid = 1;
159 pDir1->Pde[Index].Write = 1;
160 pDir1->Pde[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
161
162 return TRUE;
163 }
164
165 ULONG
166 FrLdrMapRangeOfPages(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress, ULONG cPages)
167 {
168 ULONG i;
169
170 for (i = 0; i < cPages; i++)
171 {
172 if (!FrLdrMapSinglePage(VirtualAddress, PhysicalAddress))
173 {
174 return i;
175 }
176 VirtualAddress += PAGE_SIZE;
177 PhysicalAddress += PAGE_SIZE;
178 }
179 return i;
180 }
181
182
183 /*++
184 * FrLdrSetupPageDirectory
185 * INTERNAL
186 *
187 * Sets up the ReactOS Startup Page Directory.
188 *
189 * Params:
190 * None.
191 *
192 * Returns:
193 * None.
194 *--*/
195 VOID
196 FASTCALL
197 FrLdrSetupPageDirectory(VOID)
198 {
199 ULONG KernelPages;
200 PVOID UserSharedData;
201
202 /* Allocate a Page for the PML4 */
203 pPML4 = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
204
205 ASSERT(pPML4);
206
207 /* The page tables are located at 0xfffff68000000000
208 * We create a recursive self mapping through all 4 levels at
209 * virtual address 0xfffff6fb7dbedf68 */
210 pPML4->Pde[VAtoPXI(PXE_BASE)].Valid = 1;
211 pPML4->Pde[VAtoPXI(PXE_BASE)].Write = 1;
212 pPML4->Pde[VAtoPXI(PXE_BASE)].PageFrameNumber = PtrToPfn(pPML4);
213
214 /* Setup low memory pages */
215 if (FrLdrMapRangeOfPages(0, 0, 1024) < 1024)
216 {
217 DbgPrint("Could not map low memory pages.\n");
218 }
219
220 /* Setup kernel pages */
221 KernelPages = (ROUND_TO_PAGES(NextModuleBase - KERNEL_BASE_PHYS) / PAGE_SIZE);
222 if (FrLdrMapRangeOfPages(KernelBase, KERNEL_BASE_PHYS, KernelPages) != KernelPages)
223 {
224 DbgPrint("Could not map %d kernel pages.\n", KernelPages);
225 }
226
227 /* Setup a page for the idt */
228 pIdt = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
229 IdtBase = KernelBase + KernelPages * PAGE_SIZE;
230 if (!FrLdrMapSinglePage(IdtBase, (ULONGLONG)pIdt))
231 {
232 DbgPrint("Could not map idt page.\n", KernelPages);
233 }
234
235 /* Setup a page for the gdt & tss */
236 pGdt = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
237 GdtBase = IdtBase + PAGE_SIZE;
238 TssBase = GdtBase + 20 * sizeof(ULONG64); // FIXME: don't hardcode
239 if (!FrLdrMapSinglePage(GdtBase, (ULONGLONG)pGdt))
240 {
241 DbgPrint("Could not map gdt page.\n", KernelPages);
242 }
243
244 /* Setup KUSER_SHARED_DATA page */
245 UserSharedData = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
246 if (!FrLdrMapSinglePage(KI_USER_SHARED_DATA, (ULONG64)UserSharedData))
247 {
248 DbgPrint("Could not map KUSER_SHARED_DATA page.\n", KernelPages);
249 }
250
251 /* Map APIC page */
252 if (!FrLdrMapSinglePage(APIC_BASE, APIC_PHYS_BASE))
253 {
254 DbgPrint("Could not map APIC page.\n");
255 }
256
257 }
258
259 VOID
260 FrLdrSetupGdtIdt()
261 {
262 PKGDTENTRY64 Entry;
263 KDESCRIPTOR Desc;
264
265 RtlZeroMemory(pGdt, PAGE_SIZE);
266
267 /* Setup KGDT_64_R0_CODE */
268 Entry = KiGetGdtEntry(pGdt, KGDT_64_R0_CODE);
269 *(PULONG64)Entry = 0x00209b0000000000ULL;
270
271 /* Setup KGDT_64_R0_SS */
272 Entry = KiGetGdtEntry(pGdt, KGDT_64_R0_SS);
273 *(PULONG64)Entry = 0x00cf93000000ffffULL;
274
275 /* Setup KGDT_64_DATA */
276 Entry = KiGetGdtEntry(pGdt, KGDT_64_DATA);
277 *(PULONG64)Entry = 0x00cff3000000ffffULL;
278
279 /* Setup KGDT_64_R3_CODE */
280 Entry = KiGetGdtEntry(pGdt, KGDT_64_R3_CODE);
281 *(PULONG64)Entry = 0x0020fb0000000000ULL;
282
283 /* Setup KGDT_32_R3_TEB */
284 Entry = KiGetGdtEntry(pGdt, KGDT_32_R3_TEB);
285 *(PULONG64)Entry = 0xff40f3fd50003c00ULL;
286
287 /* Setup TSS entry */
288 Entry = KiGetGdtEntry(pGdt, KGDT_TSS);
289 KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
290
291 /* Setup the gdt descriptor */
292 Desc.Limit = 12 * sizeof(ULONG64) - 1;
293 Desc.Base = (PVOID)GdtBase;
294
295 /* Set the new Gdt */
296 __lgdt(&Desc.Limit);
297 DbgPrint("Gdtr.Base = %p\n", Desc.Base);
298
299 /* Setup the idt descriptor */
300 Desc.Limit = 12 * sizeof(ULONG64) - 1;
301 Desc.Base = (PVOID)IdtBase;
302
303 /* Set the new Idt */
304 __lidt(&Desc.Limit);
305 DbgPrint("Idtr.Base = %p\n", Desc.Base);
306
307 }