1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/amd64/cpu.c 5 * PURPOSE: Routines for CPU-level support 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 /* GLOBALS *******************************************************************/ 17 18 /* The Boot TSS */ 19 KTSS64 KiBootTss; 20 21 /* CPU Features and Flags */ 22 ULONG KeI386CpuType; 23 ULONG KeI386CpuStep; 24 ULONG KeI386MachineType; 25 ULONG KeI386NpxPresent = 1; 26 ULONG KeLargestCacheLine = 0x40; 27 ULONG KiDmaIoCoherency = 0; 28 BOOLEAN KiSMTProcessorsPresent; 29 30 /* Flush data */ 31 volatile LONG KiTbFlushTimeStamp; 32 33 /* CPU Signatures */ 34 static const CHAR CmpIntelID[] = "GenuineIntel"; 35 static const CHAR CmpAmdID[] = "AuthenticAMD"; 36 static const CHAR CmpCentaurID[] = "CentaurHauls"; 37 38 /* FUNCTIONS *****************************************************************/ 39 40 VOID 41 NTAPI 42 KiSetProcessorType(VOID) 43 { 44 CPU_INFO CpuInfo; 45 ULONG Stepping, Type; 46 47 /* Do CPUID 1 now */ 48 KiCpuId(&CpuInfo, 1); 49 50 /* 51 * Get the Stepping and Type. The stepping contains both the 52 * Model and the Step, while the Type contains the returned Type. 53 * We ignore the family. 54 * 55 * For the stepping, we convert this: zzzzzzxy into this: x0y 56 */ 57 Stepping = CpuInfo.Eax & 0xF0; 58 Stepping <<= 4; 59 Stepping += (CpuInfo.Eax & 0xFF); 60 Stepping &= 0xF0F; 61 Type = CpuInfo.Eax & 0xF00; 62 Type >>= 8; 63 64 /* Save them in the PRCB */ 65 KeGetCurrentPrcb()->CpuID = TRUE; 66 KeGetCurrentPrcb()->CpuType = (UCHAR)Type; 67 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping; 68 } 69 70 ULONG 71 NTAPI 72 KiGetCpuVendor(VOID) 73 { 74 PKPRCB Prcb = KeGetCurrentPrcb(); 75 CPU_INFO CpuInfo; 76 77 /* Get the Vendor ID and null-terminate it */ 78 KiCpuId(&CpuInfo, 0); 79 80 /* Copy it to the PRCB and null-terminate it */ 81 *(ULONG*)&Prcb->VendorString[0] = CpuInfo.Ebx; 82 *(ULONG*)&Prcb->VendorString[4] = CpuInfo.Edx; 83 *(ULONG*)&Prcb->VendorString[8] = CpuInfo.Ecx; 84 Prcb->VendorString[12] = 0; 85 86 /* Now check the CPU Type */ 87 if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID)) 88 { 89 Prcb->CpuVendor = CPU_INTEL; 90 } 91 else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID)) 92 { 93 Prcb->CpuVendor = CPU_AMD; 94 } 95 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID)) 96 { 97 DPRINT1("VIA CPUs not fully supported\n"); 98 Prcb->CpuVendor = CPU_VIA; 99 } 100 else 101 { 102 /* Invalid CPU */ 103 DPRINT1("%s CPU support not fully tested!\n", Prcb->VendorString); 104 Prcb->CpuVendor = CPU_UNKNOWN; 105 } 106 107 return Prcb->CpuVendor; 108 } 109 110 ULONG 111 NTAPI 112 KiGetFeatureBits(VOID) 113 { 114 PKPRCB Prcb = KeGetCurrentPrcb(); 115 ULONG Vendor; 116 ULONG FeatureBits = KF_WORKING_PTE; 117 CPU_INFO CpuInfo; 118 119 /* Get the Vendor ID */ 120 Vendor = KiGetCpuVendor(); 121 122 /* Make sure we got a valid vendor ID at least. */ 123 if (!Vendor) return FeatureBits; 124 125 /* Get the CPUID Info. */ 126 KiCpuId(&CpuInfo, 1); 127 128 /* Set the initial APIC ID */ 129 Prcb->InitialApicId = (UCHAR)(CpuInfo.Ebx >> 24); 130 131 /* Convert all CPUID Feature bits into our format */ 132 if (CpuInfo.Edx & X86_FEATURE_VME) FeatureBits |= KF_V86_VIS | KF_CR4; 133 if (CpuInfo.Edx & X86_FEATURE_PSE) FeatureBits |= KF_LARGE_PAGE | KF_CR4; 134 if (CpuInfo.Edx & X86_FEATURE_TSC) FeatureBits |= KF_RDTSC; 135 if (CpuInfo.Edx & X86_FEATURE_CX8) FeatureBits |= KF_CMPXCHG8B; 136 if (CpuInfo.Edx & X86_FEATURE_SYSCALL) FeatureBits |= KF_FAST_SYSCALL; 137 if (CpuInfo.Edx & X86_FEATURE_MTTR) FeatureBits |= KF_MTRR; 138 if (CpuInfo.Edx & X86_FEATURE_PGE) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4; 139 if (CpuInfo.Edx & X86_FEATURE_CMOV) FeatureBits |= KF_CMOV; 140 if (CpuInfo.Edx & X86_FEATURE_PAT) FeatureBits |= KF_PAT; 141 if (CpuInfo.Edx & X86_FEATURE_DS) FeatureBits |= KF_DTS; 142 if (CpuInfo.Edx & X86_FEATURE_MMX) FeatureBits |= KF_MMX; 143 if (CpuInfo.Edx & X86_FEATURE_FXSR) FeatureBits |= KF_FXSR; 144 if (CpuInfo.Edx & X86_FEATURE_SSE) FeatureBits |= KF_XMMI; 145 if (CpuInfo.Edx & X86_FEATURE_SSE2) FeatureBits |= KF_XMMI64; 146 147 if (CpuInfo.Ecx & X86_FEATURE_SSE3) FeatureBits |= KF_SSE3; 148 //if (CpuInfo.Ecx & X86_FEATURE_MONITOR) FeatureBits |= KF_MONITOR; 149 //if (CpuInfo.Ecx & X86_FEATURE_SSSE3) FeatureBits |= KF_SSE3SUP; 150 if (CpuInfo.Ecx & X86_FEATURE_CX16) FeatureBits |= KF_CMPXCHG16B; 151 //if (CpuInfo.Ecx & X86_FEATURE_SSE41) FeatureBits |= KF_SSE41; 152 //if (CpuInfo.Ecx & X86_FEATURE_POPCNT) FeatureBits |= KF_POPCNT; 153 if (CpuInfo.Ecx & X86_FEATURE_XSAVE) FeatureBits |= KF_XSTATE; 154 155 /* Check if the CPU has hyper-threading */ 156 if (CpuInfo.Edx & X86_FEATURE_HT) 157 { 158 /* Set the number of logical CPUs */ 159 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(CpuInfo.Ebx >> 16); 160 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) 161 { 162 /* We're on dual-core */ 163 KiSMTProcessorsPresent = TRUE; 164 } 165 } 166 else 167 { 168 /* We only have a single CPU */ 169 Prcb->LogicalProcessorsPerPhysicalProcessor = 1; 170 } 171 172 /* Check extended cpuid features */ 173 KiCpuId(&CpuInfo, 0x80000000); 174 if ((CpuInfo.Eax & 0xffffff00) == 0x80000000) 175 { 176 /* Check if CPUID 0x80000001 is supported */ 177 if (CpuInfo.Eax >= 0x80000001) 178 { 179 /* Check which extended features are available. */ 180 KiCpuId(&CpuInfo, 0x80000001); 181 182 /* Check if NX-bit is supported */ 183 if (CpuInfo.Edx & X86_FEATURE_NX) FeatureBits |= KF_NX_BIT; 184 185 /* Now handle each features for each CPU Vendor */ 186 switch (Vendor) 187 { 188 case CPU_AMD: 189 if (CpuInfo.Edx & 0x80000000) FeatureBits |= KF_3DNOW; 190 break; 191 } 192 } 193 } 194 195 /* Return the Feature Bits */ 196 return FeatureBits; 197 } 198 199 VOID 200 NTAPI 201 KiGetCacheInformation(VOID) 202 { 203 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 204 ULONG Vendor; 205 ULONG CacheRequests = 0, i; 206 ULONG CurrentRegister; 207 UCHAR RegisterByte; 208 BOOLEAN FirstPass = TRUE; 209 CPU_INFO CpuInfo; 210 211 /* Set default L2 size */ 212 Pcr->SecondLevelCacheSize = 0; 213 214 /* Get the Vendor ID and make sure we support CPUID */ 215 Vendor = KiGetCpuVendor(); 216 if (!Vendor) return; 217 218 /* Check the Vendor ID */ 219 switch (Vendor) 220 { 221 /* Handle Intel case */ 222 case CPU_INTEL: 223 224 /*Check if we support CPUID 2 */ 225 KiCpuId(&CpuInfo, 0); 226 if (CpuInfo.Eax >= 2) 227 { 228 /* We need to loop for the number of times CPUID will tell us to */ 229 do 230 { 231 /* Do the CPUID call */ 232 KiCpuId(&CpuInfo, 2); 233 234 /* Check if it was the first call */ 235 if (FirstPass) 236 { 237 /* 238 * The number of times to loop is the first byte. Read 239 * it and then destroy it so we don't get confused. 240 */ 241 CacheRequests = CpuInfo.Eax & 0xFF; 242 CpuInfo.Eax &= 0xFFFFFF00; 243 244 /* Don't go over this again */ 245 FirstPass = FALSE; 246 } 247 248 /* Loop all 4 registers */ 249 for (i = 0; i < 4; i++) 250 { 251 /* Get the current register */ 252 CurrentRegister = CpuInfo.AsUINT32[i]; 253 254 /* 255 * If the upper bit is set, then this register should 256 * be skipped. 257 */ 258 if (CurrentRegister & 0x80000000) continue; 259 260 /* Keep looping for every byte inside this register */ 261 while (CurrentRegister) 262 { 263 /* Read a byte, skip a byte. */ 264 RegisterByte = (UCHAR)(CurrentRegister & 0xFF); 265 CurrentRegister >>= 8; 266 if (!RegisterByte) continue; 267 268 /* 269 * Valid values are from 0x40 (0 bytes) to 0x49 270 * (32MB), or from 0x80 to 0x89 (same size but 271 * 8-way associative. 272 */ 273 if (((RegisterByte > 0x40) && 274 (RegisterByte <= 0x49)) || 275 ((RegisterByte > 0x80) && 276 (RegisterByte <= 0x89))) 277 { 278 /* Mask out only the first nibble */ 279 RegisterByte &= 0x0F; 280 281 /* Set the L2 Cache Size */ 282 Pcr->SecondLevelCacheSize = 0x10000 << 283 RegisterByte; 284 } 285 } 286 } 287 } while (--CacheRequests); 288 } 289 break; 290 291 case CPU_AMD: 292 293 /* Check if we support CPUID 0x80000006 */ 294 KiCpuId(&CpuInfo, 0x80000000); 295 if (CpuInfo.Eax >= 6) 296 { 297 /* Get 2nd level cache and tlb size */ 298 KiCpuId(&CpuInfo, 0x80000006); 299 300 /* Set the L2 Cache Size */ 301 Pcr->SecondLevelCacheSize = (CpuInfo.Ecx & 0xFFFF0000) >> 6; 302 } 303 break; 304 } 305 } 306 307 VOID 308 NTAPI 309 KeFlushCurrentTb(VOID) 310 { 311 /* Flush the TLB by resetting CR3 */ 312 __writecr3(__readcr3()); 313 } 314 315 VOID 316 NTAPI 317 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState) 318 { 319 /* Restore the CR registers */ 320 __writecr0(ProcessorState->SpecialRegisters.Cr0); 321 // __writecr2(ProcessorState->SpecialRegisters.Cr2); 322 __writecr3(ProcessorState->SpecialRegisters.Cr3); 323 __writecr4(ProcessorState->SpecialRegisters.Cr4); 324 __writecr8(ProcessorState->SpecialRegisters.Cr8); 325 326 /* Restore the DR registers */ 327 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0); 328 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1); 329 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2); 330 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3); 331 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6); 332 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7); 333 334 /* Restore GDT, IDT, LDT and TSS */ 335 __lgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); 336 // __lldt(&ProcessorState->SpecialRegisters.Ldtr); 337 // __ltr(&ProcessorState->SpecialRegisters.Tr); 338 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 339 340 // __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME 341 // ProcessorState->SpecialRegisters.DebugControl 342 // ProcessorState->SpecialRegisters.LastBranchToRip 343 // ProcessorState->SpecialRegisters.LastBranchFromRip 344 // ProcessorState->SpecialRegisters.LastExceptionToRip 345 // ProcessorState->SpecialRegisters.LastExceptionFromRip 346 347 /* Restore MSRs */ 348 __writemsr(X86_MSR_GSBASE, ProcessorState->SpecialRegisters.MsrGsBase); 349 __writemsr(X86_MSR_KERNEL_GSBASE, ProcessorState->SpecialRegisters.MsrGsSwap); 350 __writemsr(X86_MSR_STAR, ProcessorState->SpecialRegisters.MsrStar); 351 __writemsr(X86_MSR_LSTAR, ProcessorState->SpecialRegisters.MsrLStar); 352 __writemsr(X86_MSR_CSTAR, ProcessorState->SpecialRegisters.MsrCStar); 353 __writemsr(X86_MSR_SFMASK, ProcessorState->SpecialRegisters.MsrSyscallMask); 354 355 } 356 357 VOID 358 NTAPI 359 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState) 360 { 361 /* Save the CR registers */ 362 ProcessorState->SpecialRegisters.Cr0 = __readcr0(); 363 ProcessorState->SpecialRegisters.Cr2 = __readcr2(); 364 ProcessorState->SpecialRegisters.Cr3 = __readcr3(); 365 ProcessorState->SpecialRegisters.Cr4 = __readcr4(); 366 ProcessorState->SpecialRegisters.Cr8 = __readcr8(); 367 368 /* Save the DR registers */ 369 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0); 370 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1); 371 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2); 372 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3); 373 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6); 374 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7); 375 376 /* Save GDT, IDT, LDT and TSS */ 377 __sgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); 378 __sldt(&ProcessorState->SpecialRegisters.Ldtr); 379 __str(&ProcessorState->SpecialRegisters.Tr); 380 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 381 382 // __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr); 383 // ProcessorState->SpecialRegisters.DebugControl = 384 // ProcessorState->SpecialRegisters.LastBranchToRip = 385 // ProcessorState->SpecialRegisters.LastBranchFromRip = 386 // ProcessorState->SpecialRegisters.LastExceptionToRip = 387 // ProcessorState->SpecialRegisters.LastExceptionFromRip = 388 389 /* Save MSRs */ 390 ProcessorState->SpecialRegisters.MsrGsBase = __readmsr(X86_MSR_GSBASE); 391 ProcessorState->SpecialRegisters.MsrGsSwap = __readmsr(X86_MSR_KERNEL_GSBASE); 392 ProcessorState->SpecialRegisters.MsrStar = __readmsr(X86_MSR_STAR); 393 ProcessorState->SpecialRegisters.MsrLStar = __readmsr(X86_MSR_LSTAR); 394 ProcessorState->SpecialRegisters.MsrCStar = __readmsr(X86_MSR_CSTAR); 395 ProcessorState->SpecialRegisters.MsrSyscallMask = __readmsr(X86_MSR_SFMASK); 396 } 397 398 VOID 399 NTAPI 400 KeFlushEntireTb(IN BOOLEAN Invalid, 401 IN BOOLEAN AllProcessors) 402 { 403 KIRQL OldIrql; 404 405 // FIXME: halfplemented 406 /* Raise the IRQL for the TB Flush */ 407 OldIrql = KeRaiseIrqlToSynchLevel(); 408 409 /* Flush the TB for the Current CPU, and update the flush stamp */ 410 KeFlushCurrentTb(); 411 412 /* Update the flush stamp and return to original IRQL */ 413 InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1); 414 KeLowerIrql(OldIrql); 415 416 } 417 418 KAFFINITY 419 NTAPI 420 KeQueryActiveProcessors(VOID) 421 { 422 PAGED_CODE(); 423 424 /* Simply return the number of active processors */ 425 return KeActiveProcessors; 426 } 427 428 NTSTATUS 429 NTAPI 430 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState) 431 { 432 UNREFERENCED_PARAMETER(FloatingState); 433 return STATUS_SUCCESS; 434 } 435 436 NTSTATUS 437 NTAPI 438 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState) 439 { 440 UNREFERENCED_PARAMETER(FloatingState); 441 return STATUS_SUCCESS; 442 } 443 444 BOOLEAN 445 NTAPI 446 KeInvalidateAllCaches(VOID) 447 { 448 /* Invalidate all caches */ 449 __wbinvd(); 450 return TRUE; 451 } 452 453 /* 454 * @implemented 455 */ 456 ULONG 457 NTAPI 458 KeGetRecommendedSharedDataAlignment(VOID) 459 { 460 /* Return the global variable */ 461 return KeLargestCacheLine; 462 } 463 464 /* 465 * @implemented 466 */ 467 VOID 468 __cdecl 469 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State) 470 { 471 /* Capture the context */ 472 RtlCaptureContext(&State->ContextFrame); 473 474 /* Capture the control state */ 475 KiSaveProcessorControlState(State); 476 } 477 478 /* 479 * @implemented 480 */ 481 VOID 482 NTAPI 483 KeSetDmaIoCoherency(IN ULONG Coherency) 484 { 485 /* Save the coherency globally */ 486 KiDmaIoCoherency = Coherency; 487 } 488