Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencpu.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/amd64/cpu.c 00005 * PURPOSE: Routines for CPU-level support 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Timo Kreuzer (timo.kreuzer@reactos.org) 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* FIXME: Local EFLAGS defines not used anywhere else */ 00017 #define EFLAGS_IOPL 0x3000 00018 #define EFLAGS_NF 0x4000 00019 #define EFLAGS_RF 0x10000 00020 #define EFLAGS_ID 0x200000 00021 00022 /* GLOBALS *******************************************************************/ 00023 00024 /* The Boot TSS */ 00025 KTSS64 KiBootTss; 00026 00027 /* CPU Features and Flags */ 00028 ULONG KeI386CpuType; 00029 ULONG KeI386CpuStep; 00030 ULONG KeI386MachineType; 00031 ULONG KeI386NpxPresent = 1; 00032 ULONG KeLargestCacheLine = 0x40; 00033 ULONG KiDmaIoCoherency = 0; 00034 BOOLEAN KiSMTProcessorsPresent; 00035 00036 /* Freeze data */ 00037 KIRQL KiOldIrql; 00038 ULONG KiFreezeFlag; 00039 00040 /* Flush data */ 00041 volatile LONG KiTbFlushTimeStamp; 00042 00043 /* CPU Signatures */ 00044 static const CHAR CmpIntelID[] = "GenuineIntel"; 00045 static const CHAR CmpAmdID[] = "AuthenticAMD"; 00046 static const CHAR CmpCyrixID[] = "CyrixInstead"; 00047 static const CHAR CmpTransmetaID[] = "GenuineTMx86"; 00048 static const CHAR CmpCentaurID[] = "CentaurHauls"; 00049 static const CHAR CmpRiseID[] = "RiseRiseRise"; 00050 00051 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/ 00052 00053 VOID 00054 NTAPI 00055 CPUID(IN ULONG InfoType, 00056 OUT PULONG CpuInfoEax, 00057 OUT PULONG CpuInfoEbx, 00058 OUT PULONG CpuInfoEcx, 00059 OUT PULONG CpuInfoEdx) 00060 { 00061 ULONG CpuInfo[4]; 00062 00063 /* Perform the CPUID Operation */ 00064 __cpuid((int*)CpuInfo, InfoType); 00065 00066 /* Return the results */ 00067 *CpuInfoEax = CpuInfo[0]; 00068 *CpuInfoEbx = CpuInfo[1]; 00069 *CpuInfoEcx = CpuInfo[2]; 00070 *CpuInfoEdx = CpuInfo[3]; 00071 } 00072 00073 /* FUNCTIONS *****************************************************************/ 00074 00075 VOID 00076 NTAPI 00077 KiSetProcessorType(VOID) 00078 { 00079 ULONG64 EFlags; 00080 INT Reg[4]; 00081 ULONG Stepping, Type; 00082 00083 /* Start by assuming no CPUID data */ 00084 KeGetCurrentPrcb()->CpuID = 0; 00085 00086 /* Save EFlags */ 00087 EFlags = __readeflags(); 00088 00089 /* Do CPUID 1 now */ 00090 __cpuid(Reg, 1); 00091 00092 /* 00093 * Get the Stepping and Type. The stepping contains both the 00094 * Model and the Step, while the Type contains the returned Type. 00095 * We ignore the family. 00096 * 00097 * For the stepping, we convert this: zzzzzzxy into this: x0y 00098 */ 00099 Stepping = Reg[0] & 0xF0; 00100 Stepping <<= 4; 00101 Stepping += (Reg[0] & 0xFF); 00102 Stepping &= 0xF0F; 00103 Type = Reg[0] & 0xF00; 00104 Type >>= 8; 00105 00106 /* Save them in the PRCB */ 00107 KeGetCurrentPrcb()->CpuID = TRUE; 00108 KeGetCurrentPrcb()->CpuType = (UCHAR)Type; 00109 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping; 00110 00111 /* Restore EFLAGS */ 00112 __writeeflags(EFlags); 00113 } 00114 00115 ULONG 00116 NTAPI 00117 KiGetCpuVendor(VOID) 00118 { 00119 PKPRCB Prcb = KeGetCurrentPrcb(); 00120 INT Vendor[5]; 00121 00122 /* Get the Vendor ID and null-terminate it */ 00123 __cpuid(Vendor, 0); 00124 00125 /* Copy it to the PRCB and null-terminate it */ 00126 *(ULONG*)&Prcb->VendorString[0] = Vendor[1]; // ebx 00127 *(ULONG*)&Prcb->VendorString[4] = Vendor[3]; // edx 00128 *(ULONG*)&Prcb->VendorString[8] = Vendor[2]; // ecx 00129 *(ULONG*)&Prcb->VendorString[12] = 0; 00130 00131 /* Now check the CPU Type */ 00132 if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID)) 00133 { 00134 return CPU_INTEL; 00135 } 00136 else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID)) 00137 { 00138 return CPU_AMD; 00139 } 00140 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCyrixID)) 00141 { 00142 DPRINT1("Cyrix CPUs not fully supported\n"); 00143 return 0; 00144 } 00145 else if (!strcmp((PCHAR)Prcb->VendorString, CmpTransmetaID)) 00146 { 00147 DPRINT1("Transmeta CPUs not fully supported\n"); 00148 return 0; 00149 } 00150 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID)) 00151 { 00152 DPRINT1("VIA CPUs not fully supported\n"); 00153 return 0; 00154 } 00155 else if (!strcmp((PCHAR)Prcb->VendorString, CmpRiseID)) 00156 { 00157 DPRINT1("Rise CPUs not fully supported\n"); 00158 return 0; 00159 } 00160 00161 /* Invalid CPU */ 00162 return 0; 00163 } 00164 00165 ULONG 00166 NTAPI 00167 KiGetFeatureBits(VOID) 00168 { 00169 PKPRCB Prcb = KeGetCurrentPrcb(); 00170 ULONG Vendor; 00171 ULONG FeatureBits = KF_WORKING_PTE; 00172 INT Reg[4]; 00173 ULONG CpuFeatures = 0; 00174 00175 /* Get the Vendor ID */ 00176 Vendor = KiGetCpuVendor(); 00177 00178 /* Make sure we got a valid vendor ID at least. */ 00179 if (!Vendor) return FeatureBits; 00180 00181 /* Get the CPUID Info. Features are in Reg[3]. */ 00182 __cpuid(Reg, 1); 00183 00184 /* Set the initial APIC ID */ 00185 Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24); 00186 00187 /* Set the current features */ 00188 CpuFeatures = Reg[3]; 00189 00190 /* Convert all CPUID Feature bits into our format */ 00191 if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4; 00192 if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4; 00193 if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC; 00194 if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B; 00195 if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL; 00196 if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR; 00197 if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4; 00198 if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV; 00199 if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT; 00200 if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS; 00201 if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX; 00202 if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR; 00203 if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI; 00204 if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64; 00205 00206 #if 0 00207 if (Reg[2] & 0x00000001) FeatureBits |= KF_SSE3NEW; 00208 if (Reg[2] & 0x00000008) FeatureBits |= KF_MONITOR; 00209 if (Reg[2] & 0x00000200) FeatureBits |= KF_SSE3SUP; 00210 if (Reg[2] & 0x00002000) FeatureBits |= KF_CMPXCHG16B; 00211 if (Reg[2] & 0x00080000) FeatureBits |= KF_SSE41; 00212 if (Reg[2] & 0x00800000) FeatureBits |= KF_POPCNT; 00213 #endif 00214 00215 /* Check if the CPU has hyper-threading */ 00216 if (CpuFeatures & 0x10000000) 00217 { 00218 /* Set the number of logical CPUs */ 00219 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16); 00220 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) 00221 { 00222 /* We're on dual-core */ 00223 KiSMTProcessorsPresent = TRUE; 00224 } 00225 } 00226 else 00227 { 00228 /* We only have a single CPU */ 00229 Prcb->LogicalProcessorsPerPhysicalProcessor = 1; 00230 } 00231 00232 /* Check extended cpuid features */ 00233 __cpuid(Reg, 0x80000000); 00234 if ((Reg[0] & 0xffffff00) == 0x80000000) 00235 { 00236 /* Check if CPUID 0x80000001 is supported */ 00237 if (Reg[0] >= 0x80000001) 00238 { 00239 /* Check which extended features are available. */ 00240 __cpuid(Reg, 0x80000001); 00241 00242 /* Check if NX-bit is supported */ 00243 if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT; 00244 00245 /* Now handle each features for each CPU Vendor */ 00246 switch (Vendor) 00247 { 00248 case CPU_AMD: 00249 if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW; 00250 break; 00251 } 00252 } 00253 } 00254 00255 /* Return the Feature Bits */ 00256 return FeatureBits; 00257 } 00258 00259 VOID 00260 NTAPI 00261 KiGetCacheInformation(VOID) 00262 { 00263 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00264 ULONG Vendor; 00265 INT Data[4]; 00266 ULONG CacheRequests = 0, i; 00267 ULONG CurrentRegister; 00268 UCHAR RegisterByte; 00269 BOOLEAN FirstPass = TRUE; 00270 00271 /* Set default L2 size */ 00272 Pcr->SecondLevelCacheSize = 0; 00273 00274 /* Get the Vendor ID and make sure we support CPUID */ 00275 Vendor = KiGetCpuVendor(); 00276 if (!Vendor) return; 00277 00278 /* Check the Vendor ID */ 00279 switch (Vendor) 00280 { 00281 /* Handle Intel case */ 00282 case CPU_INTEL: 00283 00284 /*Check if we support CPUID 2 */ 00285 __cpuid(Data, 0); 00286 if (Data[0] >= 2) 00287 { 00288 /* We need to loop for the number of times CPUID will tell us to */ 00289 do 00290 { 00291 /* Do the CPUID call */ 00292 __cpuid(Data, 2); 00293 00294 /* Check if it was the first call */ 00295 if (FirstPass) 00296 { 00297 /* 00298 * The number of times to loop is the first byte. Read 00299 * it and then destroy it so we don't get confused. 00300 */ 00301 CacheRequests = Data[0] & 0xFF; 00302 Data[0] &= 0xFFFFFF00; 00303 00304 /* Don't go over this again */ 00305 FirstPass = FALSE; 00306 } 00307 00308 /* Loop all 4 registers */ 00309 for (i = 0; i < 4; i++) 00310 { 00311 /* Get the current register */ 00312 CurrentRegister = Data[i]; 00313 00314 /* 00315 * If the upper bit is set, then this register should 00316 * be skipped. 00317 */ 00318 if (CurrentRegister & 0x80000000) continue; 00319 00320 /* Keep looping for every byte inside this register */ 00321 while (CurrentRegister) 00322 { 00323 /* Read a byte, skip a byte. */ 00324 RegisterByte = (UCHAR)(CurrentRegister & 0xFF); 00325 CurrentRegister >>= 8; 00326 if (!RegisterByte) continue; 00327 00328 /* 00329 * Valid values are from 0x40 (0 bytes) to 0x49 00330 * (32MB), or from 0x80 to 0x89 (same size but 00331 * 8-way associative. 00332 */ 00333 if (((RegisterByte > 0x40) && 00334 (RegisterByte <= 0x49)) || 00335 ((RegisterByte > 0x80) && 00336 (RegisterByte <= 0x89))) 00337 { 00338 /* Mask out only the first nibble */ 00339 RegisterByte &= 0x0F; 00340 00341 /* Set the L2 Cache Size */ 00342 Pcr->SecondLevelCacheSize = 0x10000 << 00343 RegisterByte; 00344 } 00345 } 00346 } 00347 } while (--CacheRequests); 00348 } 00349 break; 00350 00351 case CPU_AMD: 00352 00353 /* Check if we support CPUID 0x80000006 */ 00354 __cpuid(Data, 0x80000000); 00355 if (Data[0] >= 6) 00356 { 00357 /* Get 2nd level cache and tlb size */ 00358 __cpuid(Data, 0x80000006); 00359 00360 /* Set the L2 Cache Size */ 00361 Pcr->SecondLevelCacheSize = (Data[2] & 0xFFFF0000) >> 6; 00362 } 00363 break; 00364 } 00365 } 00366 00367 VOID 00368 NTAPI 00369 KeFlushCurrentTb(VOID) 00370 { 00371 /* Flush the TLB by resetting CR3 */ 00372 __writecr3(__readcr3()); 00373 } 00374 00375 VOID 00376 NTAPI 00377 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState) 00378 { 00379 /* Restore the CR registers */ 00380 __writecr0(ProcessorState->SpecialRegisters.Cr0); 00381 // __writecr2(ProcessorState->SpecialRegisters.Cr2); 00382 __writecr3(ProcessorState->SpecialRegisters.Cr3); 00383 __writecr4(ProcessorState->SpecialRegisters.Cr4); 00384 __writecr8(ProcessorState->SpecialRegisters.Cr8); 00385 00386 /* Restore the DR registers */ 00387 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0); 00388 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1); 00389 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2); 00390 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3); 00391 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6); 00392 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7); 00393 00394 /* Restore GDT, IDT, LDT and TSS */ 00395 __lgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); 00396 // __lldt(&ProcessorState->SpecialRegisters.Ldtr); 00397 // __ltr(&ProcessorState->SpecialRegisters.Tr); 00398 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 00399 00400 // __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME 00401 // ProcessorState->SpecialRegisters.DebugControl 00402 // ProcessorState->SpecialRegisters.LastBranchToRip 00403 // ProcessorState->SpecialRegisters.LastBranchFromRip 00404 // ProcessorState->SpecialRegisters.LastExceptionToRip 00405 // ProcessorState->SpecialRegisters.LastExceptionFromRip 00406 00407 /* Restore MSRs */ 00408 __writemsr(X86_MSR_GSBASE, ProcessorState->SpecialRegisters.MsrGsBase); 00409 __writemsr(X86_MSR_KERNEL_GSBASE, ProcessorState->SpecialRegisters.MsrGsSwap); 00410 __writemsr(X86_MSR_STAR, ProcessorState->SpecialRegisters.MsrStar); 00411 __writemsr(X86_MSR_LSTAR, ProcessorState->SpecialRegisters.MsrLStar); 00412 __writemsr(X86_MSR_CSTAR, ProcessorState->SpecialRegisters.MsrCStar); 00413 __writemsr(X86_MSR_SFMASK, ProcessorState->SpecialRegisters.MsrSyscallMask); 00414 00415 } 00416 00417 VOID 00418 NTAPI 00419 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState) 00420 { 00421 /* Save the CR registers */ 00422 ProcessorState->SpecialRegisters.Cr0 = __readcr0(); 00423 ProcessorState->SpecialRegisters.Cr2 = __readcr2(); 00424 ProcessorState->SpecialRegisters.Cr3 = __readcr3(); 00425 ProcessorState->SpecialRegisters.Cr4 = __readcr4(); 00426 ProcessorState->SpecialRegisters.Cr8 = __readcr8(); 00427 00428 /* Save the DR registers */ 00429 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0); 00430 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1); 00431 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2); 00432 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3); 00433 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6); 00434 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7); 00435 00436 /* Save GDT, IDT, LDT and TSS */ 00437 __sgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); 00438 __sldt(&ProcessorState->SpecialRegisters.Ldtr); 00439 __str(&ProcessorState->SpecialRegisters.Tr); 00440 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 00441 00442 // __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr); 00443 // ProcessorState->SpecialRegisters.DebugControl = 00444 // ProcessorState->SpecialRegisters.LastBranchToRip = 00445 // ProcessorState->SpecialRegisters.LastBranchFromRip = 00446 // ProcessorState->SpecialRegisters.LastExceptionToRip = 00447 // ProcessorState->SpecialRegisters.LastExceptionFromRip = 00448 00449 /* Save MSRs */ 00450 ProcessorState->SpecialRegisters.MsrGsBase = __readmsr(X86_MSR_GSBASE); 00451 ProcessorState->SpecialRegisters.MsrGsSwap = __readmsr(X86_MSR_KERNEL_GSBASE); 00452 ProcessorState->SpecialRegisters.MsrStar = __readmsr(X86_MSR_STAR); 00453 ProcessorState->SpecialRegisters.MsrLStar = __readmsr(X86_MSR_LSTAR); 00454 ProcessorState->SpecialRegisters.MsrCStar = __readmsr(X86_MSR_CSTAR); 00455 ProcessorState->SpecialRegisters.MsrSyscallMask = __readmsr(X86_MSR_SFMASK); 00456 } 00457 00458 VOID 00459 NTAPI 00460 KeFlushEntireTb(IN BOOLEAN Invalid, 00461 IN BOOLEAN AllProcessors) 00462 { 00463 KIRQL OldIrql; 00464 00465 // FIXME: halfplemented 00466 /* Raise the IRQL for the TB Flush */ 00467 OldIrql = KeRaiseIrqlToSynchLevel(); 00468 00469 /* Flush the TB for the Current CPU, and update the flush stamp */ 00470 KeFlushCurrentTb(); 00471 00472 /* Update the flush stamp and return to original IRQL */ 00473 InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1); 00474 KeLowerIrql(OldIrql); 00475 00476 } 00477 00478 KAFFINITY 00479 NTAPI 00480 KeQueryActiveProcessors(VOID) 00481 { 00482 PAGED_CODE(); 00483 00484 /* Simply return the number of active processors */ 00485 return KeActiveProcessors; 00486 } 00487 00488 NTSTATUS 00489 NTAPI 00490 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState) 00491 { 00492 UNREFERENCED_PARAMETER(FloatingState); 00493 return STATUS_SUCCESS; 00494 } 00495 00496 NTSTATUS 00497 NTAPI 00498 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState) 00499 { 00500 UNREFERENCED_PARAMETER(FloatingState); 00501 return STATUS_SUCCESS; 00502 } 00503 00504 BOOLEAN 00505 NTAPI 00506 KeInvalidateAllCaches(VOID) 00507 { 00508 /* Invalidate all caches */ 00509 __wbinvd(); 00510 return TRUE; 00511 } 00512 00513 /* 00514 * @implemented 00515 */ 00516 ULONG 00517 NTAPI 00518 KeGetRecommendedSharedDataAlignment(VOID) 00519 { 00520 /* Return the global variable */ 00521 return KeLargestCacheLine; 00522 } 00523 00524 /* 00525 * @implemented 00526 */ 00527 VOID 00528 __cdecl 00529 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State) 00530 { 00531 /* Capture the context */ 00532 RtlCaptureContext(&State->ContextFrame); 00533 00534 /* Capture the control state */ 00535 KiSaveProcessorControlState(State); 00536 } 00537 00538 /* 00539 * @implemented 00540 */ 00541 VOID 00542 NTAPI 00543 KeSetDmaIoCoherency(IN ULONG Coherency) 00544 { 00545 /* Save the coherency globally */ 00546 KiDmaIoCoherency = Coherency; 00547 } Generated on Sun May 27 2012 04:37:30 for ReactOS by
1.7.6.1
|