xref: /reactos/ntoskrnl/ke/arm/kiinit.c (revision ea6e7740)
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
36 KiInitMachineDependent(VOID)
37 {
38     /* There is nothing to do on ARM */
39     return;
40 }
41 
42 VOID
43 NTAPI
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                             0xFFFFFFFF,
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
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 = 1;
199     Pcr->Prcb.MinorVersion = 1;
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
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
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
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