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->IdealProcessor = Prcb->Number; 130 Thread->Priority = HIGH_PRIORITY; 131 Thread->State = Running; 132 Thread->Affinity = (ULONG_PTR)1 << Prcb->Number; 133 Thread->WaitIrql = DISPATCH_LEVEL; 134 Process->ActiveProcessors |= (ULONG_PTR)1 << Prcb->Number; 135 136 } 137 138 CODE_SEG("INIT") 139 DECLSPEC_NORETURN 140 VOID 141 NTAPI 142 KiSystemStartupBootStack(VOID) 143 { 144 PLOADER_PARAMETER_BLOCK LoaderBlock = KeLoaderBlock; // hack 145 PKPRCB Prcb = KeGetCurrentPrcb(); 146 PKTHREAD Thread = (PKTHREAD)KeLoaderBlock->Thread; 147 PKPROCESS Process = Thread->ApcState.Process; 148 PVOID KernelStack = (PVOID)KeLoaderBlock->KernelStack; 149 150 /* Initialize the Power Management Support for this PRCB */ 151 PoInitializePrcb(Prcb); 152 153 /* Save CPU state */ 154 KiSaveProcessorControlState(&Prcb->ProcessorState); 155 156 /* Get cache line information for this CPU */ 157 KiGetCacheInformation(); 158 159 /* Initialize spinlocks and DPC data */ 160 KiInitSpinLocks(Prcb, Prcb->Number); 161 162 /* Set up the thread-related fields in the PRCB */ 163 Prcb->CurrentThread = Thread; 164 Prcb->NextThread = NULL; 165 Prcb->IdleThread = Thread; 166 167 /* Initialize PRCB pool lookaside pointers */ 168 ExInitPoolLookasidePointers(); 169 170 /* Lower to APC_LEVEL */ 171 KeLowerIrql(APC_LEVEL); 172 173 /* Check if this is the boot cpu */ 174 if (Prcb->Number == 0) 175 { 176 /* Initialize the kernel */ 177 KiInitializeKernel(Process, Thread, KernelStack, Prcb, LoaderBlock); 178 } 179 else 180 { 181 /* Initialize the startup thread */ 182 KiInitializeHandBuiltThread(Thread, Process, KernelStack); 183 } 184 185 /* Calculate the CPU frequency */ 186 KiCalculateCpuFrequency(Prcb); 187 188 /* Raise to Dispatch */ 189 KfRaiseIrql(DISPATCH_LEVEL); 190 191 /* Set the Idle Priority to 0. This will jump into Phase 1 */ 192 KeSetPriorityThread(Thread, 0); 193 194 /* If there's no thread scheduled, put this CPU in the Idle summary */ 195 KiAcquirePrcbLock(Prcb); 196 if (!Prcb->NextThread) KiIdleSummary |= (ULONG_PTR)1 << Prcb->Number; 197 KiReleasePrcbLock(Prcb); 198 199 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */ 200 KfRaiseIrql(HIGH_LEVEL); 201 LoaderBlock->Prcb = 0; 202 203 /* Set the priority of this thread to 0 */ 204 Thread = KeGetCurrentThread(); 205 Thread->Priority = 0; 206 207 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ 208 _enable(); 209 KeLowerIrql(DISPATCH_LEVEL); 210 211 /* Set the right wait IRQL */ 212 Thread->WaitIrql = DISPATCH_LEVEL; 213 214 /* Jump into the idle loop */ 215 KiIdleLoop(); 216 } 217 218 CODE_SEG("INIT") 219 VOID 220 NTAPI 221 KiInitializeKernel(IN PKPROCESS InitProcess, 222 IN PKTHREAD InitThread, 223 IN PVOID IdleStack, 224 IN PKPRCB Prcb, 225 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 226 { 227 ULONG_PTR PageDirectory[2]; 228 PVOID DpcStack; 229 ULONG i; 230 231 /* Set Node Data */ 232 KeNodeBlock[0] = &KiNode0; 233 Prcb->ParentNode = KeNodeBlock[0]; 234 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember; 235 236 /* Set boot-level flags */ 237 KeFeatureBits = Prcb->FeatureBits; 238 239 /* Initialize 8/16 bit SList support */ 240 RtlpUse16ByteSLists = (KeFeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE; 241 242 /* Set the current MP Master KPRCB to the Boot PRCB */ 243 Prcb->MultiThreadSetMaster = Prcb; 244 245 /* Initialize Bugcheck Callback data */ 246 InitializeListHead(&KeBugcheckCallbackListHead); 247 InitializeListHead(&KeBugcheckReasonCallbackListHead); 248 KeInitializeSpinLock(&BugCheckCallbackLock); 249 250 /* Initialize the Timer Expiration DPC */ 251 KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL); 252 KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0); 253 254 /* Initialize Profiling data */ 255 KeInitializeSpinLock(&KiProfileLock); 256 InitializeListHead(&KiProfileListHead); 257 InitializeListHead(&KiProfileSourceListHead); 258 259 /* Loop the timer table */ 260 for (i = 0; i < TIMER_TABLE_SIZE; i++) 261 { 262 /* Initialize the list and entries */ 263 InitializeListHead(&KiTimerTableListHead[i].Entry); 264 KiTimerTableListHead[i].Time.HighPart = 0xFFFFFFFF; 265 KiTimerTableListHead[i].Time.LowPart = 0; 266 } 267 268 /* Initialize the Swap event and all swap lists */ 269 KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE); 270 InitializeListHead(&KiProcessInSwapListHead); 271 InitializeListHead(&KiProcessOutSwapListHead); 272 InitializeListHead(&KiStackInSwapListHead); 273 274 /* Initialize the mutex for generic DPC calls */ 275 ExInitializeFastMutex(&KiGenericCallDpcMutex); 276 277 /* Initialize the syscall table */ 278 KeServiceDescriptorTable[0].Base = MainSSDT; 279 KeServiceDescriptorTable[0].Count = NULL; 280 KeServiceDescriptorTable[0].Limit = KiServiceLimit; 281 KeServiceDescriptorTable[1].Limit = 0; 282 KeServiceDescriptorTable[0].Number = MainSSPT; 283 284 /* Copy the the current table into the shadow table for win32k */ 285 RtlCopyMemory(KeServiceDescriptorTableShadow, 286 KeServiceDescriptorTable, 287 sizeof(KeServiceDescriptorTable)); 288 289 /* Initialize the Idle Process and the Process Listhead */ 290 InitializeListHead(&KiProcessListHead); 291 PageDirectory[0] = 0; 292 PageDirectory[1] = 0; 293 KeInitializeProcess(InitProcess, 294 0, 295 0xFFFFFFFF, 296 PageDirectory, 297 FALSE); 298 InitProcess->QuantumReset = MAXCHAR; 299 300 /* Initialize the startup thread */ 301 KiInitializeHandBuiltThread(InitThread, InitProcess, IdleStack); 302 303 /* Initialize the Kernel Executive */ 304 ExpInitializeExecutive(0, LoaderBlock); 305 306 /* Calculate the time reciprocal */ 307 KiTimeIncrementReciprocal = 308 KiComputeReciprocal(KeMaximumIncrement, 309 &KiTimeIncrementShiftCount); 310 311 /* Update DPC Values in case they got updated by the executive */ 312 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; 313 Prcb->MinimumDpcRate = KiMinimumDpcRate; 314 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 315 316 /* Allocate the DPC Stack */ 317 DpcStack = MmCreateKernelStack(FALSE, 0); 318 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0); 319 Prcb->DpcStack = DpcStack; 320 } 321 322