1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/amd64/kiinit.c 5 * PURPOSE: Kernel Initialization for x86 CPUs 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Timo Kreuzer (timo.kreuzer@reactos.org) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \ 17 KF_LARGE_PAGE|KF_FAST_SYSCALL|KF_GLOBAL_PAGE| \ 18 KF_CMOV|KF_PAT|KF_MMX|KF_FXSR|KF_NX_BIT|KF_MTRR) 19 20 /* GLOBALS *******************************************************************/ 21 22 /* Function pointer for early debug prints */ 23 ULONG (*FrLdrDbgPrint)(const char *Format, ...); 24 25 /* Spinlocks used only on X86 */ 26 KSPIN_LOCK KiFreezeExecutionLock; 27 28 29 KIPCR KiInitialPcr; 30 31 /* Boot and double-fault/NMI/DPC stack */ 32 UCHAR DECLSPEC_ALIGN(16) P0BootStackData[KERNEL_STACK_SIZE] = {0}; 33 UCHAR DECLSPEC_ALIGN(16) KiDoubleFaultStackData[KERNEL_STACK_SIZE] = {0}; 34 ULONG_PTR P0BootStack = (ULONG_PTR)&P0BootStackData[KERNEL_STACK_SIZE]; 35 ULONG_PTR KiDoubleFaultStack = (ULONG_PTR)&KiDoubleFaultStackData[KERNEL_STACK_SIZE]; 36 37 ULONGLONG BootCycles, BootCyclesEnd; 38 39 void KiInitializeSegments(); 40 void KiSystemCallEntry64(); 41 void KiSystemCallEntry32(); 42 43 /* FUNCTIONS *****************************************************************/ 44 45 CODE_SEG("INIT") 46 VOID 47 NTAPI 48 KiInitMachineDependent(VOID) 49 { 50 /* Check for large page support */ 51 if (KeFeatureBits & KF_LARGE_PAGE) 52 { 53 /* FIXME: Support this */ 54 DPRINT("Large Page support detected but not yet taken advantage of!\n"); 55 } 56 57 /* Check for global page support */ 58 if (KeFeatureBits & KF_GLOBAL_PAGE) 59 { 60 /* FIXME: Support this */ 61 DPRINT("Global Page support detected but not yet taken advantage of!\n"); 62 } 63 64 /* Check if we have MTRR */ 65 if (KeFeatureBits & KF_MTRR) 66 { 67 /* FIXME: Support this */ 68 DPRINT("MTRR support detected but not yet taken advantage of!\n"); 69 } 70 71 /* Check for PAT and/or MTRR support */ 72 if (KeFeatureBits & KF_PAT) 73 { 74 /* FIXME: Support this */ 75 DPRINT("PAT support detected but not yet taken advantage of!\n"); 76 } 77 78 // /* Allocate the IOPM save area */ 79 // Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool, 80 // IOPM_SIZE, 81 // ' eK'); 82 // if (!Ki386IopmSaveArea) 83 // { 84 // /* Bugcheck. We need this for V86/VDM support. */ 85 // KeBugCheckEx(NO_PAGES_AVAILABLE, 2, IOPM_SIZE, 0, 0); 86 // } 87 88 } 89 90 VOID 91 NTAPI 92 KiInitializePcr(IN PKIPCR Pcr, 93 IN ULONG ProcessorNumber, 94 IN PKTHREAD IdleThread, 95 IN PVOID DpcStack) 96 { 97 KDESCRIPTOR GdtDescriptor = {{0},0,0}, IdtDescriptor = {{0},0,0}; 98 PKGDTENTRY64 TssEntry; 99 USHORT Tr = 0; 100 101 /* Zero out the PCR */ 102 RtlZeroMemory(Pcr, sizeof(KIPCR)); 103 104 /* Set pointers to ourselves */ 105 Pcr->Self = (PKPCR)Pcr; 106 Pcr->CurrentPrcb = &Pcr->Prcb; 107 108 /* Set the PCR Version */ 109 Pcr->MajorVersion = PCR_MAJOR_VERSION; 110 Pcr->MinorVersion = PCR_MINOR_VERSION; 111 112 /* Set the PRCB Version */ 113 Pcr->Prcb.MajorVersion = PRCB_MAJOR_VERSION; 114 Pcr->Prcb.MinorVersion = PRCB_MINOR_VERSION; 115 116 /* Set the Build Type */ 117 Pcr->Prcb.BuildType = 0; 118 #ifndef CONFIG_SMP 119 Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR; 120 #endif 121 #if DBG 122 Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG; 123 #endif 124 125 /* Set the Processor Number and current Processor Mask */ 126 Pcr->Prcb.Number = (UCHAR)ProcessorNumber; 127 Pcr->Prcb.SetMember = 1ULL << ProcessorNumber; 128 129 /* Get GDT and IDT descriptors */ 130 __sgdt(&GdtDescriptor.Limit); 131 __sidt(&IdtDescriptor.Limit); 132 Pcr->GdtBase = (PVOID)GdtDescriptor.Base; 133 Pcr->IdtBase = (PKIDTENTRY)IdtDescriptor.Base; 134 135 /* Get TSS Selector */ 136 __str(&Tr); 137 ASSERT(Tr == KGDT64_SYS_TSS); 138 139 /* Get TSS Entry */ 140 TssEntry = KiGetGdtEntry(Pcr->GdtBase, Tr); 141 142 /* Get the KTSS itself */ 143 Pcr->TssBase = KiGetGdtDescriptorBase(TssEntry); 144 145 Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; // FIXME 146 147 /* Set DPC Stack */ 148 Pcr->Prcb.DpcStack = DpcStack; 149 150 /* Setup the processor set */ 151 Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember; 152 153 /* Clear DR6/7 to cleanup bootloader debugging */ 154 Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr6 = 0; 155 Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr7 = 0; 156 157 /* Initialize MXCSR (all exceptions masked) */ 158 Pcr->Prcb.MxCsr = INITIAL_MXCSR; 159 160 /* Set the Current Thread */ 161 Pcr->Prcb.CurrentThread = IdleThread; 162 163 /* Start us out at PASSIVE_LEVEL */ 164 Pcr->Irql = PASSIVE_LEVEL; 165 KeSetCurrentIrql(PASSIVE_LEVEL); 166 } 167 168 VOID 169 NTAPI 170 KiInitializeCpu(PKIPCR Pcr) 171 { 172 ULONG64 Pat; 173 ULONG64 FeatureBits; 174 175 /* Initialize gs */ 176 KiInitializeSegments(); 177 178 /* Set GS base */ 179 __writemsr(MSR_GS_BASE, (ULONG64)Pcr); 180 __writemsr(MSR_GS_SWAP, (ULONG64)Pcr); 181 182 /* Detect and set the CPU Type */ 183 KiSetProcessorType(); 184 185 /* Get the processor features for this CPU */ 186 FeatureBits = KiGetFeatureBits(); 187 188 /* Check if we support all needed features */ 189 if ((FeatureBits & REQUIRED_FEATURE_BITS) != REQUIRED_FEATURE_BITS) 190 { 191 /* If not, bugcheck system */ 192 FrLdrDbgPrint("CPU doesn't have needed features! Has: 0x%x, required: 0x%x\n", 193 FeatureBits, REQUIRED_FEATURE_BITS); 194 KeBugCheck(0); 195 } 196 197 /* Set DEP to always on */ 198 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; 199 FeatureBits |= KF_NX_ENABLED; 200 201 /* Save feature bits */ 202 Pcr->Prcb.FeatureBits = (ULONG)FeatureBits; 203 Pcr->Prcb.FeatureBitsHigh = FeatureBits >> 32; 204 205 /* Enable fx save restore support */ 206 __writecr4(__readcr4() | CR4_FXSR); 207 208 /* Enable XMMI exceptions */ 209 __writecr4(__readcr4() | CR4_XMMEXCPT); 210 211 /* Enable Write-Protection */ 212 __writecr0(__readcr0() | CR0_WP); 213 214 /* Disable fpu monitoring */ 215 __writecr0(__readcr0() & ~CR0_MP); 216 217 /* Disable x87 fpu exceptions */ 218 __writecr0(__readcr0() & ~CR0_NE); 219 220 /* LDT is unused */ 221 __lldt(0); 222 223 /* Set the systemcall entry points */ 224 __writemsr(MSR_LSTAR, (ULONG64)KiSystemCallEntry64); 225 __writemsr(MSR_CSTAR, (ULONG64)KiSystemCallEntry32); 226 227 __writemsr(MSR_STAR, ((ULONG64)KGDT64_R0_CODE << 32) | 228 ((ULONG64)(KGDT64_R3_CMCODE|RPL_MASK) << 48)); 229 230 /* Set the flags to be cleared when doing a syscall */ 231 __writemsr(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF | EFLAGS_DF); 232 233 /* Enable syscall instruction and no-execute support */ 234 __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_SCE | MSR_NXE); 235 236 /* Initialize the PAT */ 237 Pat = (PAT_WB << 0) | (PAT_WC << 8) | (PAT_UCM << 16) | (PAT_UC << 24) | 238 (PAT_WB << 32) | (PAT_WC << 40) | (PAT_UCM << 48) | (PAT_UC << 56); 239 __writemsr(MSR_PAT, Pat); 240 241 /* Initialize MXCSR */ 242 _mm_setcsr(INITIAL_MXCSR); 243 } 244 245 VOID 246 FASTCALL 247 KiInitializeTss(IN PKTSS64 Tss, 248 IN UINT64 Stack) 249 { 250 PKGDTENTRY64 TssEntry; 251 252 /* Get pointer to the GDT entry */ 253 TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS); 254 255 /* Initialize the GDT entry */ 256 KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0); 257 258 /* Zero out the TSS */ 259 RtlZeroMemory(Tss, sizeof(KTSS64)); 260 261 /* FIXME: I/O Map? */ 262 Tss->IoMapBase = 0x68; 263 264 /* Setup ring 0 stack pointer */ 265 Tss->Rsp0 = Stack; 266 267 /* Setup a stack for Double Fault Traps */ 268 Tss->Ist[1] = (ULONG64)KiDoubleFaultStack; 269 270 /* Setup a stack for CheckAbort Traps */ 271 Tss->Ist[2] = (ULONG64)KiDoubleFaultStack; 272 273 /* Setup a stack for NMI Traps */ 274 Tss->Ist[3] = (ULONG64)KiDoubleFaultStack; 275 276 /* Load the task register */ 277 __ltr(KGDT64_SYS_TSS); 278 } 279 280 CODE_SEG("INIT") 281 VOID 282 NTAPI 283 KiInitializeKernelMachineDependent( 284 IN PKPRCB Prcb, 285 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 286 { 287 ULONG64 FeatureBits; 288 289 /* Set boot-level flags */ 290 KeI386CpuType = Prcb->CpuType; 291 KeI386CpuStep = Prcb->CpuStep; 292 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; 293 KeProcessorLevel = (USHORT)Prcb->CpuType; 294 if (Prcb->CpuID) 295 KeProcessorRevision = Prcb->CpuStep; 296 297 FeatureBits = Prcb->FeatureBits | (ULONG64)Prcb->FeatureBitsHigh << 32; 298 299 /* Set basic CPU Features that user mode can read */ 300 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE; 301 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE; 302 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; 303 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 304 (FeatureBits & KF_MMX) ? TRUE : FALSE; 305 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = 306 ((FeatureBits & KF_FXSR) && (FeatureBits & KF_XMMI)) ? TRUE : FALSE; 307 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = 308 (FeatureBits & KF_3DNOW) ? TRUE : FALSE; 309 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE; 310 SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE; // ??? 311 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = 312 ((FeatureBits & KF_FXSR) && (FeatureBits & KF_XMMI64)) ? TRUE : FALSE; 313 SharedUserData->ProcessorFeatures[PF_SSE_DAZ_MODE_AVAILABLE] = FALSE; // ??? 314 SharedUserData->ProcessorFeatures[PF_NX_ENABLED] = TRUE; 315 SharedUserData->ProcessorFeatures[PF_SSE3_INSTRUCTIONS_AVAILABLE] = 316 (FeatureBits & KF_SSE3) ? TRUE : FALSE; 317 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128] = 318 (FeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE; 319 SharedUserData->ProcessorFeatures[PF_COMPARE64_EXCHANGE128] = FALSE; // ??? 320 SharedUserData->ProcessorFeatures[PF_CHANNELS_ENABLED] = FALSE; // ??? 321 SharedUserData->ProcessorFeatures[PF_XSAVE_ENABLED] = FALSE; // FIXME 322 SharedUserData->ProcessorFeatures[PF_SECOND_LEVEL_ADDRESS_TRANSLATION] = 323 (FeatureBits & KF_SLAT) ? TRUE : FALSE; 324 SharedUserData->ProcessorFeatures[PF_VIRT_FIRMWARE_ENABLED] = 325 (FeatureBits & KF_VIRT_FIRMWARE_ENABLED) ? TRUE : FALSE; 326 SharedUserData->ProcessorFeatures[PF_RDWRFSGSBASE_AVAILABLE] = 327 (FeatureBits & KF_RDWRFSGSBASE) ? TRUE : FALSE; 328 SharedUserData->ProcessorFeatures[PF_FASTFAIL_AVAILABLE] = TRUE; 329 SharedUserData->ProcessorFeatures[PF_RDRAND_INSTRUCTION_AVAILABLE] = 330 (FeatureBits & KF_RDRAND) ? TRUE : FALSE; 331 SharedUserData->ProcessorFeatures[PF_RDTSCP_INSTRUCTION_AVAILABLE] = 332 (FeatureBits & KF_RDTSCP) ? TRUE : FALSE; 333 SharedUserData->ProcessorFeatures[PF_RDPID_INSTRUCTION_AVAILABLE] = FALSE; // ??? 334 SharedUserData->ProcessorFeatures[PF_SSSE3_INSTRUCTIONS_AVAILABLE] = 335 (FeatureBits & KF_SSSE3) ? TRUE : FALSE; 336 SharedUserData->ProcessorFeatures[PF_SSE4_1_INSTRUCTIONS_AVAILABLE] = 337 (FeatureBits & KF_SSE4_1) ? TRUE : FALSE; 338 SharedUserData->ProcessorFeatures[PF_SSE4_2_INSTRUCTIONS_AVAILABLE] = 339 (FeatureBits & KF_SSE4_2) ? TRUE : FALSE; 340 SharedUserData->ProcessorFeatures[PF_AVX_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME 341 SharedUserData->ProcessorFeatures[PF_AVX2_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME 342 SharedUserData->ProcessorFeatures[PF_AVX512F_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME 343 344 /* Set the default NX policy (opt-in) */ 345 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN; 346 347 /* Check if NPX is always on */ 348 if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON")) 349 { 350 /* Set it always on */ 351 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; 352 Prcb->FeatureBits |= KF_NX_ENABLED; 353 } 354 else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT")) 355 { 356 /* Set it in opt-out mode */ 357 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT; 358 Prcb->FeatureBits |= KF_NX_ENABLED; 359 } 360 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) || 361 (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE"))) 362 { 363 /* Set the feature bits */ 364 Prcb->FeatureBits |= KF_NX_ENABLED; 365 } 366 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) || 367 (strstr(KeLoaderBlock->LoadOptions, "EXECUTE"))) 368 { 369 /* Set disabled mode */ 370 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF; 371 Prcb->FeatureBits |= KF_NX_DISABLED; 372 } 373 374 #if DBG 375 /* Print applied kernel features/policies and boot CPU features */ 376 KiReportCpuFeatures(Prcb); 377 #endif 378 } 379 380 static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3]; 381 382 void 383 KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 384 { 385 PLDR_DATA_TABLE_ENTRY LdrEntry; 386 PLIST_ENTRY Entry; 387 ULONG i; 388 389 /* Initialize the list head */ 390 InitializeListHead(&PsLoadedModuleList); 391 392 /* Loop the first 3 entries */ 393 for (Entry = LoaderBlock->LoadOrderListHead.Flink, i = 0; 394 Entry != &LoaderBlock->LoadOrderListHead && i < 3; 395 Entry = Entry->Flink, i++) 396 { 397 /* Get the data table entry */ 398 LdrEntry = CONTAINING_RECORD(Entry, 399 LDR_DATA_TABLE_ENTRY, 400 InLoadOrderLinks); 401 402 /* Copy the entry */ 403 LdrCoreEntries[i] = *LdrEntry; 404 405 /* Insert the copy into the list */ 406 InsertTailList(&PsLoadedModuleList, &LdrCoreEntries[i].InLoadOrderLinks); 407 } 408 } 409 410 CODE_SEG("INIT") 411 DECLSPEC_NORETURN 412 VOID 413 NTAPI 414 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 415 { 416 CCHAR Cpu; 417 PKTHREAD InitialThread; 418 ULONG64 InitialStack; 419 PKIPCR Pcr; 420 421 /* Boot cycles timestamp */ 422 BootCycles = __rdtsc(); 423 424 /* HACK */ 425 FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea; 426 //FrLdrDbgPrint("Hello from KiSystemStartup!!!\n"); 427 428 /* Save the loader block */ 429 KeLoaderBlock = LoaderBlock; 430 431 /* Get the current CPU number */ 432 Cpu = KeNumberProcessors++; // FIXME 433 434 /* LoaderBlock initialization for Cpu 0 */ 435 if (Cpu == 0) 436 { 437 /* Set the initial stack, idle thread and process */ 438 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; 439 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; 440 LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb; 441 LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb; 442 } 443 444 /* Get Pcr from loader block */ 445 Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb); 446 447 /* Set the PRCB for this Processor */ 448 KiProcessorBlock[Cpu] = &Pcr->Prcb; 449 450 /* Align stack to 16 bytes */ 451 LoaderBlock->KernelStack &= ~(16 - 1); 452 453 /* Save the initial thread and stack */ 454 InitialStack = LoaderBlock->KernelStack; // Checkme 455 InitialThread = (PKTHREAD)LoaderBlock->Thread; 456 457 /* Set us as the current process */ 458 InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process; 459 460 /* Initialize the PCR */ 461 KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack); 462 463 /* Initialize the CPU features */ 464 KiInitializeCpu(Pcr); 465 466 /* Initial setup for the boot CPU */ 467 if (Cpu == 0) 468 { 469 /* Initialize the module list (ntos, hal, kdcom) */ 470 KiInitModuleList(LoaderBlock); 471 472 /* Setup the TSS descriptors and entries */ 473 KiInitializeTss(Pcr->TssBase, InitialStack); 474 475 /* Setup the IDT */ 476 KeInitExceptions(); 477 478 /* Initialize debugging system */ 479 KdInitSystem(0, KeLoaderBlock); 480 481 /* Check for break-in */ 482 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 483 } 484 485 DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n", 486 Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase); 487 488 /* Acquire lock */ 489 while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0)) 490 { 491 /* Loop until lock is free */ 492 while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1); 493 } 494 495 /* Initialize the Processor with HAL */ 496 HalInitializeProcessor(Cpu, KeLoaderBlock); 497 498 /* Set processor as active */ 499 KeActiveProcessors |= 1ULL << Cpu; 500 501 /* Release lock */ 502 InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0); 503 504 /* Raise to HIGH_LEVEL */ 505 KfRaiseIrql(HIGH_LEVEL); 506 507 /* Machine specific kernel initialization */ 508 if (Cpu == 0) KiInitializeKernelMachineDependent(&Pcr->Prcb, LoaderBlock); 509 510 /* Switch to new kernel stack and start kernel bootstrapping */ 511 KiSwitchToBootStack(InitialStack & ~3); 512 } 513 514