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