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