3 * Copyright (C) 2008 - 2009 Timo Kreuzer (timo.kreuzer@reactor.org)
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.
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.
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.
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
;
31 PPAGE_DIRECTORY_AMD64 pPML4
;
34 /* FUNCTIONS *****************************************************************/
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
);
73 * Prepares the system for loading the Kernel.
76 * Magic - Multiboot Magic
87 FrLdrStartup(ULONG Magic
)
89 /* Disable Interrupts */
92 /* Re-initalize EFLAGS */
95 /* Initialize the page directory */
96 FrLdrSetupPageDirectory();
98 /* Set the new PML4 */
99 __writecr3((ULONGLONG
)pPML4
);
103 LoaderBlock
.FrLdrDbgPrint
= DbgPrint
;
105 // DumpLoaderBlock();
107 DbgPrint("Jumping to kernel @ %p.\n", KernelEntryPoint
);
110 (*KernelEntryPoint
)(Magic
, &LoaderBlock
);
114 PPAGE_DIRECTORY_AMD64
115 FrLdrGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir
, ULONG Index
)
117 PPAGE_DIRECTORY_AMD64 pSubDir
;
122 if (!pDir
->Pde
[Index
].Valid
)
124 pSubDir
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
127 RtlZeroMemory(pSubDir
, PAGE_SIZE
);
128 pDir
->Pde
[Index
].PageFrameNumber
= PtrToPfn(pSubDir
);
129 pDir
->Pde
[Index
].Valid
= 1;
130 pDir
->Pde
[Index
].Write
= 1;
134 pSubDir
= (PPAGE_DIRECTORY_AMD64
)((ULONGLONG
)(pDir
->Pde
[Index
].PageFrameNumber
) * PAGE_SIZE
);
140 FrLdrMapSinglePage(ULONGLONG VirtualAddress
, ULONGLONG PhysicalAddress
)
142 PPAGE_DIRECTORY_AMD64 pDir3
, pDir2
, pDir1
;
145 pDir3
= FrLdrGetOrCreatePageDir(pPML4
, VAtoPXI(VirtualAddress
));
146 pDir2
= FrLdrGetOrCreatePageDir(pDir3
, VAtoPPI(VirtualAddress
));
147 pDir1
= FrLdrGetOrCreatePageDir(pDir2
, VAtoPDI(VirtualAddress
));
152 Index
= VAtoPTI(VirtualAddress
);
153 if (pDir1
->Pde
[Index
].Valid
)
158 pDir1
->Pde
[Index
].Valid
= 1;
159 pDir1
->Pde
[Index
].Write
= 1;
160 pDir1
->Pde
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
166 FrLdrMapRangeOfPages(ULONGLONG VirtualAddress
, ULONGLONG PhysicalAddress
, ULONG cPages
)
170 for (i
= 0; i
< cPages
; i
++)
172 if (!FrLdrMapSinglePage(VirtualAddress
, PhysicalAddress
))
176 VirtualAddress
+= PAGE_SIZE
;
177 PhysicalAddress
+= PAGE_SIZE
;
184 * FrLdrSetupPageDirectory
187 * Sets up the ReactOS Startup Page Directory.
197 FrLdrSetupPageDirectory(VOID
)
200 PVOID UserSharedData
;
202 /* Allocate a Page for the PML4 */
203 pPML4
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
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
);
214 /* Setup low memory pages */
215 if (FrLdrMapRangeOfPages(0, 0, 1024) < 1024)
217 DbgPrint("Could not map low memory pages.\n");
220 /* Setup kernel pages */
221 KernelPages
= (ROUND_TO_PAGES(NextModuleBase
- KERNEL_BASE_PHYS
) / PAGE_SIZE
);
222 if (FrLdrMapRangeOfPages(KernelBase
, KERNEL_BASE_PHYS
, KernelPages
) != KernelPages
)
224 DbgPrint("Could not map %d kernel pages.\n", KernelPages
);
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
))
232 DbgPrint("Could not map idt page.\n", KernelPages
);
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
))
241 DbgPrint("Could not map gdt page.\n", KernelPages
);
244 /* Setup KUSER_SHARED_DATA page */
245 UserSharedData
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
246 if (!FrLdrMapSinglePage(KI_USER_SHARED_DATA
, (ULONG64
)UserSharedData
))
248 DbgPrint("Could not map KUSER_SHARED_DATA page.\n", KernelPages
);
252 if (!FrLdrMapSinglePage(APIC_BASE
, APIC_PHYS_BASE
))
254 DbgPrint("Could not map APIC page.\n");
265 RtlZeroMemory(pGdt
, PAGE_SIZE
);
267 /* Setup KGDT_64_R0_CODE */
268 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_R0_CODE
);
269 *(PULONG64
)Entry
= 0x00209b0000000000ULL
;
271 /* Setup KGDT_64_R0_SS */
272 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_R0_SS
);
273 *(PULONG64
)Entry
= 0x00cf93000000ffffULL
;
275 /* Setup KGDT_64_DATA */
276 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_DATA
);
277 *(PULONG64
)Entry
= 0x00cff3000000ffffULL
;
279 /* Setup KGDT_64_R3_CODE */
280 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_R3_CODE
);
281 *(PULONG64
)Entry
= 0x0020fb0000000000ULL
;
283 /* Setup KGDT_32_R3_TEB */
284 Entry
= KiGetGdtEntry(pGdt
, KGDT_32_R3_TEB
);
285 *(PULONG64
)Entry
= 0xff40f3fd50003c00ULL
;
287 /* Setup TSS entry */
288 Entry
= KiGetGdtEntry(pGdt
, KGDT_TSS
);
289 KiInitGdtEntry(Entry
, TssBase
, sizeof(KTSS
), I386_TSS
, 0);
291 /* Setup the gdt descriptor */
292 Desc
.Limit
= 12 * sizeof(ULONG64
) - 1;
293 Desc
.Base
= (PVOID
)GdtBase
;
295 /* Set the new Gdt */
297 DbgPrint("Gdtr.Base = %p\n", Desc
.Base
);
299 /* Setup the idt descriptor */
300 Desc
.Limit
= 12 * sizeof(ULONG64
) - 1;
301 Desc
.Base
= (PVOID
)IdtBase
;
303 /* Set the new Idt */
305 DbgPrint("Idtr.Base = %p\n", Desc
.Base
);