1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/arm/kiinit.c
5 * PURPOSE: Implements the kernel entry point for ARM machines
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 VOID
16 NTAPI
17 KdPortPutByteEx(
18 PCPPORT PortInformation,
19 UCHAR ByteToSend
20 );
21
22 /* GLOBALS ********************************************************************/
23
24 KINTERRUPT KxUnexpectedInterrupt;
25 BOOLEAN KeIsArmV6;
26 ULONG KeNumberProcessIds;
27 ULONG KeNumberTbEntries;
28 ULONG ProcessCount; // PERF
29 extern PVOID KiArmVectorTable;
30 #define __ARMV6__ KeIsArmV6
31
32 /* FUNCTIONS ******************************************************************/
33
34 VOID
35 NTAPI
KiInitMachineDependent(VOID)36 KiInitMachineDependent(VOID)
37 {
38 /* There is nothing to do on ARM */
39 return;
40 }
41
42 VOID
43 NTAPI
KiInitializeKernel(IN PKPROCESS InitProcess,IN PKTHREAD InitThread,IN PVOID IdleStack,IN PKPRCB Prcb,IN CCHAR Number,IN PLOADER_PARAMETER_BLOCK LoaderBlock)44 KiInitializeKernel(IN PKPROCESS InitProcess,
45 IN PKTHREAD InitThread,
46 IN PVOID IdleStack,
47 IN PKPRCB Prcb,
48 IN CCHAR Number,
49 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
50 {
51 PKIPCR Pcr = (PKIPCR)KeGetPcr();
52 ULONG PageDirectory[2];
53 ULONG i;
54
55 /* Set the default NX policy (opt-in) */
56 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
57
58 /* Initialize spinlocks and DPC data */
59 KiInitSpinLocks(Prcb, Number);
60
61 /* Set stack pointers */
62 //Pcr->InitialStack = IdleStack;
63 Pcr->Prcb.SpBase = IdleStack; // ???
64
65 /* Check if this is the Boot CPU */
66 if (!Number)
67 {
68 /* Setup the unexpected interrupt */
69 KxUnexpectedInterrupt.DispatchAddress = KiUnexpectedInterrupt;
70 for (i = 0; i < 4; i++)
71 {
72 /* Copy the template code */
73 KxUnexpectedInterrupt.DispatchCode[i] = ((PULONG)KiInterruptTemplate)[i];
74 }
75
76 /* Set DMA coherency */
77 KiDmaIoCoherency = 0;
78
79 /* Sweep D-Cache */
80 HalSweepDcache();
81
82 /* Set boot-level flags */
83 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
84 KeFeatureBits = 0;
85 /// FIXME: just a wild guess
86 KeProcessorLevel = (USHORT)(Pcr->Prcb.ProcessorState.ArchState.Cp15_Cr0_CpuId >> 8);
87 KeProcessorRevision = (USHORT)(Pcr->Prcb.ProcessorState.ArchState.Cp15_Cr0_CpuId & 0xFF);
88 #if 0
89 /* Set the current MP Master KPRCB to the Boot PRCB */
90 Prcb->MultiThreadSetMaster = Prcb;
91 #endif
92 /* Lower to APC_LEVEL */
93 KeLowerIrql(APC_LEVEL);
94
95 /* Initialize portable parts of the OS */
96 KiInitSystem();
97
98 /* Initialize the Idle Process and the Process Listhead */
99 InitializeListHead(&KiProcessListHead);
100 PageDirectory[0] = 0;
101 PageDirectory[1] = 0;
102 KeInitializeProcess(InitProcess,
103 0,
104 MAXULONG_PTR,
105 PageDirectory,
106 FALSE);
107 InitProcess->QuantumReset = MAXCHAR;
108 }
109 else
110 {
111 /* FIXME-V6: See if we want to support MP */
112 DPRINT1("ARM MPCore not supported\n");
113 }
114
115 /* Setup the Idle Thread */
116 KeInitializeThread(InitProcess,
117 InitThread,
118 NULL,
119 NULL,
120 NULL,
121 NULL,
122 NULL,
123 IdleStack);
124 InitThread->NextProcessor = Number;
125 InitThread->Priority = HIGH_PRIORITY;
126 InitThread->State = Running;
127 InitThread->Affinity = 1 << Number;
128 InitThread->WaitIrql = DISPATCH_LEVEL;
129 InitProcess->ActiveProcessors = 1 << Number;
130
131 /* HACK for MmUpdatePageDir */
132 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
133
134 /* Set up the thread-related fields in the PRCB */
135 Prcb->CurrentThread = InitThread;
136 Prcb->NextThread = NULL;
137 Prcb->IdleThread = InitThread;
138
139 /* Initialize the Kernel Executive */
140 ExpInitializeExecutive(Number, LoaderBlock);
141
142 /* Only do this on the boot CPU */
143 if (!Number)
144 {
145 /* Calculate the time reciprocal */
146 KiTimeIncrementReciprocal =
147 KiComputeReciprocal(KeMaximumIncrement,
148 &KiTimeIncrementShiftCount);
149
150 /* Update DPC Values in case they got updated by the executive */
151 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
152 Prcb->MinimumDpcRate = KiMinimumDpcRate;
153 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
154 }
155
156 /* Raise to Dispatch */
157 KfRaiseIrql(DISPATCH_LEVEL);
158
159 /* Set the Idle Priority to 0. This will jump into Phase 1 */
160 KeSetPriorityThread(InitThread, 0);
161
162 /* If there's no thread scheduled, put this CPU in the Idle summary */
163 KiAcquirePrcbLock(Prcb);
164 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
165 KiReleasePrcbLock(Prcb);
166
167 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
168 KfRaiseIrql(HIGH_LEVEL);
169 LoaderBlock->Prcb = 0;
170 }
171
172 //C_ASSERT((PKIPCR)KeGetPcr() == (PKIPCR)0xFFDFF000);
173 //C_ASSERT((FIELD_OFFSET(KIPCR, FirstLevelDcacheSize) & 4) == 0);
174 //C_ASSERT(sizeof(KIPCR) <= PAGE_SIZE);
175
176 VOID
177 NTAPI
KiInitializePcr(IN ULONG ProcessorNumber,IN PKIPCR Pcr,IN PKTHREAD IdleThread,IN PVOID PanicStack,IN PVOID InterruptStack)178 KiInitializePcr(IN ULONG ProcessorNumber,
179 IN PKIPCR Pcr,
180 IN PKTHREAD IdleThread,
181 IN PVOID PanicStack,
182 IN PVOID InterruptStack)
183 {
184 ULONG i;
185
186 /* Set the Current Thread */
187 Pcr->Prcb.CurrentThread = IdleThread;
188
189 /* Set pointers to ourselves */
190 Pcr->Self = (PKPCR)Pcr;
191 Pcr->CurrentPrcb = &Pcr->Prcb;
192
193 /* Set the PCR Version */
194 Pcr->MajorVersion = PCR_MAJOR_VERSION;
195 Pcr->MinorVersion = PCR_MINOR_VERSION;
196
197 /* Set the PCRB Version */
198 Pcr->Prcb.MajorVersion = PRCB_MAJOR_VERSION;
199 Pcr->Prcb.MinorVersion = PRCB_MINOR_VERSION;
200
201 /* Set the Build Type */
202 Pcr->Prcb.BuildType = 0;
203 #ifndef CONFIG_SMP
204 Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR;
205 #endif
206 #if DBG
207 Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG;
208 #endif
209
210 /* Set the Processor Number and current Processor Mask */
211 Pcr->Prcb.Number = (UCHAR)ProcessorNumber;
212 Pcr->Prcb.SetMember = 1 << ProcessorNumber;
213
214 /* Set the PRCB for this Processor */
215 KiProcessorBlock[ProcessorNumber] = Pcr->CurrentPrcb;
216
217 /* Start us out at PASSIVE_LEVEL */
218 Pcr->CurrentIrql = PASSIVE_LEVEL;
219
220 /* Set the stacks */
221 Pcr->Prcb.PanicStackBase = (ULONG)PanicStack;
222 Pcr->Prcb.IsrStack = InterruptStack;
223 #if 0
224 /* Setup the processor set */
225 Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember;
226 #endif
227
228 /* Copy cache information from the loader block */
229 Pcr->Prcb.Cache[FirstLevelDcache].Type = CacheData;
230 Pcr->Prcb.Cache[FirstLevelDcache].Level = 1;
231 Pcr->Prcb.Cache[FirstLevelDcache].Associativity = 0; // FIXME
232 Pcr->Prcb.Cache[FirstLevelDcache].LineSize = KeLoaderBlock->u.Arm.FirstLevelDcacheFillSize;
233 Pcr->Prcb.Cache[FirstLevelDcache].Size = KeLoaderBlock->u.Arm.FirstLevelDcacheSize;
234
235 Pcr->Prcb.Cache[SecondLevelDcache].Type = CacheData;
236 Pcr->Prcb.Cache[SecondLevelDcache].Level = 2;
237 Pcr->Prcb.Cache[SecondLevelDcache].Associativity = 0; // FIXME
238 Pcr->Prcb.Cache[SecondLevelDcache].LineSize = KeLoaderBlock->u.Arm.SecondLevelDcacheFillSize;
239 Pcr->Prcb.Cache[SecondLevelDcache].Size = KeLoaderBlock->u.Arm.SecondLevelDcacheSize;
240
241 Pcr->Prcb.Cache[FirstLevelIcache].Type = CacheInstruction;
242 Pcr->Prcb.Cache[FirstLevelIcache].Level = 1;
243 Pcr->Prcb.Cache[FirstLevelIcache].Associativity = 0; // FIXME
244 Pcr->Prcb.Cache[FirstLevelIcache].LineSize = KeLoaderBlock->u.Arm.FirstLevelIcacheFillSize;
245 Pcr->Prcb.Cache[FirstLevelIcache].Size = KeLoaderBlock->u.Arm.FirstLevelIcacheSize;
246
247 Pcr->Prcb.Cache[SecondLevelIcache].Type = CacheInstruction;
248 Pcr->Prcb.Cache[SecondLevelIcache].Level = 2;
249 Pcr->Prcb.Cache[SecondLevelIcache].Associativity = 0; // FIXME
250 Pcr->Prcb.Cache[SecondLevelIcache].LineSize = KeLoaderBlock->u.Arm.SecondLevelIcacheFillSize;
251 Pcr->Prcb.Cache[SecondLevelIcache].Size = KeLoaderBlock->u.Arm.SecondLevelIcacheSize;
252
253 /* Set global d-cache fill and alignment values */
254 if (Pcr->Prcb.Cache[SecondLevelDcache].Size == 0)
255 {
256 /* Use the first level */
257 Pcr->Prcb.Cache[GlobalDcache] = Pcr->Prcb.Cache[FirstLevelDcache];
258 }
259 else
260 {
261 /* Use the second level */
262 Pcr->Prcb.Cache[GlobalDcache] = Pcr->Prcb.Cache[SecondLevelDcache];
263 }
264
265 /* Set the alignment */
266 //Pcr->DcacheAlignment = Pcr->DcacheFillSize - 1;
267
268 /* Set global i-cache fill and alignment values */
269 if (Pcr->Prcb.Cache[SecondLevelIcache].Size == 0)
270 {
271 /* Use the first level */
272 Pcr->Prcb.Cache[GlobalIcache] = Pcr->Prcb.Cache[FirstLevelIcache];
273 }
274 else
275 {
276 /* Use the second level */
277 Pcr->Prcb.Cache[GlobalIcache] = Pcr->Prcb.Cache[SecondLevelIcache];
278 }
279
280 /* Set the alignment */
281 //Pcr->IcacheAlignment = Pcr->IcacheFillSize - 1;
282
283 /* Set processor information */
284 //Pcr->ProcessorId = KeArmIdCodeRegisterGet().AsUlong;
285
286 /* Set all interrupt routines to unexpected interrupts as well */
287 for (i = 0; i < MAXIMUM_VECTOR; i++)
288 {
289 /* Point to the same template */
290 Pcr->Idt[i] = (PVOID)&KxUnexpectedInterrupt.DispatchCode;
291 }
292
293 /* Set default stall factor */
294 Pcr->StallScaleFactor = 50;
295
296 /* Setup software interrupts */
297 Pcr->Idt[PASSIVE_LEVEL] = KiPassiveRelease;
298 Pcr->Idt[APC_LEVEL] = KiApcInterrupt;
299 Pcr->Idt[DISPATCH_LEVEL] = KiDispatchInterrupt;
300 #if 0
301 Pcr->ReservedVectors = (1 << PASSIVE_LEVEL) |
302 (1 << APC_LEVEL) |
303 (1 << DISPATCH_LEVEL) |
304 (1 << IPI_LEVEL);
305 #endif
306 }
307
308 VOID
KiInitializeMachineType(VOID)309 KiInitializeMachineType(VOID)
310 {
311 /* Detect ARM version */
312 KeIsArmV6 = KeArmIdCodeRegisterGet().Architecture >= 7;
313
314 /* Set the number of TLB entries and ASIDs */
315 KeNumberTbEntries = 64;
316 if (__ARMV6__)
317 {
318 /* 256 ASIDs on v6/v7 */
319 KeNumberProcessIds = 256;
320 }
321 else
322 {
323 /* The TLB is VIVT on v4/v5 */
324 KeNumberProcessIds = 0;
325 }
326 }
327
328 DECLSPEC_NORETURN
329 VOID
KiInitializeSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)330 KiInitializeSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
331 {
332 ULONG Cpu;
333 PKTHREAD InitialThread;
334 PKPROCESS InitialProcess;
335 ARM_CONTROL_REGISTER ControlRegister;
336 PKIPCR Pcr = (PKIPCR)KeGetPcr();
337 PKTHREAD Thread;
338
339 /* Flush the TLB */
340 KeFlushTb();
341
342 /* Save the loader block and get the current CPU */
343 KeLoaderBlock = LoaderBlock;
344 Cpu = KeNumberProcessors;
345
346 /* Save the initial thread and process */
347 InitialThread = (PKTHREAD)LoaderBlock->Thread;
348 InitialProcess = (PKPROCESS)LoaderBlock->Process;
349
350 /* Clean the APC List Head */
351 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
352
353 /* Initialize the machine type */
354 KiInitializeMachineType();
355
356 /* Skip initial setup if this isn't the Boot CPU */
357 if (Cpu) goto AppCpuInit;
358
359 /* Initialize the PCR */
360 RtlZeroMemory(Pcr, PAGE_SIZE);
361 KiInitializePcr(Cpu,
362 Pcr,
363 InitialThread,
364 (PVOID)LoaderBlock->u.Arm.PanicStack,
365 (PVOID)LoaderBlock->u.Arm.InterruptStack);
366
367 /* Now sweep caches */
368 HalSweepIcache();
369 HalSweepDcache();
370
371 /* Set us as the current process */
372 InitialThread->ApcState.Process = InitialProcess;
373
374 AppCpuInit:
375 /* Setup CPU-related fields */
376 Pcr->Prcb.Number = Cpu;
377 Pcr->Prcb.SetMember = 1 << Cpu;
378
379 /* Initialize the Processor with HAL */
380 HalInitializeProcessor(Cpu, KeLoaderBlock);
381
382 /* Set active processors */
383 KeActiveProcessors |= Pcr->Prcb.SetMember;
384 KeNumberProcessors++;
385
386 /* Check if this is the boot CPU */
387 if (!Cpu)
388 {
389 /* Initialize debugging system */
390 KdInitSystem(0, KeLoaderBlock);
391
392 /* Check for break-in */
393 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
394 }
395
396 /* Raise to HIGH_LEVEL */
397 KfRaiseIrql(HIGH_LEVEL);
398
399 /* Set the exception address to high */
400 ControlRegister = KeArmControlRegisterGet();
401 ControlRegister.HighVectors = TRUE;
402 KeArmControlRegisterSet(ControlRegister);
403
404 /* Setup the exception vector table */
405 RtlCopyMemory((PVOID)0xFFFF0000, &KiArmVectorTable, 14 * sizeof(PVOID));
406
407 /* Initialize the rest of the kernel now */
408 KiInitializeKernel((PKPROCESS)LoaderBlock->Process,
409 (PKTHREAD)LoaderBlock->Thread,
410 (PVOID)LoaderBlock->KernelStack,
411 &Pcr->Prcb,
412 Pcr->Prcb.Number,
413 KeLoaderBlock);
414
415 /* Set the priority of this thread to 0 */
416 Thread = KeGetCurrentThread();
417 Thread->Priority = 0;
418
419 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
420 _enable();
421 KfLowerIrql(DISPATCH_LEVEL);
422
423 /* Set the right wait IRQL */
424 Thread->WaitIrql = DISPATCH_LEVEL;
425
426 /* Jump into the idle loop */
427 KiIdleLoop();
428 }
429
430 ULONG
DbgPrintEarly(const char * fmt,...)431 DbgPrintEarly(const char *fmt, ...)
432 {
433 va_list args;
434 unsigned int i;
435 char Buffer[1024];
436 PCHAR String = Buffer;
437
438 va_start(args, fmt);
439 i = vsprintf(Buffer, fmt, args);
440 va_end(args);
441
442 /* Output the message */
443 while (*String != 0)
444 {
445 if (*String == '\n')
446 {
447 KdPortPutByteEx(NULL, '\r');
448 }
449 KdPortPutByteEx(NULL, *String);
450 String++;
451 }
452
453 return STATUS_SUCCESS;
454 }
455