xref: /reactos/ntoskrnl/ke/arm/kiinit.c (revision 5abf0c76)
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