xref: /reactos/ntoskrnl/ke/krnlinit.c (revision d8d4d8fa)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ke/krnlinit.c
5  * PURPOSE:         Portable part of kernel initialization
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 #include <internal/napi.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 /* Portable CPU Features and Flags */
19 USHORT KeProcessorArchitecture;
20 USHORT KeProcessorLevel;
21 USHORT KeProcessorRevision;
22 ULONG KeFeatureBits;
23 KAFFINITY KeActiveProcessors = 1;
24 
25 /* System call count */
26 ULONG KiServiceLimit = NUMBER_OF_SYSCALLS;
27 
28 /* ARC Loader Block */
29 PLOADER_PARAMETER_BLOCK KeLoaderBlock;
30 
31 /* PRCB Array */
32 PKPRCB KiProcessorBlock[MAXIMUM_PROCESSORS];
33 
34 /* Number of processors */
35 CCHAR KeNumberProcessors = 0;
36 
37 /* NUMA Node Support */
38 KNODE KiNode0;
39 PKNODE KeNodeBlock[1] = { &KiNode0 };
40 UCHAR KeNumberNodes = 1;
41 UCHAR KeProcessNodeSeed;
42 
43 /* Initial Process and Thread */
44 ETHREAD KiInitialThread;
45 EPROCESS KiInitialProcess;
46 
47 /* System-defined Spinlocks */
48 KSPIN_LOCK KiDispatcherLock;
49 KSPIN_LOCK MmPfnLock;
50 KSPIN_LOCK MmSystemSpaceLock;
51 KSPIN_LOCK CcBcbSpinLock;
52 KSPIN_LOCK CcMasterSpinLock;
53 KSPIN_LOCK CcVacbSpinLock;
54 KSPIN_LOCK CcWorkQueueSpinLock;
55 KSPIN_LOCK NonPagedPoolLock;
56 KSPIN_LOCK MmNonPagedPoolLock;
57 KSPIN_LOCK IopCancelSpinLock;
58 KSPIN_LOCK IopVpbSpinLock;
59 KSPIN_LOCK IopDatabaseLock;
60 KSPIN_LOCK IopCompletionLock;
61 KSPIN_LOCK NtfsStructLock;
62 KSPIN_LOCK AfdWorkQueueSpinLock;
63 KSPIN_LOCK KiTimerTableLock[LOCK_QUEUE_TIMER_TABLE_LOCKS];
64 KSPIN_LOCK KiReverseStallIpiLock;
65 
66 /* FUNCTIONS *****************************************************************/
67 
68 CODE_SEG("INIT")
69 VOID
70 NTAPI
71 KiInitSystem(VOID)
72 {
73     ULONG i;
74 
75     /* Initialize Bugcheck Callback data */
76     InitializeListHead(&KeBugcheckCallbackListHead);
77     InitializeListHead(&KeBugcheckReasonCallbackListHead);
78     KeInitializeSpinLock(&BugCheckCallbackLock);
79 
80     /* Initialize the Timer Expiration DPC */
81     KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL);
82     KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0);
83 
84     /* Initialize Profiling data */
85     KeInitializeSpinLock(&KiProfileLock);
86     InitializeListHead(&KiProfileListHead);
87     InitializeListHead(&KiProfileSourceListHead);
88 
89     /* Loop the timer table */
90     for (i = 0; i < TIMER_TABLE_SIZE; i++)
91     {
92         /* Initialize the list and entries */
93         InitializeListHead(&KiTimerTableListHead[i].Entry);
94         KiTimerTableListHead[i].Time.HighPart = 0xFFFFFFFF;
95         KiTimerTableListHead[i].Time.LowPart = 0;
96     }
97 
98     /* Initialize the Swap event and all swap lists */
99     KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE);
100     InitializeListHead(&KiProcessInSwapListHead);
101     InitializeListHead(&KiProcessOutSwapListHead);
102     InitializeListHead(&KiStackInSwapListHead);
103 
104     /* Initialize the mutex for generic DPC calls */
105     ExInitializeFastMutex(&KiGenericCallDpcMutex);
106 
107     /* Initialize the syscall table */
108     KeServiceDescriptorTable[0].Base = MainSSDT;
109     KeServiceDescriptorTable[0].Count = NULL;
110     KeServiceDescriptorTable[0].Limit = KiServiceLimit;
111     KeServiceDescriptorTable[1].Limit = 0;
112     KeServiceDescriptorTable[0].Number = MainSSPT;
113 
114     /* Copy the the current table into the shadow table for win32k */
115     RtlCopyMemory(KeServiceDescriptorTableShadow,
116                   KeServiceDescriptorTable,
117                   sizeof(KeServiceDescriptorTable));
118 }
119 
120 CODE_SEG("INIT")
121 LARGE_INTEGER
122 NTAPI
123 KiComputeReciprocal(IN LONG Divisor,
124                     OUT PUCHAR Shift)
125 {
126     LARGE_INTEGER Reciprocal = {{0, 0}};
127     LONG BitCount = 0, Remainder = 1;
128 
129     /* Start by calculating the remainder */
130     while (Reciprocal.HighPart >= 0)
131     {
132         /* Increase the loop (bit) count */
133         BitCount++;
134 
135         /* Calculate the current fraction */
136         Reciprocal.HighPart = (Reciprocal.HighPart << 1) |
137                               (Reciprocal.LowPart >> 31);
138         Reciprocal.LowPart <<= 1;
139 
140         /* Double the remainder and see if we went past the divisor */
141         Remainder <<= 1;
142         if (Remainder >= Divisor)
143         {
144             /* Set the low-bit and calculate the new remainder */
145             Remainder -= Divisor;
146             Reciprocal.LowPart |= 1;
147         }
148     }
149 
150     /* Check if we have a remainder */
151     if (Remainder)
152     {
153         /* Check if the current fraction value is too large */
154         if ((Reciprocal.LowPart == 0xFFFFFFFF) &&
155             (Reciprocal.HighPart == (LONG)0xFFFFFFFF))
156         {
157             /* Set the high bit and reduce the bit count */
158             Reciprocal.LowPart = 0;
159             Reciprocal.HighPart = 0x80000000;
160             BitCount--;
161         }
162         else
163         {
164             /* Check if only the lowest bits got too large */
165             if (Reciprocal.LowPart == 0xFFFFFFFF)
166             {
167                 /* Reset them and increase the high bits instead */
168                 Reciprocal.LowPart = 0;
169                 Reciprocal.HighPart++;
170             }
171             else
172             {
173                 /* All is well, increase the low bits */
174                 Reciprocal.LowPart++;
175             }
176         }
177     }
178 
179     /* Now calculate the actual shift and return the reciprocal */
180     *Shift = (UCHAR)BitCount - 64;
181     return Reciprocal;
182 }
183 
184 CODE_SEG("INIT")
185 VOID
186 NTAPI
187 KiInitSpinLocks(IN PKPRCB Prcb,
188                 IN CCHAR Number)
189 {
190     ULONG i;
191 
192     /* Initialize Dispatcher Fields */
193     Prcb->QueueIndex = 1;
194     Prcb->ReadySummary = 0;
195     Prcb->DeferredReadyListHead.Next = NULL;
196     for (i = 0; i < MAXIMUM_PRIORITY; i++)
197     {
198         /* Initialize the ready list */
199         InitializeListHead(&Prcb->DispatcherReadyListHead[i]);
200     }
201 
202     /* Initialize DPC Fields */
203     InitializeListHead(&Prcb->DpcData[DPC_NORMAL].DpcListHead);
204     KeInitializeSpinLock(&Prcb->DpcData[DPC_NORMAL].DpcLock);
205     Prcb->DpcData[DPC_NORMAL].DpcQueueDepth = 0;
206     Prcb->DpcData[DPC_NORMAL].DpcCount = 0;
207     Prcb->DpcRoutineActive = FALSE;
208     Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
209     Prcb->MinimumDpcRate = KiMinimumDpcRate;
210     Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
211     KeInitializeDpc(&Prcb->CallDpc, NULL, NULL);
212     KeSetTargetProcessorDpc(&Prcb->CallDpc, Number);
213     KeSetImportanceDpc(&Prcb->CallDpc, HighImportance);
214 
215     /* Initialize the Wait List Head */
216     InitializeListHead(&Prcb->WaitListHead);
217 
218     /* Initialize Queued Spinlocks */
219     Prcb->LockQueue[LockQueueDispatcherLock].Next = NULL;
220     Prcb->LockQueue[LockQueueDispatcherLock].Lock = &KiDispatcherLock;
221     Prcb->LockQueue[LockQueueExpansionLock].Next = NULL;
222     Prcb->LockQueue[LockQueueExpansionLock].Lock = NULL;
223     Prcb->LockQueue[LockQueuePfnLock].Next = NULL;
224     Prcb->LockQueue[LockQueuePfnLock].Lock = &MmPfnLock;
225     Prcb->LockQueue[LockQueueSystemSpaceLock].Next = NULL;
226     Prcb->LockQueue[LockQueueSystemSpaceLock].Lock = &MmSystemSpaceLock;
227     Prcb->LockQueue[LockQueueBcbLock].Next = NULL;
228     Prcb->LockQueue[LockQueueBcbLock].Lock = &CcBcbSpinLock;
229     Prcb->LockQueue[LockQueueMasterLock].Next = NULL;
230     Prcb->LockQueue[LockQueueMasterLock].Lock = &CcMasterSpinLock;
231     Prcb->LockQueue[LockQueueVacbLock].Next = NULL;
232     Prcb->LockQueue[LockQueueVacbLock].Lock = &CcVacbSpinLock;
233     Prcb->LockQueue[LockQueueWorkQueueLock].Next = NULL;
234     Prcb->LockQueue[LockQueueWorkQueueLock].Lock = &CcWorkQueueSpinLock;
235     Prcb->LockQueue[LockQueueNonPagedPoolLock].Next = NULL;
236     Prcb->LockQueue[LockQueueNonPagedPoolLock].Lock = &NonPagedPoolLock;
237     Prcb->LockQueue[LockQueueMmNonPagedPoolLock].Next = NULL;
238     Prcb->LockQueue[LockQueueMmNonPagedPoolLock].Lock = &MmNonPagedPoolLock;
239     Prcb->LockQueue[LockQueueIoCancelLock].Next = NULL;
240     Prcb->LockQueue[LockQueueIoCancelLock].Lock = &IopCancelSpinLock;
241     Prcb->LockQueue[LockQueueIoVpbLock].Next = NULL;
242     Prcb->LockQueue[LockQueueIoVpbLock].Lock = &IopVpbSpinLock;
243     Prcb->LockQueue[LockQueueIoDatabaseLock].Next = NULL;
244     Prcb->LockQueue[LockQueueIoDatabaseLock].Lock = &IopDatabaseLock;
245     Prcb->LockQueue[LockQueueIoCompletionLock].Next = NULL;
246     Prcb->LockQueue[LockQueueIoCompletionLock].Lock = &IopCompletionLock;
247     Prcb->LockQueue[LockQueueNtfsStructLock].Next = NULL;
248     Prcb->LockQueue[LockQueueNtfsStructLock].Lock = &NtfsStructLock;
249     Prcb->LockQueue[LockQueueAfdWorkQueueLock].Next = NULL;
250     Prcb->LockQueue[LockQueueAfdWorkQueueLock].Lock = &AfdWorkQueueSpinLock;
251     Prcb->LockQueue[LockQueueUnusedSpare16].Next = NULL;
252     Prcb->LockQueue[LockQueueUnusedSpare16].Lock = NULL;
253 
254     /* Loop timer locks (shared amongst all CPUs) */
255     for (i = 0; i < LOCK_QUEUE_TIMER_TABLE_LOCKS; i++)
256     {
257         /* Setup the Queued Spinlock (done only once by the boot CPU) */
258         if (!Number)
259             KeInitializeSpinLock(&KiTimerTableLock[i]);
260 
261         /* Initialize the lock */
262         Prcb->LockQueue[LockQueueTimerTableLock + i].Next = NULL;
263         Prcb->LockQueue[LockQueueTimerTableLock + i].Lock =
264             &KiTimerTableLock[i];
265     }
266 
267     /* Initialize the PRCB lock */
268     KeInitializeSpinLock(&Prcb->PrcbLock);
269 
270     /* Check if this is the boot CPU */
271     if (!Number)
272     {
273         /* Initialize the lock themselves */
274         KeInitializeSpinLock(&KiDispatcherLock);
275         KeInitializeSpinLock(&KiReverseStallIpiLock);
276         KeInitializeSpinLock(&MmPfnLock);
277         KeInitializeSpinLock(&MmSystemSpaceLock);
278         KeInitializeSpinLock(&CcBcbSpinLock);
279         KeInitializeSpinLock(&CcMasterSpinLock);
280         KeInitializeSpinLock(&CcVacbSpinLock);
281         KeInitializeSpinLock(&CcWorkQueueSpinLock);
282         KeInitializeSpinLock(&IopCancelSpinLock);
283         KeInitializeSpinLock(&IopCompletionLock);
284         KeInitializeSpinLock(&IopDatabaseLock);
285         KeInitializeSpinLock(&IopVpbSpinLock);
286         KeInitializeSpinLock(&NonPagedPoolLock);
287         KeInitializeSpinLock(&MmNonPagedPoolLock);
288         KeInitializeSpinLock(&NtfsStructLock);
289         KeInitializeSpinLock(&AfdWorkQueueSpinLock);
290     }
291 }
292 
293 CODE_SEG("INIT")
294 BOOLEAN
295 NTAPI
296 KeInitSystem(VOID)
297 {
298     /* Check if Threaded DPCs are enabled */
299     if (KeThreadDpcEnable)
300     {
301         /* FIXME: TODO */
302         DPRINT1("Threaded DPCs not yet supported\n");
303     }
304 
305     /* Initialize non-portable parts of the kernel */
306     KiInitMachineDependent();
307     return TRUE;
308 }
309