We now define the cache and id registers in CP15 (C0 Opcode 0 and 1).
[reactos.git] / reactos / boot / freeldr / freeldr / arch / arm / loader.c
1 /*
2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: GPL - See COPYING 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 <internal/arm/ke.h>
13 #include <internal/arm/mm.h>
14 #include <internal/arm/intrin_i.h>
15
16 /* GLOBALS ********************************************************************/
17
18 ULONG PageDirectoryStart, PageDirectoryEnd;
19 LOADER_PARAMETER_BLOCK ArmLoaderBlock;
20 LOADER_PARAMETER_EXTENSION ArmExtension;
21 extern ARM_TRANSLATION_TABLE ArmTranslationTable;
22 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
23
24 ULONG SizeBits[] =
25 {
26 -1, // INVALID
27 -1, // INVALID
28 1 << 12, // 4KB
29 1 << 13, // 8KB
30 1 << 14, // 16KB
31 1 << 15, // 32KB
32 1 << 16, // 64KB
33 1 << 17 // 128KB
34 };
35
36 ULONG AssocBits[] =
37 {
38 -1, // INVALID
39 -1, // INVALID
40 4 // 4-way associative
41 };
42
43 ULONG LenBits[] =
44 {
45 -1, // INVALID
46 -1, // INVALID
47 8 // 8 words per line (32 bytes)
48 };
49
50 /* FUNCTIONS ******************************************************************/
51
52 VOID
53 ArmSetupPageDirectory(VOID)
54 {
55 ARM_TTB_REGISTER TtbRegister;
56 ARM_DOMAIN_REGISTER DomainRegister;
57 ARM_PTE Pte;
58 ULONG i;
59 PARM_TRANSLATION_TABLE TranslationTable;
60
61 //
62 // Allocate translation table buffer.
63 // During bootstrap, this will be a simple L1 (Master) Page Table with
64 // Section entries for KSEG0 and the first MB of RAM.
65 //
66 TranslationTable = &ArmTranslationTable;
67 if (!TranslationTable) return;
68
69 //
70 // Set it as the TTB
71 //
72 TtbRegister.AsUlong = (ULONG)TranslationTable;
73 ASSERT(TtbRegister.Reserved == 0);
74 KeArmTranslationTableRegisterSet(TtbRegister);
75
76 //
77 // Use Domain 0, enforce AP bits (client)
78 //
79 DomainRegister.AsUlong = 0;
80 DomainRegister.Domain0 = ClientDomain;
81 KeArmDomainRegisterSet(DomainRegister);
82
83 //
84 // Set Fault PTEs everywhere
85 //
86 RtlZeroMemory(TranslationTable, 4096 * sizeof(ARM_PTE));
87
88 //
89 // Build the template PTE
90 //
91 Pte.L1.Section.Type = SectionPte;
92 Pte.L1.Section.Buffered = FALSE;
93 Pte.L1.Section.Cached = FALSE;
94 Pte.L1.Section.Reserved = 1; // ARM926EJ-S manual recommends setting to 1
95 Pte.L1.Section.Domain = Domain0;
96 Pte.L1.Section.Access = SupervisorAccess;
97 Pte.L1.Section.BaseAddress = 0;
98 Pte.L1.Section.Ignored = Pte.L1.Section.Ignored1 = 0;
99
100 //
101 // Map KSEG0 (0x80000000 - 0xA0000000) to 0x00000000 - 0x20000000
102 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
103 // which is the entrypoint, just like on x86.
104 //
105 for (i = (KSEG0_BASE >> TTB_SHIFT); i < ((KSEG0_BASE + 0x20000000) >> TTB_SHIFT); i++)
106 {
107 //
108 // Write PTE and update the base address (next MB) for the next one
109 //
110 TranslationTable->Pte[i] = Pte;
111 Pte.L1.Section.BaseAddress++;
112 }
113
114 //
115 // Identity map the first MB of memory as well
116 //
117 Pte.L1.Section.BaseAddress = 0;
118 TranslationTable->Pte[0] = Pte;
119 }
120
121 VOID
122 ArmSetupPagingAndJump(IN ULONG Magic)
123 {
124 ARM_CONTROL_REGISTER ControlRegister;
125
126 //
127 // Enable MMU, DCache and ICache
128 //
129 ControlRegister = KeArmControlRegisterGet();
130 ControlRegister.MmuEnabled = TRUE;
131 ControlRegister.ICacheEnabled = TRUE;
132 ControlRegister.DCacheEnabled = TRUE;
133 KeArmControlRegisterSet(ControlRegister);
134
135 //
136 // Jump to Kernel
137 //
138 (*KernelEntryPoint)(Magic, (PVOID)&ArmLoaderBlock);
139 }
140
141 VOID
142 ArmPrepareForReactOS(IN BOOLEAN Setup)
143 {
144 ARM_CACHE_REGISTER CacheReg;
145 PVOID Base;
146
147 //
148 // Initialize the loader block
149 //
150 InitializeListHead(&ArmLoaderBlock.BootDriverListHead);
151 InitializeListHead(&ArmLoaderBlock.LoadOrderListHead);
152 InitializeListHead(&ArmLoaderBlock.MemoryDescriptorListHead);
153
154 //
155 // Setup the extension and setup block
156 //
157 ArmLoaderBlock.Extension = &ArmExtension;
158 ArmLoaderBlock.SetupLdrBlock = NULL;
159
160 //
161 // TODO: Setup memory descriptors
162 //
163
164 //
165 // TODO: Setup registry data
166 //
167
168 //
169 // TODO: Setup ARC Hardware tree data
170 //
171
172 //
173 // TODO: Setup NLS data
174 //
175
176 //
177 // TODO: Setup boot-driver data
178 //
179
180 //
181 // TODO: Setup extension parameters
182 //
183
184 //
185 // Send the command line
186 //
187 ArmLoaderBlock.LoadOptions = reactos_kernel_cmdline;
188
189 //
190 // Setup cache information
191 //
192 CacheReg = KeArmCacheRegisterGet();
193 ArmLoaderBlock.u.Arm.FirstLevelDcacheSize = SizeBits[CacheReg.DSize];
194 ArmLoaderBlock.u.Arm.FirstLevelDcacheFillSize = LenBits[CacheReg.DLength];
195 ArmLoaderBlock.u.Arm.FirstLevelDcacheFillSize <<= 2;
196 ArmLoaderBlock.u.Arm.FirstLevelIcacheSize = SizeBits[CacheReg.ISize];
197 ArmLoaderBlock.u.Arm.FirstLevelIcacheFillSize = LenBits[CacheReg.ILength];
198 ArmLoaderBlock.u.Arm.FirstLevelIcacheFillSize <<= 2;
199 ArmLoaderBlock.u.Arm.SecondLevelDcacheSize =
200 ArmLoaderBlock.u.Arm.SecondLevelDcacheFillSize =
201 ArmLoaderBlock.u.Arm.SecondLevelIcacheSize =
202 ArmLoaderBlock.u.Arm.SecondLevelIcacheFillSize = 0;
203
204 //
205 // Allocate the Interrupt stack
206 //
207 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupDpcStack);
208 ArmLoaderBlock.u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
209
210 //
211 // Allocate the Kernel Boot stack
212 //
213 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupKernelStack);
214 ArmLoaderBlock.KernelStack = KSEG0_BASE | (ULONG)Base;
215
216 //
217 // Allocate the Abort stack
218 //
219 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
220 ArmLoaderBlock.u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
221
222 //
223 // Allocate the PCRs (1MB each for now!)
224 //
225 Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
226 ArmLoaderBlock.u.Arm.PcrPage = (ULONG)Base >> TTB_SHIFT;
227 ArmLoaderBlock.u.Arm.PcrPage2 = ArmLoaderBlock.u.Arm.PcrPage + 1;
228
229 //
230 // Allocate PDR pages
231 //
232 Base = MmAllocateMemoryWithType(3 * 1024 * 1024, LoaderStartupPdrPage);
233 ArmLoaderBlock.u.Arm.PdrPage = (ULONG)Base >> TTB_SHIFT;
234
235 //
236 // Set initial PRCB, Thread and Process on the last PDR page
237 //
238 Base = (PVOID)((ULONG)Base + 2 * 1024 * 1024);
239 ArmLoaderBlock.Prcb = KSEG0_BASE | (ULONG)Base;
240 ArmLoaderBlock.Process = ArmLoaderBlock.Prcb + sizeof(KPRCB);
241 ArmLoaderBlock.Thread = ArmLoaderBlock.Process + sizeof(EPROCESS);
242 }
243
244 VOID
245 FrLdrStartup(IN ULONG Magic)
246 {
247 //
248 // Disable interrupts (aleady done)
249 //
250
251 //
252 // Set proper CPSR (already done)
253 //
254
255 //
256 // Initialize the page directory
257 //
258 ArmSetupPageDirectory();
259
260 //
261 // Initialize paging and load NTOSKRNL
262 //
263 TuiPrintf("Kernel Command Line: %s\n", ArmLoaderBlock.LoadOptions);
264 ArmSetupPagingAndJump(Magic);
265 }