[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / arch / arm / winldr.c
1 /*
2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/freeldr/arch/arm/loader.c
5 * PURPOSE: ARM Kernel Loader
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES ***************************************************************/
10
11 #include <freeldr.h>
12 #include <debug.h>
13 #include <internal/arm/mm.h>
14 #include <internal/arm/intrin_i.h>
15
16 #define PFN_SHIFT 12
17 #define LARGE_PFN_SHIFT 20
18
19 #define PTE_BASE 0xC0000000
20 #define PDE_BASE 0xC0400000
21 #define PDR_BASE 0xFFD00000
22 #define VECTOR_BASE 0xFFFF0000
23
24 #ifdef _ZOOM2_
25 #define IDMAP_BASE 0x81000000
26 #define MMIO_BASE 0x10000000
27 #else
28 #define IDMAP_BASE 0x00000000
29 #define MMIO_BASE 0x10000000
30 #endif
31
32 #define LowMemPageTableIndex (IDMAP_BASE >> PDE_SHIFT)
33 #define MmioPageTableIndex (MMIO_BASE >> PDE_SHIFT)
34 #define KernelPageTableIndex (KSEG0_BASE >> PDE_SHIFT)
35 #define StartupPtePageTableIndex (PTE_BASE >> PDE_SHIFT)
36 #define StartupPdePageTableIndex (PDE_BASE >> PDE_SHIFT)
37 #define PdrPageTableIndex (PDR_BASE >> PDE_SHIFT)
38 #define VectorPageTableIndex (VECTOR_BASE >> PDE_SHIFT)
39
40 #ifndef _ZOOM2_
41 PVOID MempPdrBaseAddress = (PVOID)0x70000;
42 PVOID MempKernelBaseAddress = (PVOID)0;
43 #else
44 PVOID MempPdrBaseAddress = (PVOID)0x81100000;
45 PVOID MempKernelBaseAddress = (PVOID)0x80000000;
46 #endif
47
48 /* Converts a Physical Address into a Page Frame Number */
49 #define PaToPfn(p) ((p) >> PFN_SHIFT)
50 #define PaToLargePfn(p) ((p) >> LARGE_PFN_SHIFT)
51 #define PaPtrToPfn(p) (((ULONG_PTR)(p)) >> PFN_SHIFT)
52
53 /* Converts a Physical Address into a Coarse Page Table PFN */
54 #define PaPtrToPdePfn(p) (((ULONG_PTR)(p)) >> CPT_SHIFT)
55
56 typedef struct _KPDR_PAGE
57 {
58 PAGE_DIRECTORY_ARM PageDir; // 0xC0400000 [0xFFD00000]
59 CHAR HyperSpace[233 * PAGE_SIZE]; // 0xC0404000 [0xFFD04000]
60 PAGE_TABLE_ARM KernelPageTable[3]; // 0xC04ED000 [0xFFDED000]
61 CHAR SharedData[PAGE_SIZE]; // 0xC04F0000 [0xFFDF0000]
62 CHAR KernelStack[KERNEL_STACK_SIZE]; // 0xC04F1000 [0xFFDF1000]
63 CHAR PanicStack[KERNEL_STACK_SIZE]; // 0xC04F4000 [0xFFDF4000]
64 CHAR InterruptStack[KERNEL_STACK_SIZE]; // 0xC04F7000 [0xFFDF7000]
65 CHAR InitialProcess[PAGE_SIZE]; // 0xC04FA000 [0xFFDFA000]
66 CHAR InitialThread[PAGE_SIZE]; // 0xC04FB000 [0xFFDFB000]
67 CHAR Prcb[PAGE_SIZE]; // 0xC04FC000 [0xFFDFC000]
68 PAGE_TABLE_ARM PageDirPageTable; // 0xC04FD000 [0xFFDFD000]
69 PAGE_TABLE_ARM VectorPageTable; // 0xC04FE000 [0xFFDFE000]
70 CHAR Pcr[PAGE_SIZE]; // 0xC04FF000 [0xFFDFF000]
71 } KPDR_PAGE, *PKPDR_PAGE;
72
73 C_ASSERT(sizeof(KPDR_PAGE) == (1 * 1024 * 1024));
74
75 HARDWARE_PTE_ARMV6 TempPte;
76 HARDWARE_LARGE_PTE_ARMV6 TempLargePte;
77 HARDWARE_PDE_ARMV6 TempPde;
78 PKPDR_PAGE PdrPage;
79
80 /* FUNCTIONS **************************************************************/
81
82 BOOLEAN
83 MempSetupPaging(IN PFN_NUMBER StartPage,
84 IN PFN_NUMBER NumberOfPages,
85 IN BOOLEAN KernelMapping)
86 {
87 return TRUE;
88 }
89
90 VOID
91 MempUnmapPage(IN PFN_NUMBER Page)
92 {
93 return;
94 }
95
96 VOID
97 MempDump(VOID)
98 {
99 return;
100 }
101
102 BOOLEAN
103 WinLdrMapSpecialPages(ULONG PcrBasePage)
104 {
105 ULONG i;
106 PHARDWARE_PTE_ARMV6 PointerPte;
107 PHARDWARE_PDE_ARMV6 PointerPde;
108 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
109 PFN_NUMBER Pfn;
110
111 /* Setup the Startup PDE */
112 LargePte = &PdrPage->PageDir.Pte[StartupPdePageTableIndex];
113 TempLargePte.PageFrameNumber = PaToLargePfn((ULONG_PTR)&PdrPage->PageDir);
114 *LargePte = TempLargePte;
115
116 /* Map-in the PDR */
117 LargePte = &PdrPage->PageDir.Pte[PdrPageTableIndex];
118 *LargePte = TempLargePte;
119
120 /* After this point, any MiAddressToPde is guaranteed not to fault */
121
122 /*
123 * Link them in the Startup PDE.
124 * Note these are the entries in the PD at (MiAddressToPde(PTE_BASE)).
125 */
126 PointerPde = &PdrPage->PageDir.Pde[StartupPtePageTableIndex];
127 Pfn = PaPtrToPdePfn(&PdrPage->PageDirPageTable);
128 for (i = 0; i < 4; i++)
129 {
130 TempPde.PageFrameNumber = Pfn++;
131 *PointerPde++ = TempPde;
132 }
133
134 /*
135 * Now map these page tables in PTE space (MiAddressToPte(PTE_BASE)).
136 * Note that they all live on a single page, since each is 1KB.
137 */
138 PointerPte = &PdrPage->PageDirPageTable.Pte[0x300];
139 TempPte.PageFrameNumber = PaPtrToPfn(&PdrPage->PageDirPageTable);
140 *PointerPte = TempPte;
141
142 /*
143 * After this point, MiAddressToPte((PDE_BASE) to MiAddressToPte(PDE_TOP))
144 * is guaranteed not to fault.
145 * Any subsequent page allocation will first need its page table created
146 * and mapped in the PTE_BASE first, then the page table itself will be
147 * editable through its flat PTE address.
148 */
149
150 /* Setup the Vector PDE */
151 PointerPde = &PdrPage->PageDir.Pde[VectorPageTableIndex];
152 TempPde.PageFrameNumber = PaPtrToPdePfn(&PdrPage->VectorPageTable);
153 *PointerPde = TempPde;
154
155 /* Setup the Vector PTEs */
156 PointerPte = &PdrPage->VectorPageTable.Pte[0xF0];
157 TempPte.PageFrameNumber = 0;
158 *PointerPte = TempPte;
159
160 /* TODO: Map in the kernel CPTs */
161 return TRUE;
162 }
163
164 VOID
165 WinLdrSetupForNt(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
166 IN PVOID *GdtIdt,
167 IN ULONG *PcrBasePage,
168 IN ULONG *TssBasePage)
169 {
170 PKPDR_PAGE PdrPage = (PVOID)0xFFD00000;
171
172 /* Load cache information */
173 LoaderBlock->u.Arm.FirstLevelDcacheSize = FirstLevelDcacheSize;
174 LoaderBlock->u.Arm.FirstLevelDcacheFillSize = FirstLevelDcacheFillSize;
175 LoaderBlock->u.Arm.FirstLevelIcacheSize = FirstLevelIcacheSize;
176 LoaderBlock->u.Arm.FirstLevelIcacheFillSize = FirstLevelIcacheFillSize;
177 LoaderBlock->u.Arm.SecondLevelDcacheSize = SecondLevelDcacheSize;
178 LoaderBlock->u.Arm.SecondLevelDcacheFillSize = SecondLevelDcacheFillSize;
179 LoaderBlock->u.Arm.SecondLevelIcacheSize = SecondLevelIcacheSize;
180 LoaderBlock->u.Arm.SecondLevelIcacheFillSize = SecondLevelIcacheSize;
181
182 /* Write initial context information */
183 LoaderBlock->KernelStack = (ULONG_PTR)PdrPage->KernelStack;
184 LoaderBlock->KernelStack += KERNEL_STACK_SIZE;
185 LoaderBlock->u.Arm.PanicStack = (ULONG_PTR)PdrPage->PanicStack;
186 LoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
187 LoaderBlock->u.Arm.InterruptStack = (ULONG_PTR)PdrPage->InterruptStack;
188 LoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
189 LoaderBlock->Prcb = (ULONG_PTR)PdrPage->Prcb;
190 LoaderBlock->Process = (ULONG_PTR)PdrPage->InitialProcess;
191 LoaderBlock->Thread = (ULONG_PTR)PdrPage->InitialThread;
192 }
193
194 BOOLEAN
195 MempAllocatePageTables(VOID)
196 {
197 ULONG i;
198 PHARDWARE_PTE_ARMV6 PointerPte;
199 PHARDWARE_PDE_ARMV6 PointerPde;
200 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
201 PFN_NUMBER Pfn;
202
203 /* Setup templates */
204 TempPte.Sbo = TempPte.Valid = TempLargePte.LargePage = TempLargePte.Sbo = TempPde.Valid = 1;
205
206 /* Allocate the 1MB "PDR" (Processor Data Region). Must be 1MB aligned */
207 PdrPage = MmAllocateMemoryAtAddress(sizeof(KPDR_PAGE),
208 MempPdrBaseAddress,
209 LoaderMemoryData);
210
211 /* Setup the Low Memory PDE as an identity-mapped Large Page (1MB) */
212 LargePte = &PdrPage->PageDir.Pte[LowMemPageTableIndex];
213 TempLargePte.PageFrameNumber = PaToLargePfn(IDMAP_BASE);
214 *LargePte = TempLargePte;
215
216 /* Setup the MMIO PDE as two identity mapped large pages -- the kernel will blow these away later */
217 LargePte = &PdrPage->PageDir.Pte[MmioPageTableIndex];
218 Pfn = PaToLargePfn(MMIO_BASE);
219 for (i = 0; i < 2; i++)
220 {
221 TempLargePte.PageFrameNumber = Pfn++;
222 *LargePte++ = TempLargePte;
223 }
224
225 /* Setup the Kernel PDEs */
226 PointerPde = &PdrPage->PageDir.Pde[KernelPageTableIndex];
227 Pfn = PaPtrToPdePfn(PdrPage->KernelPageTable);
228 for (i = 0; i < 12; i++)
229 {
230 TempPde.PageFrameNumber = Pfn;
231 *PointerPde++ = TempPde;
232 Pfn++;
233 }
234
235 /* Setup the Kernel PTEs */
236 PointerPte = PdrPage->KernelPageTable[0].Pte;
237 Pfn = PaPtrToPfn(MempKernelBaseAddress);
238 for (i = 0; i < 3072; i++)
239 {
240 TempPte.PageFrameNumber = Pfn++;
241 *PointerPte++ = TempPte;
242 }
243
244 /* Done */
245 return TRUE;
246 }
247
248 VOID
249 WinLdrSetProcessorContext(VOID)
250 {
251 ARM_CONTROL_REGISTER ControlRegister;
252 ARM_TTB_REGISTER TtbRegister;
253 ARM_DOMAIN_REGISTER DomainRegister;
254
255 /* Set the TTBR */
256 TtbRegister.AsUlong = (ULONG_PTR)&PdrPage->PageDir;
257 ASSERT(TtbRegister.Reserved == 0);
258 KeArmTranslationTableRegisterSet(TtbRegister);
259
260 /* Disable domains and simply use access bits on PTEs */
261 DomainRegister.AsUlong = 0;
262 DomainRegister.Domain0 = ClientDomain;
263 KeArmDomainRegisterSet(DomainRegister);
264
265 /* Enable ARMv6+ paging (MMU), caches and the access bit */
266 ControlRegister = KeArmControlRegisterGet();
267 ControlRegister.MmuEnabled = TRUE;
268 ControlRegister.ICacheEnabled = TRUE;
269 ControlRegister.DCacheEnabled = TRUE;
270 ControlRegister.ForceAp = TRUE;
271 ControlRegister.ExtendedPageTables = TRUE;
272 KeArmControlRegisterSet(ControlRegister);
273 }
274
275 VOID
276 WinLdrSetupMachineDependent(
277 PLOADER_PARAMETER_BLOCK LoaderBlock)
278 {
279 }
280
281 VOID DiskStopFloppyMotor(VOID)
282 {
283 }
284
285 VOID
286 RealEntryPoint(VOID)
287 {
288 BootMain("");
289 }
290
291 VOID
292 NTAPI
293 FrLdrBugCheckWithMessage(
294 ULONG BugCode,
295 PCHAR File,
296 ULONG Line,
297 PSTR Format,
298 ...)
299 {
300
301 }