- Revert 49927 "Update to trunk" as it breaks KsStudio (again)
[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 MMIO_BASE 0x10000000
23 #define VECTOR_BASE 0xFFFF0000
24
25 #define LowMemPageTableIndex 0
26 #define KernelPageTableIndex (KSEG0_BASE >> PDE_SHIFT)
27 #define StartupPtePageTableIndex (PTE_BASE >> PDE_SHIFT)
28 #define StartupPdePageTableIndex (PDE_BASE >> PDE_SHIFT)
29 #define MmioPageTableIndex (MMIO_BASE >> PDE_SHIFT)
30 #define PdrPageTableIndex (PDR_BASE >> PDE_SHIFT)
31 #define VectorPageTableIndex (VECTOR_BASE >> PDE_SHIFT)
32
33 /* Converts a Physical Address into a Page Frame Number */
34 #define PaToPfn(p) ((p) >> PFN_SHIFT)
35 #define PaToLargePfn(p) ((p) >> LARGE_PFN_SHIFT)
36 #define PaPtrToPfn(p) (((ULONG_PTR)(p)) >> PFN_SHIFT)
37
38 /* Converts a Physical Address into a Coarse Page Table PFN */
39 #define PaPtrToPdePfn(p) (((ULONG_PTR)(p)) >> CPT_SHIFT)
40
41 typedef struct _KPDR_PAGE
42 {
43 PAGE_DIRECTORY_ARM PageDir; // 0xC0400000 [0xFFD00000]
44 CHAR HyperSpace[233 * PAGE_SIZE]; // 0xC0404000 [0xFFD04000]
45 PAGE_TABLE_ARM KernelPageTable[3]; // 0xC04ED000 [0xFFDED000]
46 CHAR SharedData[PAGE_SIZE]; // 0xC04F0000 [0xFFDF0000]
47 CHAR KernelStack[KERNEL_STACK_SIZE]; // 0xC04F1000 [0xFFDF1000]
48 CHAR PanicStack[KERNEL_STACK_SIZE]; // 0xC04F4000 [0xFFDF4000]
49 CHAR InterruptStack[KERNEL_STACK_SIZE]; // 0xC04F7000 [0xFFDF7000]
50 CHAR InitialProcess[PAGE_SIZE]; // 0xC04FA000 [0xFFDFA000]
51 CHAR InitialThread[PAGE_SIZE]; // 0xC04FB000 [0xFFDFB000]
52 CHAR Prcb[PAGE_SIZE]; // 0xC04FC000 [0xFFDFC000]
53 PAGE_TABLE_ARM PageDirPageTable; // 0xC04FD000 [0xFFDFD000]
54 PAGE_TABLE_ARM VectorPageTable; // 0xC04FE000 [0xFFDFE000]
55 CHAR Pcr[PAGE_SIZE]; // 0xC04FF000 [0xFFDFF000]
56 } KPDR_PAGE, *PKPDR_PAGE;
57
58 C_ASSERT(sizeof(KPDR_PAGE) == (1 * 1024 * 1024));
59
60 HARDWARE_PTE_ARMV6 TempPte;
61 HARDWARE_LARGE_PTE_ARMV6 TempLargePte;
62 HARDWARE_PDE_ARMV6 TempPde;
63 PKPDR_PAGE PdrPage;
64
65 /* FUNCTIONS **************************************************************/
66
67 BOOLEAN
68 MempSetupPaging(IN ULONG StartPage,
69 IN ULONG NumberOfPages)
70 {
71 return TRUE;
72 }
73
74 VOID
75 MempUnmapPage(IN ULONG Page)
76 {
77 return;
78 }
79
80 VOID
81 MempDump(VOID)
82 {
83 return;
84 }
85
86 BOOLEAN
87 WinLdrMapSpecialPages(ULONG PcrBasePage)
88 {
89 ULONG i;
90 PHARDWARE_PTE_ARMV6 PointerPte;
91 PHARDWARE_PDE_ARMV6 PointerPde;
92 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
93 PFN_NUMBER Pfn;
94
95 /* Setup the Startup PDE */
96 LargePte = &PdrPage->PageDir.Pte[StartupPdePageTableIndex];
97 TempLargePte.PageFrameNumber = PaToLargePfn((ULONG_PTR)&PdrPage->PageDir);
98 *LargePte = TempLargePte;
99
100 /* Map-in the PDR */
101 LargePte = &PdrPage->PageDir.Pte[PdrPageTableIndex];
102 *LargePte = TempLargePte;
103
104 /* After this point, any MiAddressToPde is guaranteed not to fault */
105
106 /*
107 * Link them in the Startup PDE.
108 * Note these are the entries in the PD at (MiAddressToPde(PTE_BASE)).
109 */
110 PointerPde = &PdrPage->PageDir.Pde[StartupPtePageTableIndex];
111 Pfn = PaPtrToPdePfn(&PdrPage->PageDirPageTable);
112 for (i = 0; i < 4; i++)
113 {
114 TempPde.PageFrameNumber = Pfn++;
115 *PointerPde++ = TempPde;
116 }
117
118 /*
119 * Now map these page tables in PTE space (MiAddressToPte(PTE_BASE)).
120 * Note that they all live on a single page, since each is 1KB.
121 */
122 PointerPte = &PdrPage->PageDirPageTable.Pte[0x300];
123 TempPte.PageFrameNumber = PaPtrToPfn(&PdrPage->PageDirPageTable);
124 *PointerPte = TempPte;
125
126 /*
127 * After this point, MiAddressToPte((PDE_BASE) to MiAddressToPte(PDE_TOP))
128 * is guaranteed not to fault.
129 * Any subsequent page allocation will first need its page table created
130 * and mapped in the PTE_BASE first, then the page table itself will be
131 * editable through its flat PTE address.
132 */
133
134 /* Setup the Vector PDE */
135 PointerPde = &PdrPage->PageDir.Pde[VectorPageTableIndex];
136 TempPde.PageFrameNumber = PaPtrToPdePfn(&PdrPage->VectorPageTable);
137 *PointerPde = TempPde;
138
139 /* Setup the Vector PTEs */
140 PointerPte = &PdrPage->VectorPageTable.Pte[0xF0];
141 TempPte.PageFrameNumber = 0;
142 *PointerPte = TempPte;
143
144 /* TODO: Map in the kernel CPTs */
145 return TRUE;
146 }
147
148 VOID
149 WinLdrSetupForNt(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
150 IN PVOID *GdtIdt,
151 IN ULONG *PcrBasePage,
152 IN ULONG *TssBasePage)
153 {
154 PKPDR_PAGE PdrPage = (PVOID)0xFFD00000;
155
156 /* Load cache information */
157 LoaderBlock->u.Arm.FirstLevelDcacheSize = FirstLevelDcacheSize;
158 LoaderBlock->u.Arm.FirstLevelDcacheFillSize = FirstLevelDcacheFillSize;
159 LoaderBlock->u.Arm.FirstLevelIcacheSize = FirstLevelIcacheSize;
160 LoaderBlock->u.Arm.FirstLevelIcacheFillSize = FirstLevelIcacheFillSize;
161 LoaderBlock->u.Arm.SecondLevelDcacheSize = SecondLevelDcacheSize;
162 LoaderBlock->u.Arm.SecondLevelDcacheFillSize = SecondLevelDcacheFillSize;
163 LoaderBlock->u.Arm.SecondLevelIcacheSize = SecondLevelIcacheSize;
164 LoaderBlock->u.Arm.SecondLevelIcacheFillSize = SecondLevelIcacheSize;
165
166 /* Write initial context information */
167 LoaderBlock->KernelStack = (ULONG_PTR)PdrPage->KernelStack;
168 LoaderBlock->KernelStack += KERNEL_STACK_SIZE;
169 LoaderBlock->u.Arm.PanicStack = (ULONG_PTR)PdrPage->PanicStack;
170 LoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
171 LoaderBlock->u.Arm.InterruptStack = (ULONG_PTR)PdrPage->InterruptStack;
172 LoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
173 LoaderBlock->Prcb = (ULONG_PTR)PdrPage->Prcb;
174 LoaderBlock->Process = (ULONG_PTR)PdrPage->InitialProcess;
175 LoaderBlock->Thread = (ULONG_PTR)PdrPage->InitialThread;
176 }
177
178 BOOLEAN
179 MempAllocatePageTables(VOID)
180 {
181 ULONG i;
182 PHARDWARE_PTE_ARMV6 PointerPte;
183 PHARDWARE_PDE_ARMV6 PointerPde;
184 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
185 PFN_NUMBER Pfn;
186
187 /* Setup templates */
188 TempPte.Accessed = TempPte.Valid = TempLargePte.LargePage = TempLargePte.Accessed = TempPde.Valid = 1;
189
190 /* Allocate the 1MB "PDR" (Processor Data Region). Must be 1MB aligned */
191 PdrPage = MmAllocateMemoryAtAddress(sizeof(KPDR_PAGE), (PVOID)0x700000, LoaderMemoryData);
192
193 /* Setup the Low Memory PDE as an identity-mapped Large Page (1MB) */
194 LargePte = &PdrPage->PageDir.Pte[LowMemPageTableIndex];
195 *LargePte = TempLargePte;
196
197 /* Setup the MMIO PDE as two identity mapped large pages -- the kernel will blow these away later */
198 LargePte = &PdrPage->PageDir.Pte[MmioPageTableIndex];
199 Pfn = PaToLargePfn(0x10000000);
200 for (i = 0; i < 2; i++)
201 {
202 TempLargePte.PageFrameNumber = Pfn++;
203 *LargePte++ = TempLargePte;
204 }
205
206 /* Setup the Kernel PDEs */
207 PointerPde = &PdrPage->PageDir.Pde[KernelPageTableIndex];
208 Pfn = PaPtrToPdePfn(PdrPage->KernelPageTable);
209 for (i = 0; i < 12; i++)
210 {
211 TempPde.PageFrameNumber = Pfn;
212 *PointerPde++ = TempPde;
213 Pfn++;
214 }
215
216 /* Setup the Kernel PTEs */
217 PointerPte = PdrPage->KernelPageTable[0].Pte;
218 Pfn = 0;
219 for (i = 0; i < 3072; i++)
220 {
221 TempPte.PageFrameNumber = Pfn++;
222 *PointerPte++ = TempPte;
223 }
224
225 /* Done */
226 return TRUE;
227 }
228
229 VOID
230 WinLdrSetProcessorContext(PVOID GdtIdt,
231 IN ULONG Pcr,
232 IN ULONG Tss)
233 {
234 ARM_CONTROL_REGISTER ControlRegister;
235 ARM_TTB_REGISTER TtbRegister;
236 ARM_DOMAIN_REGISTER DomainRegister;
237
238 /* Set the TTBR */
239 TtbRegister.AsUlong = (ULONG_PTR)&PdrPage->PageDir;
240 ASSERT(TtbRegister.Reserved == 0);
241 KeArmTranslationTableRegisterSet(TtbRegister);
242
243 /* Disable domains and simply use access bits on PTEs */
244 DomainRegister.AsUlong = 0;
245 DomainRegister.Domain0 = ClientDomain;
246 KeArmDomainRegisterSet(DomainRegister);
247
248 /* Enable ARMv6+ paging (MMU), caches and the access bit */
249 ControlRegister = KeArmControlRegisterGet();
250 ControlRegister.MmuEnabled = TRUE;
251 ControlRegister.ICacheEnabled = TRUE;
252 ControlRegister.DCacheEnabled = TRUE;
253 ControlRegister.ForceAp = TRUE;
254 ControlRegister.ExtendedPageTables = TRUE;
255 KeArmControlRegisterSet(ControlRegister);
256 }