ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cpu.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.