* Sync up to trunk r55544.
[reactos.git] / ntoskrnl / ke / krnlinit.c
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 UCHAR KeNumberProcessors = 0;
36
37 /* NUMA Node Support */
38 KNODE KiNode0;
39 PKNODE KeNodeBlock[1];
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[16];
64 KSPIN_LOCK KiReverseStallIpiLock;
65
66 /* FUNCTIONS *****************************************************************/
67
68 VOID
69 NTAPI
70 INIT_FUNCTION
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 LARGE_INTEGER
121 NTAPI
122 INIT_FUNCTION
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 VOID
185 NTAPI
186 INIT_FUNCTION
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 */
255 for (i = 0; i < LOCK_QUEUE_TIMER_TABLE_LOCKS; i++)
256 {
257 /* Initialize the lock and setup the Queued Spinlock */
258 KeInitializeSpinLock(&KiTimerTableLock[i]);
259 Prcb->LockQueue[LockQueueTimerTableLock + i].Next = NULL;
260 Prcb->LockQueue[LockQueueTimerTableLock + i].Lock =
261 &KiTimerTableLock[i];
262 }
263
264 /* Initialize the PRCB lock */
265 KeInitializeSpinLock(&Prcb->PrcbLock);
266
267 /* Check if this is the boot CPU */
268 if (!Number)
269 {
270 /* Initialize the lock themselves */
271 KeInitializeSpinLock(&KiDispatcherLock);
272 KeInitializeSpinLock(&KiReverseStallIpiLock);
273 KeInitializeSpinLock(&MmPfnLock);
274 KeInitializeSpinLock(&MmSystemSpaceLock);
275 KeInitializeSpinLock(&CcBcbSpinLock);
276 KeInitializeSpinLock(&CcMasterSpinLock);
277 KeInitializeSpinLock(&CcVacbSpinLock);
278 KeInitializeSpinLock(&CcWorkQueueSpinLock);
279 KeInitializeSpinLock(&IopCancelSpinLock);
280 KeInitializeSpinLock(&IopCompletionLock);
281 KeInitializeSpinLock(&IopDatabaseLock);
282 KeInitializeSpinLock(&IopVpbSpinLock);
283 KeInitializeSpinLock(&NonPagedPoolLock);
284 KeInitializeSpinLock(&MmNonPagedPoolLock);
285 KeInitializeSpinLock(&NtfsStructLock);
286 KeInitializeSpinLock(&AfdWorkQueueSpinLock);
287 }
288 }
289
290 BOOLEAN
291 NTAPI
292 INIT_FUNCTION
293 KeInitSystem(VOID)
294 {
295 /* Check if Threaded DPCs are enabled */
296 if (KeThreadDpcEnable)
297 {
298 /* FIXME: TODO */
299 DPRINT1("Threaded DPCs not yet supported\n");
300 }
301
302 /* Initialize non-portable parts of the kernel */
303 KiInitMachineDependent();
304 return TRUE;
305 }