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