[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / ntldr / 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/freeldr/arch/arm/winldr.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 static
103 BOOLEAN
104 WinLdrMapSpecialPages(ULONG PcrBasePage)
105 {
106 ULONG i;
107 PHARDWARE_PTE_ARMV6 PointerPte;
108 PHARDWARE_PDE_ARMV6 PointerPde;
109 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
110 PFN_NUMBER Pfn;
111
112 /* Setup the Startup PDE */
113 LargePte = &PdrPage->PageDir.Pte[StartupPdePageTableIndex];
114 TempLargePte.PageFrameNumber = PaToLargePfn((ULONG_PTR)&PdrPage->PageDir);
115 *LargePte = TempLargePte;
116
117 /* Map-in the PDR */
118 LargePte = &PdrPage->PageDir.Pte[PdrPageTableIndex];
119 *LargePte = TempLargePte;
120
121 /* After this point, any MiAddressToPde is guaranteed not to fault */
122
123 /*
124 * Link them in the Startup PDE.
125 * Note these are the entries in the PD at (MiAddressToPde(PTE_BASE)).
126 */
127 PointerPde = &PdrPage->PageDir.Pde[StartupPtePageTableIndex];
128 Pfn = PaPtrToPdePfn(&PdrPage->PageDirPageTable);
129 for (i = 0; i < 4; i++)
130 {
131 TempPde.PageFrameNumber = Pfn++;
132 *PointerPde++ = TempPde;
133 }
134
135 /*
136 * Now map these page tables in PTE space (MiAddressToPte(PTE_BASE)).
137 * Note that they all live on a single page, since each is 1KB.
138 */
139 PointerPte = &PdrPage->PageDirPageTable.Pte[0x300];
140 TempPte.PageFrameNumber = PaPtrToPfn(&PdrPage->PageDirPageTable);
141 *PointerPte = TempPte;
142
143 /*
144 * After this point, MiAddressToPte((PDE_BASE) to MiAddressToPte(PDE_TOP))
145 * is guaranteed not to fault.
146 * Any subsequent page allocation will first need its page table created
147 * and mapped in the PTE_BASE first, then the page table itself will be
148 * editable through its flat PTE address.
149 */
150
151 /* Setup the Vector PDE */
152 PointerPde = &PdrPage->PageDir.Pde[VectorPageTableIndex];
153 TempPde.PageFrameNumber = PaPtrToPdePfn(&PdrPage->VectorPageTable);
154 *PointerPde = TempPde;
155
156 /* Setup the Vector PTEs */
157 PointerPte = &PdrPage->VectorPageTable.Pte[0xF0];
158 TempPte.PageFrameNumber = 0;
159 *PointerPte = TempPte;
160
161 /* TODO: Map in the kernel CPTs */
162 return TRUE;
163 }
164
165 VOID
166 WinLdrSetupForNt(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
167 IN PVOID *GdtIdt,
168 IN ULONG *PcrBasePage,
169 IN ULONG *TssBasePage)
170 {
171 PKPDR_PAGE PdrPage = (PVOID)0xFFD00000;
172
173 /* Load cache information */
174 LoaderBlock->u.Arm.FirstLevelDcacheSize = FirstLevelDcacheSize;
175 LoaderBlock->u.Arm.FirstLevelDcacheFillSize = FirstLevelDcacheFillSize;
176 LoaderBlock->u.Arm.FirstLevelIcacheSize = FirstLevelIcacheSize;
177 LoaderBlock->u.Arm.FirstLevelIcacheFillSize = FirstLevelIcacheFillSize;
178 LoaderBlock->u.Arm.SecondLevelDcacheSize = SecondLevelDcacheSize;
179 LoaderBlock->u.Arm.SecondLevelDcacheFillSize = SecondLevelDcacheFillSize;
180 LoaderBlock->u.Arm.SecondLevelIcacheSize = SecondLevelIcacheSize;
181 LoaderBlock->u.Arm.SecondLevelIcacheFillSize = SecondLevelIcacheSize;
182
183 /* Write initial context information */
184 LoaderBlock->KernelStack = (ULONG_PTR)PdrPage->KernelStack;
185 LoaderBlock->KernelStack += KERNEL_STACK_SIZE;
186 LoaderBlock->u.Arm.PanicStack = (ULONG_PTR)PdrPage->PanicStack;
187 LoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
188 LoaderBlock->u.Arm.InterruptStack = (ULONG_PTR)PdrPage->InterruptStack;
189 LoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
190 LoaderBlock->Prcb = (ULONG_PTR)PdrPage->Prcb;
191 LoaderBlock->Process = (ULONG_PTR)PdrPage->InitialProcess;
192 LoaderBlock->Thread = (ULONG_PTR)PdrPage->InitialThread;
193 }
194
195 static
196 BOOLEAN
197 MempAllocatePageTables(VOID)
198 {
199 ULONG i;
200 PHARDWARE_PTE_ARMV6 PointerPte;
201 PHARDWARE_PDE_ARMV6 PointerPde;
202 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
203 PFN_NUMBER Pfn;
204
205 /* Setup templates */
206 TempPte.Sbo = TempPte.Valid = TempLargePte.LargePage = TempLargePte.Sbo = TempPde.Valid = 1;
207
208 /* Allocate the 1MB "PDR" (Processor Data Region). Must be 1MB aligned */
209 PdrPage = MmAllocateMemoryAtAddress(sizeof(KPDR_PAGE),
210 MempPdrBaseAddress,
211 LoaderMemoryData);
212
213 /* Setup the Low Memory PDE as an identity-mapped Large Page (1MB) */
214 LargePte = &PdrPage->PageDir.Pte[LowMemPageTableIndex];
215 TempLargePte.PageFrameNumber = PaToLargePfn(IDMAP_BASE);
216 *LargePte = TempLargePte;
217
218 /* Setup the MMIO PDE as two identity mapped large pages -- the kernel will blow these away later */
219 LargePte = &PdrPage->PageDir.Pte[MmioPageTableIndex];
220 Pfn = PaToLargePfn(MMIO_BASE);
221 for (i = 0; i < 2; i++)
222 {
223 TempLargePte.PageFrameNumber = Pfn++;
224 *LargePte++ = TempLargePte;
225 }
226
227 /* Setup the Kernel PDEs */
228 PointerPde = &PdrPage->PageDir.Pde[KernelPageTableIndex];
229 Pfn = PaPtrToPdePfn(PdrPage->KernelPageTable);
230 for (i = 0; i < 12; i++)
231 {
232 TempPde.PageFrameNumber = Pfn;
233 *PointerPde++ = TempPde;
234 Pfn++;
235 }
236
237 /* Setup the Kernel PTEs */
238 PointerPte = PdrPage->KernelPageTable[0].Pte;
239 Pfn = PaPtrToPfn(MempKernelBaseAddress);
240 for (i = 0; i < 3072; i++)
241 {
242 TempPte.PageFrameNumber = Pfn++;
243 *PointerPte++ = TempPte;
244 }
245
246 /* Done */
247 return TRUE;
248 }
249
250 VOID
251 WinLdrSetProcessorContext(VOID)
252 {
253 ARM_CONTROL_REGISTER ControlRegister;
254 ARM_TTB_REGISTER TtbRegister;
255 ARM_DOMAIN_REGISTER DomainRegister;
256
257 /* Set the TTBR */
258 TtbRegister.AsUlong = (ULONG_PTR)&PdrPage->PageDir;
259 ASSERT(TtbRegister.Reserved == 0);
260 KeArmTranslationTableRegisterSet(TtbRegister);
261
262 /* Disable domains and simply use access bits on PTEs */
263 DomainRegister.AsUlong = 0;
264 DomainRegister.Domain0 = ClientDomain;
265 KeArmDomainRegisterSet(DomainRegister);
266
267 /* Enable ARMv6+ paging (MMU), caches and the access bit */
268 ControlRegister = KeArmControlRegisterGet();
269 ControlRegister.MmuEnabled = TRUE;
270 ControlRegister.ICacheEnabled = TRUE;
271 ControlRegister.DCacheEnabled = TRUE;
272 ControlRegister.ForceAp = TRUE;
273 ControlRegister.ExtendedPageTables = TRUE;
274 KeArmControlRegisterSet(ControlRegister);
275 }
276
277 VOID
278 WinLdrSetupMachineDependent(
279 PLOADER_PARAMETER_BLOCK LoaderBlock)
280 {
281 }