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 ULONG 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 = FeatureBits; 203 204 /* Enable fx save restore support */ 205 __writecr4(__readcr4() | CR4_FXSR); 206 207 /* Enable XMMI exceptions */ 208 __writecr4(__readcr4() | CR4_XMMEXCPT); 209 210 /* Enable Write-Protection */ 211 __writecr0(__readcr0() | CR0_WP); 212 213 /* Disable fpu monitoring */ 214 __writecr0(__readcr0() & ~CR0_MP); 215 216 /* Disable x87 fpu exceptions */ 217 __writecr0(__readcr0() & ~CR0_NE); 218 219 /* LDT is unused */ 220 __lldt(0); 221 222 /* Set the systemcall entry points */ 223 __writemsr(MSR_LSTAR, (ULONG64)KiSystemCallEntry64); 224 __writemsr(MSR_CSTAR, (ULONG64)KiSystemCallEntry32); 225 226 __writemsr(MSR_STAR, ((ULONG64)KGDT64_R0_CODE << 32) | 227 ((ULONG64)(KGDT64_R3_CMCODE|RPL_MASK) << 48)); 228 229 /* Set the flags to be cleared when doing a syscall */ 230 __writemsr(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF | EFLAGS_DF); 231 232 /* Enable syscall instruction and no-execute support */ 233 __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_SCE | MSR_NXE); 234 235 /* Initialize the PAT */ 236 Pat = (PAT_WB << 0) | (PAT_WC << 8) | (PAT_UCM << 16) | (PAT_UC << 24) | 237 (PAT_WB << 32) | (PAT_WC << 40) | (PAT_UCM << 48) | (PAT_UC << 56); 238 __writemsr(MSR_PAT, Pat); 239 240 /* Initialize MXCSR */ 241 _mm_setcsr(INITIAL_MXCSR); 242 } 243 244 VOID 245 FASTCALL 246 KiInitializeTss(IN PKTSS64 Tss, 247 IN UINT64 Stack) 248 { 249 PKGDTENTRY64 TssEntry; 250 251 /* Get pointer to the GDT entry */ 252 TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS); 253 254 /* Initialize the GDT entry */ 255 KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0); 256 257 /* Zero out the TSS */ 258 RtlZeroMemory(Tss, sizeof(KTSS64)); 259 260 /* FIXME: I/O Map? */ 261 Tss->IoMapBase = 0x68; 262 263 /* Setup ring 0 stack pointer */ 264 Tss->Rsp0 = Stack; 265 266 /* Setup a stack for Double Fault Traps */ 267 Tss->Ist[1] = (ULONG64)KiDoubleFaultStack; 268 269 /* Setup a stack for CheckAbort Traps */ 270 Tss->Ist[2] = (ULONG64)KiDoubleFaultStack; 271 272 /* Setup a stack for NMI Traps */ 273 Tss->Ist[3] = (ULONG64)KiDoubleFaultStack; 274 275 /* Load the task register */ 276 __ltr(KGDT64_SYS_TSS); 277 } 278 279 CODE_SEG("INIT") 280 VOID 281 NTAPI 282 KiInitializeKernelMachineDependent( 283 IN PKPRCB Prcb, 284 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 285 { 286 /* Set boot-level flags */ 287 KeI386CpuType = Prcb->CpuType; 288 KeI386CpuStep = Prcb->CpuStep; 289 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; 290 KeProcessorLevel = (USHORT)Prcb->CpuType; 291 if (Prcb->CpuID) 292 KeProcessorRevision = Prcb->CpuStep; 293 294 /* Set basic CPU Features that user mode can read */ 295 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; 296 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE; 297 SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = TRUE; 298 SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE; // ??? 299 SharedUserData->ProcessorFeatures[PF_NX_ENABLED] = TRUE; 300 SharedUserData->ProcessorFeatures[PF_FASTFAIL_AVAILABLE] = TRUE; 301 SharedUserData->ProcessorFeatures[PF_XSAVE_ENABLED] = TRUE; 302 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 303 (Prcb->FeatureBits & KF_MMX) ? TRUE: FALSE; 304 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = 305 ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI)) ? TRUE: FALSE; 306 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = 307 ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI64)) ? TRUE: FALSE; 308 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = 309 (Prcb->FeatureBits & KF_3DNOW) ? TRUE: FALSE; 310 SharedUserData->ProcessorFeatures[PF_SSE3_INSTRUCTIONS_AVAILABLE] = 311 (Prcb->FeatureBits & KF_SSE3) ? TRUE: FALSE; 312 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128] = 313 (Prcb->FeatureBits & KF_CMPXCHG16B) ? TRUE: FALSE; 314 315 /* Set the default NX policy (opt-in) */ 316 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN; 317 318 /* Check if NPX is always on */ 319 if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON")) 320 { 321 /* Set it always on */ 322 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; 323 Prcb->FeatureBits |= KF_NX_ENABLED; 324 } 325 else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT")) 326 { 327 /* Set it in opt-out mode */ 328 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT; 329 Prcb->FeatureBits |= KF_NX_ENABLED; 330 } 331 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) || 332 (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE"))) 333 { 334 /* Set the feature bits */ 335 Prcb->FeatureBits |= KF_NX_ENABLED; 336 } 337 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) || 338 (strstr(KeLoaderBlock->LoadOptions, "EXECUTE"))) 339 { 340 /* Set disabled mode */ 341 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF; 342 Prcb->FeatureBits |= KF_NX_DISABLED; 343 } 344 345 #if DBG 346 /* Print applied kernel features/policies and boot CPU features */ 347 KiReportCpuFeatures(Prcb); 348 #endif 349 } 350 351 static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3]; 352 353 void 354 KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 355 { 356 PLDR_DATA_TABLE_ENTRY LdrEntry; 357 PLIST_ENTRY Entry; 358 ULONG i; 359 360 /* Initialize the list head */ 361 InitializeListHead(&PsLoadedModuleList); 362 363 /* Loop the first 3 entries */ 364 for (Entry = LoaderBlock->LoadOrderListHead.Flink, i = 0; 365 Entry != &LoaderBlock->LoadOrderListHead && i < 3; 366 Entry = Entry->Flink, i++) 367 { 368 /* Get the data table entry */ 369 LdrEntry = CONTAINING_RECORD(Entry, 370 LDR_DATA_TABLE_ENTRY, 371 InLoadOrderLinks); 372 373 /* Copy the entry */ 374 LdrCoreEntries[i] = *LdrEntry; 375 376 /* Insert the copy into the list */ 377 InsertTailList(&PsLoadedModuleList, &LdrCoreEntries[i].InLoadOrderLinks); 378 } 379 } 380 381 CODE_SEG("INIT") 382 DECLSPEC_NORETURN 383 VOID 384 NTAPI 385 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 386 { 387 CCHAR Cpu; 388 PKTHREAD InitialThread; 389 ULONG64 InitialStack; 390 PKIPCR Pcr; 391 392 /* Boot cycles timestamp */ 393 BootCycles = __rdtsc(); 394 395 /* HACK */ 396 FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea; 397 //FrLdrDbgPrint("Hello from KiSystemStartup!!!\n"); 398 399 /* Save the loader block */ 400 KeLoaderBlock = LoaderBlock; 401 402 /* Get the current CPU number */ 403 Cpu = KeNumberProcessors++; // FIXME 404 405 /* LoaderBlock initialization for Cpu 0 */ 406 if (Cpu == 0) 407 { 408 /* Set the initial stack, idle thread and process */ 409 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; 410 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; 411 LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb; 412 LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb; 413 } 414 415 /* Get Pcr from loader block */ 416 Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb); 417 418 /* Set the PRCB for this Processor */ 419 KiProcessorBlock[Cpu] = &Pcr->Prcb; 420 421 /* Align stack to 16 bytes */ 422 LoaderBlock->KernelStack &= ~(16 - 1); 423 424 /* Save the initial thread and stack */ 425 InitialStack = LoaderBlock->KernelStack; // Checkme 426 InitialThread = (PKTHREAD)LoaderBlock->Thread; 427 428 /* Set us as the current process */ 429 InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process; 430 431 /* Initialize the PCR */ 432 KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack); 433 434 /* Initialize the CPU features */ 435 KiInitializeCpu(Pcr); 436 437 /* Initial setup for the boot CPU */ 438 if (Cpu == 0) 439 { 440 /* Initialize the module list (ntos, hal, kdcom) */ 441 KiInitModuleList(LoaderBlock); 442 443 /* Setup the TSS descriptors and entries */ 444 KiInitializeTss(Pcr->TssBase, InitialStack); 445 446 /* Setup the IDT */ 447 KeInitExceptions(); 448 449 /* Initialize debugging system */ 450 KdInitSystem(0, KeLoaderBlock); 451 452 /* Check for break-in */ 453 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 454 } 455 456 DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n", 457 Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase); 458 459 /* Acquire lock */ 460 while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0)) 461 { 462 /* Loop until lock is free */ 463 while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1); 464 } 465 466 /* Initialize the Processor with HAL */ 467 HalInitializeProcessor(Cpu, KeLoaderBlock); 468 469 /* Set processor as active */ 470 KeActiveProcessors |= 1ULL << Cpu; 471 472 /* Release lock */ 473 InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0); 474 475 /* Raise to HIGH_LEVEL */ 476 KfRaiseIrql(HIGH_LEVEL); 477 478 /* Machine specific kernel initialization */ 479 if (Cpu == 0) KiInitializeKernelMachineDependent(&Pcr->Prcb, LoaderBlock); 480 481 /* Switch to new kernel stack and start kernel bootstrapping */ 482 KiSwitchToBootStack(InitialStack & ~3); 483 } 484 485