3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 /* Page Directory and Tables for non-PAE Systems */
28 extern ULONG_PTR NextModuleBase
;
29 extern ULONG_PTR KernelBase
;
30 ULONG_PTR GdtBase
, IdtBase
, TssBase
;
31 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint
;
33 PPAGE_DIRECTORY_AMD64 pPML4
;
36 /* FUNCTIONS *****************************************************************/
47 DbgPrint("LoaderBlock @ %p.\n", &LoaderBlock
);
48 DbgPrint("Flags = 0x%x.\n", LoaderBlock
.Flags
);
49 DbgPrint("MemLower = 0x%p.\n", (PVOID
)LoaderBlock
.MemLower
);
50 DbgPrint("MemHigher = 0x%p.\n", (PVOID
)LoaderBlock
.MemHigher
);
51 DbgPrint("BootDevice = 0x%x.\n", LoaderBlock
.BootDevice
);
52 DbgPrint("CommandLine = %s.\n", LoaderBlock
.CommandLine
);
53 DbgPrint("ModsCount = 0x%x.\n", LoaderBlock
.ModsCount
);
54 DbgPrint("ModsAddr = 0x%p.\n", LoaderBlock
.ModsAddr
);
55 DbgPrint("Syms = 0x%s.\n", LoaderBlock
.Syms
);
56 DbgPrint("MmapLength = 0x%x.\n", LoaderBlock
.MmapLength
);
57 DbgPrint("MmapAddr = 0x%p.\n", (PVOID
)LoaderBlock
.MmapAddr
);
58 DbgPrint("RdLength = 0x%x.\n", LoaderBlock
.RdLength
);
59 DbgPrint("RdAddr = 0x%p.\n", (PVOID
)LoaderBlock
.RdAddr
);
60 DbgPrint("DrivesCount = 0x%x.\n", LoaderBlock
.DrivesCount
);
61 DbgPrint("DrivesAddr = 0x%p.\n", (PVOID
)LoaderBlock
.DrivesAddr
);
62 DbgPrint("ConfigTable = 0x%x.\n", LoaderBlock
.ConfigTable
);
63 DbgPrint("BootLoaderName = 0x%x.\n", LoaderBlock
.BootLoaderName
);
64 DbgPrint("PageDirectoryStart = 0x%p.\n", (PVOID
)LoaderBlock
.PageDirectoryStart
);
65 DbgPrint("PageDirectoryEnd = 0x%p.\n", (PVOID
)LoaderBlock
.PageDirectoryEnd
);
66 DbgPrint("KernelBase = 0x%p.\n", (PVOID
)LoaderBlock
.KernelBase
);
67 DbgPrint("ArchExtra = 0x%p.\n", (PVOID
)LoaderBlock
.ArchExtra
);
75 * Prepares the system for loading the Kernel.
78 * Magic - Multiboot Magic
89 FrLdrStartup(ULONG Magic
)
91 /* Disable Interrupts */
94 /* Re-initalize EFLAGS */
97 /* Initialize the page directory */
98 FrLdrSetupPageDirectory();
100 /* Set the new PML4 */
101 __writecr3((ULONGLONG
)pPML4
);
105 LoaderBlock
.FrLdrDbgPrint
= DbgPrint
;
107 // DumpLoaderBlock();
109 DbgPrint("Jumping to kernel @ %p.\n", KernelEntryPoint
);
112 (*KernelEntryPoint
)(Magic
, &LoaderBlock
);
116 PPAGE_DIRECTORY_AMD64
117 FrLdrGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir
, ULONG Index
)
119 PPAGE_DIRECTORY_AMD64 pSubDir
;
124 if (!pDir
->Pde
[Index
].Valid
)
126 pSubDir
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
129 RtlZeroMemory(pSubDir
, PAGE_SIZE
);
130 pDir
->Pde
[Index
].PageFrameNumber
= PtrToPfn(pSubDir
);
131 pDir
->Pde
[Index
].Valid
= 1;
132 pDir
->Pde
[Index
].Write
= 1;
136 pSubDir
= (PPAGE_DIRECTORY_AMD64
)((ULONGLONG
)(pDir
->Pde
[Index
].PageFrameNumber
) * PAGE_SIZE
);
142 FrLdrMapSinglePage(ULONGLONG VirtualAddress
, ULONGLONG PhysicalAddress
)
144 PPAGE_DIRECTORY_AMD64 pDir3
, pDir2
, pDir1
;
147 pDir3
= FrLdrGetOrCreatePageDir(pPML4
, VAtoPXI(VirtualAddress
));
148 pDir2
= FrLdrGetOrCreatePageDir(pDir3
, VAtoPPI(VirtualAddress
));
149 pDir1
= FrLdrGetOrCreatePageDir(pDir2
, VAtoPDI(VirtualAddress
));
154 Index
= VAtoPTI(VirtualAddress
);
155 if (pDir1
->Pde
[Index
].Valid
)
160 pDir1
->Pde
[Index
].Valid
= 1;
161 pDir1
->Pde
[Index
].Write
= 1;
162 pDir1
->Pde
[Index
].PageFrameNumber
= PhysicalAddress
/ PAGE_SIZE
;
168 FrLdrMapRangeOfPages(ULONGLONG VirtualAddress
, ULONGLONG PhysicalAddress
, ULONG cPages
)
172 for (i
= 0; i
< cPages
; i
++)
174 if (!FrLdrMapSinglePage(VirtualAddress
, PhysicalAddress
))
178 VirtualAddress
+= PAGE_SIZE
;
179 PhysicalAddress
+= PAGE_SIZE
;
186 * FrLdrSetupPageDirectory
189 * Sets up the ReactOS Startup Page Directory.
199 FrLdrSetupPageDirectory(VOID
)
202 PVOID UserSharedData
;
204 /* Allocate a Page for the PML4 */
205 pPML4
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
209 /* The page tables are located at 0xfffff68000000000
210 * We create a recursive self mapping through all 4 levels at
211 * virtual address 0xfffff6fb7dbedf68 */
212 pPML4
->Pde
[VAtoPXI(PXE_BASE
)].Valid
= 1;
213 pPML4
->Pde
[VAtoPXI(PXE_BASE
)].Write
= 1;
214 pPML4
->Pde
[VAtoPXI(PXE_BASE
)].PageFrameNumber
= PtrToPfn(pPML4
);
216 /* Setup low memory pages */
217 if (FrLdrMapRangeOfPages(0, 0, 1024) < 1024)
219 DbgPrint("Could not map low memory pages.\n");
222 /* Setup kernel pages */
223 KernelPages
= (ROUND_TO_PAGES(NextModuleBase
- KERNEL_BASE_PHYS
) / PAGE_SIZE
);
224 if (FrLdrMapRangeOfPages(KernelBase
, KERNEL_BASE_PHYS
, KernelPages
) != KernelPages
)
226 DbgPrint("Could not map %d kernel pages.\n", KernelPages
);
229 /* Setup a page for the idt */
230 pIdt
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
231 IdtBase
= KernelBase
+ KernelPages
* PAGE_SIZE
;
232 if (!FrLdrMapSinglePage(IdtBase
, (ULONGLONG
)pIdt
))
234 DbgPrint("Could not map idt page.\n", KernelPages
);
237 /* Setup a page for the gdt & tss */
238 pGdt
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
239 GdtBase
= IdtBase
+ PAGE_SIZE
;
240 TssBase
= GdtBase
+ 20 * sizeof(ULONG64
); // FIXME: don't hardcode
241 if (!FrLdrMapSinglePage(GdtBase
, (ULONGLONG
)pGdt
))
243 DbgPrint("Could not map gdt page.\n", KernelPages
);
246 /* Setup KUSER_SHARED_DATA page */
247 UserSharedData
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderSpecialMemory
);
248 if (!FrLdrMapSinglePage(KI_USER_SHARED_DATA
, (ULONG64
)UserSharedData
))
250 DbgPrint("Could not map KUSER_SHARED_DATA page.\n", KernelPages
);
254 if (!FrLdrMapSinglePage(APIC_BASE
, APIC_PHYS_BASE
))
256 DbgPrint("Could not map APIC page.\n");
267 RtlZeroMemory(pGdt
, PAGE_SIZE
);
269 /* Setup KGDT_64_R0_CODE */
270 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_R0_CODE
);
271 *(PULONG64
)Entry
= 0x0020980000000000ULL
;
273 /* Setup KGDT_64_DATA */
274 Entry
= KiGetGdtEntry(pGdt
, KGDT_64_DATA
);
275 *(PULONG64
)Entry
= 0x0000F00000000000ULL
;
277 /* Setup TSS entry */
278 Entry
= KiGetGdtEntry(pGdt
, KGDT_TSS
);
279 KiInitGdtEntry(Entry
, TssBase
, I386_TSS
, 0);
281 /* Setup the gdt descriptor */
282 Desc
.Limit
= 12 * sizeof(ULONG64
) - 1;
283 Desc
.Base
= (PVOID
)GdtBase
;
285 /* Set the new Gdt */
287 DbgPrint("Gdtr.Base = %p\n", Desc
.Base
);
289 /* Setup the idt descriptor */
290 Desc
.Limit
= 12 * sizeof(ULONG64
) - 1;
291 Desc
.Base
= (PVOID
)IdtBase
;
293 /* Set the new Idt */
295 DbgPrint("Idtr.Base = %p\n", Desc
.Base
);