1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/amd64/krnlinit.c 5 * PURPOSE: Portable part of kernel initialization 6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 7 * Alex Ionescu (alex.ionescu@reactos.org) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 extern ULONG_PTR MainSSDT[]; 17 extern UCHAR MainSSPT[]; 18 19 extern BOOLEAN RtlpUse16ByteSLists; 20 21 /* FUNCTIONS *****************************************************************/ 22 23 CODE_SEG("INIT") 24 VOID 25 NTAPI 26 KiInitializeKernel(IN PKPROCESS InitProcess, 27 IN PKTHREAD InitThread, 28 IN PVOID IdleStack, 29 IN PKPRCB Prcb, 30 IN PLOADER_PARAMETER_BLOCK LoaderBlock); 31 32 33 CODE_SEG("INIT") 34 VOID 35 KiCalculateCpuFrequency( 36 IN PKPRCB Prcb) 37 { 38 if (Prcb->FeatureBits & KF_RDTSC) 39 { 40 ULONG Sample = 0; 41 CPU_INFO CpuInfo; 42 KI_SAMPLE_MAP Samples[10]; 43 PKI_SAMPLE_MAP CurrentSample = Samples; 44 45 /* Start sampling loop */ 46 for (;;) 47 { 48 /* Do a dummy CPUID to start the sample */ 49 KiCpuId(&CpuInfo, 0); 50 51 /* Fill out the starting data */ 52 CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL); 53 CurrentSample->TSCStart = __rdtsc(); 54 CurrentSample->PerfFreq.QuadPart = -50000; 55 56 /* Sleep for this sample */ 57 KeStallExecutionProcessor(CurrentSample->PerfFreq.QuadPart * -1 / 10); 58 59 /* Do another dummy CPUID */ 60 KiCpuId(&CpuInfo, 0); 61 62 /* Fill out the ending data */ 63 CurrentSample->PerfEnd = 64 KeQueryPerformanceCounter(&CurrentSample->PerfFreq); 65 CurrentSample->TSCEnd = __rdtsc(); 66 67 /* Calculate the differences */ 68 CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart - 69 CurrentSample->PerfStart.QuadPart; 70 CurrentSample->TSCDelta = CurrentSample->TSCEnd - 71 CurrentSample->TSCStart; 72 73 /* Compute CPU Speed */ 74 CurrentSample->MHz = (ULONG)((CurrentSample->TSCDelta * 75 CurrentSample-> 76 PerfFreq.QuadPart + 500000) / 77 (CurrentSample->PerfDelta * 78 1000000)); 79 80 /* Check if this isn't the first sample */ 81 if (Sample) 82 { 83 /* Check if we got a good precision within 1MHz */ 84 if ((CurrentSample->MHz == CurrentSample[-1].MHz) || 85 (CurrentSample->MHz == CurrentSample[-1].MHz + 1) || 86 (CurrentSample->MHz == CurrentSample[-1].MHz - 1)) 87 { 88 /* We did, stop sampling */ 89 break; 90 } 91 } 92 93 /* Move on */ 94 CurrentSample++; 95 Sample++; 96 97 if (Sample == RTL_NUMBER_OF(Samples)) 98 { 99 /* No luck. Average the samples and be done */ 100 ULONG TotalMHz = 0; 101 while (Sample--) 102 { 103 TotalMHz += Samples[Sample].MHz; 104 } 105 CurrentSample[-1].MHz = TotalMHz / RTL_NUMBER_OF(Samples); 106 DPRINT1("Sampling CPU frequency failed. Using average of %lu MHz\n", CurrentSample[-1].MHz); 107 break; 108 } 109 } 110 111 /* Save the CPU Speed */ 112 Prcb->MHz = CurrentSample[-1].MHz; 113 } 114 } 115 116 VOID 117 NTAPI 118 KiInitializeHandBuiltThread( 119 IN PKTHREAD Thread, 120 IN PKPROCESS Process, 121 IN PVOID Stack) 122 { 123 PKPRCB Prcb = KeGetCurrentPrcb(); 124 125 /* Setup the Thread */ 126 KeInitializeThread(Process, Thread, NULL, NULL, NULL, NULL, NULL, Stack); 127 128 Thread->NextProcessor = Prcb->Number; 129 Thread->Priority = HIGH_PRIORITY; 130 Thread->State = Running; 131 Thread->Affinity = (ULONG_PTR)1 << Prcb->Number; 132 Thread->WaitIrql = DISPATCH_LEVEL; 133 Process->ActiveProcessors |= (ULONG_PTR)1 << Prcb->Number; 134 135 } 136 137 CODE_SEG("INIT") 138 DECLSPEC_NORETURN 139 VOID 140 NTAPI 141 KiSystemStartupBootStack(VOID) 142 { 143 PLOADER_PARAMETER_BLOCK LoaderBlock = KeLoaderBlock; // hack 144 PKPRCB Prcb = KeGetCurrentPrcb(); 145 PKTHREAD Thread = (PKTHREAD)KeLoaderBlock->Thread; 146 PKPROCESS Process = Thread->ApcState.Process; 147 PVOID KernelStack = (PVOID)KeLoaderBlock->KernelStack; 148 149 /* Initialize the Power Management Support for this PRCB */ 150 PoInitializePrcb(Prcb); 151 152 /* Save CPU state */ 153 KiSaveProcessorControlState(&Prcb->ProcessorState); 154 155 /* Get cache line information for this CPU */ 156 KiGetCacheInformation(); 157 158 /* Initialize spinlocks and DPC data */ 159 KiInitSpinLocks(Prcb, Prcb->Number); 160 161 /* Set up the thread-related fields in the PRCB */ 162 Prcb->CurrentThread = Thread; 163 Prcb->NextThread = NULL; 164 Prcb->IdleThread = Thread; 165 166 /* Initialize PRCB pool lookaside pointers */ 167 ExInitPoolLookasidePointers(); 168 169 /* Lower to APC_LEVEL */ 170 KeLowerIrql(APC_LEVEL); 171 172 /* Check if this is the boot cpu */ 173 if (Prcb->Number == 0) 174 { 175 /* Initialize the kernel */ 176 KiInitializeKernel(Process, Thread, KernelStack, Prcb, LoaderBlock); 177 } 178 else 179 { 180 /* Initialize the startup thread */ 181 KiInitializeHandBuiltThread(Thread, Process, KernelStack); 182 183 /* Initialize cpu with HAL */ 184 if (!HalInitSystem(0, LoaderBlock)) 185 { 186 /* Initialization failed */ 187 KeBugCheck(HAL_INITIALIZATION_FAILED); 188 } 189 } 190 191 /* Calculate the CPU frequency */ 192 KiCalculateCpuFrequency(Prcb); 193 194 /* Raise to Dispatch */ 195 KfRaiseIrql(DISPATCH_LEVEL); 196 197 /* Set the Idle Priority to 0. This will jump into Phase 1 */ 198 KeSetPriorityThread(Thread, 0); 199 200 /* If there's no thread scheduled, put this CPU in the Idle summary */ 201 KiAcquirePrcbLock(Prcb); 202 if (!Prcb->NextThread) KiIdleSummary |= (ULONG_PTR)1 << Prcb->Number; 203 KiReleasePrcbLock(Prcb); 204 205 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */ 206 KfRaiseIrql(HIGH_LEVEL); 207 LoaderBlock->Prcb = 0; 208 209 /* Set the priority of this thread to 0 */ 210 Thread = KeGetCurrentThread(); 211 Thread->Priority = 0; 212 213 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ 214 _enable(); 215 KeLowerIrql(DISPATCH_LEVEL); 216 217 /* Set the right wait IRQL */ 218 Thread->WaitIrql = DISPATCH_LEVEL; 219 220 /* Jump into the idle loop */ 221 KiIdleLoop(); 222 } 223 224 CODE_SEG("INIT") 225 VOID 226 NTAPI 227 KiInitializeKernel(IN PKPROCESS InitProcess, 228 IN PKTHREAD InitThread, 229 IN PVOID IdleStack, 230 IN PKPRCB Prcb, 231 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 232 { 233 ULONG_PTR PageDirectory[2]; 234 PVOID DpcStack; 235 ULONG i; 236 237 /* Set Node Data */ 238 KeNodeBlock[0] = &KiNode0; 239 Prcb->ParentNode = KeNodeBlock[0]; 240 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember; 241 242 /* Set boot-level flags */ 243 KeFeatureBits = Prcb->FeatureBits; 244 245 /* Initialize 8/16 bit SList support */ 246 RtlpUse16ByteSLists = (KeFeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE; 247 248 /* Set the current MP Master KPRCB to the Boot PRCB */ 249 Prcb->MultiThreadSetMaster = Prcb; 250 251 /* Initialize Bugcheck Callback data */ 252 InitializeListHead(&KeBugcheckCallbackListHead); 253 InitializeListHead(&KeBugcheckReasonCallbackListHead); 254 KeInitializeSpinLock(&BugCheckCallbackLock); 255 256 /* Initialize the Timer Expiration DPC */ 257 KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL); 258 KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0); 259 260 /* Initialize Profiling data */ 261 KeInitializeSpinLock(&KiProfileLock); 262 InitializeListHead(&KiProfileListHead); 263 InitializeListHead(&KiProfileSourceListHead); 264 265 /* Loop the timer table */ 266 for (i = 0; i < TIMER_TABLE_SIZE; i++) 267 { 268 /* Initialize the list and entries */ 269 InitializeListHead(&KiTimerTableListHead[i].Entry); 270 KiTimerTableListHead[i].Time.HighPart = 0xFFFFFFFF; 271 KiTimerTableListHead[i].Time.LowPart = 0; 272 } 273 274 /* Initialize the Swap event and all swap lists */ 275 KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE); 276 InitializeListHead(&KiProcessInSwapListHead); 277 InitializeListHead(&KiProcessOutSwapListHead); 278 InitializeListHead(&KiStackInSwapListHead); 279 280 /* Initialize the mutex for generic DPC calls */ 281 ExInitializeFastMutex(&KiGenericCallDpcMutex); 282 283 /* Initialize the syscall table */ 284 KeServiceDescriptorTable[0].Base = MainSSDT; 285 KeServiceDescriptorTable[0].Count = NULL; 286 KeServiceDescriptorTable[0].Limit = KiServiceLimit; 287 KeServiceDescriptorTable[1].Limit = 0; 288 KeServiceDescriptorTable[0].Number = MainSSPT; 289 290 /* Copy the the current table into the shadow table for win32k */ 291 RtlCopyMemory(KeServiceDescriptorTableShadow, 292 KeServiceDescriptorTable, 293 sizeof(KeServiceDescriptorTable)); 294 295 /* Initialize the Idle Process and the Process Listhead */ 296 InitializeListHead(&KiProcessListHead); 297 PageDirectory[0] = 0; 298 PageDirectory[1] = 0; 299 KeInitializeProcess(InitProcess, 300 0, 301 0xFFFFFFFF, 302 PageDirectory, 303 FALSE); 304 InitProcess->QuantumReset = MAXCHAR; 305 306 /* Initialize the startup thread */ 307 KiInitializeHandBuiltThread(InitThread, InitProcess, IdleStack); 308 309 /* Initialize the Kernel Executive */ 310 ExpInitializeExecutive(0, LoaderBlock); 311 312 /* Calculate the time reciprocal */ 313 KiTimeIncrementReciprocal = 314 KiComputeReciprocal(KeMaximumIncrement, 315 &KiTimeIncrementShiftCount); 316 317 /* Update DPC Values in case they got updated by the executive */ 318 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; 319 Prcb->MinimumDpcRate = KiMinimumDpcRate; 320 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 321 322 /* Allocate the DPC Stack */ 323 DpcStack = MmCreateKernelStack(FALSE, 0); 324 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0); 325 Prcb->DpcStack = DpcStack; 326 } 327 328