I reworked the pagetable code a little. Now the first tables are static .bss tables...
[reactos.git] / reactos / boot / freeldr / freeldr / arch / amd64 / loader.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
5 *
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.
10 *
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.
15 *
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.
19 */
20 #define _NTSYSTEM_
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25 //#undef DbgPrint
26
27 /* Page Directory and Tables for non-PAE Systems */
28 extern ULONG_PTR NextModuleBase;
29 extern ULONG_PTR KernelBase;
30 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
31
32 PPAGE_DIRECTORY_AMD64 pPML4;
33
34 /* FUNCTIONS *****************************************************************/
35
36 /*++
37 * FrLdrStartup
38 * INTERNAL
39 *
40 * Prepares the system for loading the Kernel.
41 *
42 * Params:
43 * Magic - Multiboot Magic
44 *
45 * Returns:
46 * None.
47 *
48 * Remarks:
49 * None.
50 *
51 *--*/
52 VOID
53 NTAPI
54 FrLdrStartup(ULONG Magic)
55 {
56 /* Disable Interrupts */
57 _disable();
58
59 /* Re-initalize EFLAGS */
60 KeAmd64EraseFlags();
61
62 /* Initialize the page directory */
63 FrLdrSetupPageDirectory();
64
65 /* Set the new PML4 */
66 __writecr3((ULONGLONG)pPML4);
67
68 DbgPrint((DPRINT_WARNING, "Jumping to kernel @ %p.\n", KernelEntryPoint));
69
70 /* Jump to Kernel */
71 (*KernelEntryPoint)(Magic, &LoaderBlock);
72
73 }
74
75 PPAGE_DIRECTORY_AMD64
76 FrLdrGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir, ULONG Index)
77 {
78 PPAGE_DIRECTORY_AMD64 pSubDir;
79
80 if (!pDir)
81 return NULL;
82
83 if (!pDir->Pde[Index].Valid)
84 {
85 pSubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
86 if (!pSubDir)
87 return NULL;
88 RtlZeroMemory(pSubDir, PAGE_SIZE);
89 pDir->Pde[Index].PageFrameNumber = (ULONGLONG)pSubDir / PAGE_SIZE;
90 pDir->Pde[Index].Valid = 1;
91 pDir->Pde[Index].Write = 1;
92 }
93 else
94 {
95 pSubDir = (PPAGE_DIRECTORY_AMD64)((ULONGLONG)(pDir->Pde[Index].PageFrameNumber) * PAGE_SIZE);
96 }
97 return pSubDir;
98 }
99
100 BOOLEAN
101 FrLdrMapSinglePage(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress)
102 {
103 PPAGE_DIRECTORY_AMD64 pDir3, pDir2, pDir1;
104 ULONG Index;
105
106 pDir3 = FrLdrGetOrCreatePageDir(pPML4, VAtoIndex4(VirtualAddress));
107 pDir2 = FrLdrGetOrCreatePageDir(pDir3, VAtoIndex3(VirtualAddress));
108 pDir1 = FrLdrGetOrCreatePageDir(pDir2, VAtoIndex2(VirtualAddress));
109
110 if (!pDir1)
111 return FALSE;
112
113 Index = VAtoIndex1(VirtualAddress);
114 if (pDir1->Pde[Index].Valid)
115 {
116 return FALSE;
117 }
118
119 pDir1->Pde[Index].Valid = 1;
120 pDir1->Pde[Index].Write = 1;
121 pDir1->Pde[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
122
123 return TRUE;
124 }
125
126 ULONG
127 FrLdrMapRangeOfPages(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress, ULONG cPages)
128 {
129 ULONG i;
130
131 for (i = 0; i < cPages; i++)
132 {
133 if (!FrLdrMapSinglePage(VirtualAddress, PhysicalAddress))
134 {
135 return i;
136 }
137 VirtualAddress += PAGE_SIZE;
138 PhysicalAddress += PAGE_SIZE;
139 }
140 return i;
141 }
142
143
144 /*++
145 * FrLdrSetupPageDirectory
146 * INTERNAL
147 *
148 * Sets up the ReactOS Startup Page Directory.
149 *
150 * Params:
151 * None.
152 *
153 * Returns:
154 * None.
155 *
156 * Remarks:
157 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
158 * As such, please note that PageFrameNumber == PageEntryNumber.
159 *
160 *--*/
161 VOID
162 FASTCALL
163 FrLdrSetupPageDirectory(VOID)
164 {
165 ULONG KernelPages;
166
167 /* Allocate a Page for the PML4 */
168 pPML4 = MmAllocateMemoryWithType(4096, LoaderSpecialMemory);
169
170 ASSERT(pPML4);
171
172 /* The page tables are located at 0xfffff68000000000
173 * We create a recursive self mapping through all 4 levels at
174 * virtual address 0xfffff6fb7dbedf68 */
175 pPML4->Pde[VAtoIndex4(PML4_BASE)].Valid = 1;
176 pPML4->Pde[VAtoIndex4(PML4_BASE)].Write = 1;
177 pPML4->Pde[VAtoIndex4(PML4_BASE)].PageFrameNumber = PtrToPfn(PML4_BASE);
178
179 ASSERT(VAtoIndex4(PML4_BASE) == 0x1ed);
180 ASSERT(VAtoIndex3(PML4_BASE) == 0x1ed);
181 ASSERT(VAtoIndex2(PML4_BASE) == 0x1ed);
182 ASSERT(VAtoIndex1(PML4_BASE) == 0x1ed);
183
184 /* Setup low memory pages */
185 if (FrLdrMapRangeOfPages(0, 0, 1024) < 1024)
186 {
187 DbgPrint((DPRINT_WARNING, "Could not map low memory pages.\n"));
188 }
189
190 /* Setup kernel pages */
191 KernelPages = (ROUND_TO_PAGES(NextModuleBase - KERNEL_BASE_PHYS) / PAGE_SIZE);
192 DbgPrint((DPRINT_WARNING, "Trying to map %d pages for kernel.\n", KernelPages));
193 if (FrLdrMapRangeOfPages(KernelBase, KERNEL_BASE_PHYS, KernelPages) != KernelPages)
194 {
195 DbgPrint((DPRINT_WARNING, "Could not map %d kernel pages.\n", KernelPages));
196 }
197
198 }
199