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