xref: /reactos/ntoskrnl/ke/arm/kiinit.c (revision 8a92b556)
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 VOID
331 KiInitializeSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
332 {
333     ULONG Cpu;
334     PKTHREAD InitialThread;
335     PKPROCESS InitialProcess;
336     ARM_CONTROL_REGISTER ControlRegister;
337     PKIPCR Pcr = (PKIPCR)KeGetPcr();
338     PKTHREAD Thread;
339 
340     /* Flush the TLB */
341     KeFlushTb();
342 
343     /* Save the loader block and get the current CPU */
344     KeLoaderBlock = LoaderBlock;
345     Cpu = KeNumberProcessors;
346 
347     /* Save the initial thread and process */
348     InitialThread = (PKTHREAD)LoaderBlock->Thread;
349     InitialProcess = (PKPROCESS)LoaderBlock->Process;
350 
351     /* Clean the APC List Head */
352     InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
353 
354     /* Initialize the machine type */
355     KiInitializeMachineType();
356 
357     /* Skip initial setup if this isn't the Boot CPU */
358     if (Cpu) goto AppCpuInit;
359 
360     /* Initialize the PCR */
361     RtlZeroMemory(Pcr, PAGE_SIZE);
362     KiInitializePcr(Cpu,
363                     Pcr,
364                     InitialThread,
365                     (PVOID)LoaderBlock->u.Arm.PanicStack,
366                     (PVOID)LoaderBlock->u.Arm.InterruptStack);
367 
368     /* Now sweep caches */
369     HalSweepIcache();
370     HalSweepDcache();
371 
372     /* Set us as the current process */
373     InitialThread->ApcState.Process = InitialProcess;
374 
375 AppCpuInit:
376     /* Setup CPU-related fields */
377     Pcr->Prcb.Number = Cpu;
378     Pcr->Prcb.SetMember = 1 << Cpu;
379 
380     /* Initialize the Processor with HAL */
381     HalInitializeProcessor(Cpu, KeLoaderBlock);
382 
383     /* Set active processors */
384     KeActiveProcessors |= Pcr->Prcb.SetMember;
385     KeNumberProcessors++;
386 
387     /* Check if this is the boot CPU */
388     if (!Cpu)
389     {
390         /* Initialize debugging system */
391         KdInitSystem(0, KeLoaderBlock);
392 
393         /* Check for break-in */
394         if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
395     }
396 
397     /* Raise to HIGH_LEVEL */
398     KfRaiseIrql(HIGH_LEVEL);
399 
400     /* Set the exception address to high */
401     ControlRegister = KeArmControlRegisterGet();
402     ControlRegister.HighVectors = TRUE;
403     KeArmControlRegisterSet(ControlRegister);
404 
405     /* Setup the exception vector table */
406     RtlCopyMemory((PVOID)0xFFFF0000, &KiArmVectorTable, 14 * sizeof(PVOID));
407 
408     /* Initialize the rest of the kernel now */
409     KiInitializeKernel((PKPROCESS)LoaderBlock->Process,
410                        (PKTHREAD)LoaderBlock->Thread,
411                        (PVOID)LoaderBlock->KernelStack,
412                        &Pcr->Prcb,
413                        Pcr->Prcb.Number,
414                        KeLoaderBlock);
415 
416     /* Set the priority of this thread to 0 */
417     Thread = KeGetCurrentThread();
418     Thread->Priority = 0;
419 
420     /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
421     _enable();
422     KfLowerIrql(DISPATCH_LEVEL);
423 
424     /* Set the right wait IRQL */
425     Thread->WaitIrql = DISPATCH_LEVEL;
426 
427     /* Jump into the idle loop */
428     KiIdleLoop();
429 }
430 
431 ULONG
432 DbgPrintEarly(const char *fmt, ...)
433 {
434     va_list args;
435     unsigned int i;
436     char Buffer[1024];
437     PCHAR String = Buffer;
438 
439     va_start(args, fmt);
440     i = vsprintf(Buffer, fmt, args);
441     va_end(args);
442 
443     /* Output the message */
444     while (*String != 0)
445     {
446         if (*String == '\n')
447         {
448             KdPortPutByteEx(NULL, '\r');
449         }
450         KdPortPutByteEx(NULL, *String);
451         String++;
452     }
453 
454     return STATUS_SUCCESS;
455 }
456