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