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