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/i386/cpu.c
00005  * PURPOSE:         Routines for CPU-level support
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES *****************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS *******************************************************************/
00016 
00017 /* The TSS to use for Double Fault Traps (INT 0x9) */
00018 UCHAR KiDoubleFaultTSS[KTSS_IO_MAPS];
00019 
00020 /* The TSS to use for NMI Fault Traps (INT 0x2) */
00021 UCHAR KiNMITSS[KTSS_IO_MAPS];
00022 
00023 /* CPU Features and Flags */
00024 ULONG KeI386CpuType;
00025 ULONG KeI386CpuStep;
00026 ULONG KiFastSystemCallDisable = 0;
00027 ULONG KeI386NpxPresent = 0;
00028 ULONG KiMXCsrMask = 0;
00029 ULONG MxcsrFeatureMask = 0;
00030 ULONG KeI386XMMIPresent = 0;
00031 ULONG KeI386FxsrPresent = 0;
00032 ULONG KeI386MachineType;
00033 ULONG Ke386Pae = FALSE;
00034 ULONG Ke386NoExecute = FALSE;
00035 ULONG KeLargestCacheLine = 0x40;
00036 ULONG KeDcacheFlushCount = 0;
00037 ULONG KeIcacheFlushCount = 0;
00038 ULONG KiDmaIoCoherency = 0;
00039 ULONG KePrefetchNTAGranularity = 32;
00040 BOOLEAN KiI386PentiumLockErrataPresent;
00041 BOOLEAN KiSMTProcessorsPresent;
00042 
00043 /* The distance between SYSEXIT and IRETD return modes */
00044 UCHAR KiSystemCallExitAdjust;
00045 
00046 /* The offset that was applied -- either 0 or the value above */
00047 UCHAR KiSystemCallExitAdjusted;
00048 
00049 /* Whether the adjustment was already done once */
00050 BOOLEAN KiFastCallCopyDoneOnce;
00051 
00052 /* Flush data */
00053 volatile LONG KiTbFlushTimeStamp;
00054 
00055 /* CPU Signatures */
00056 static const CHAR CmpIntelID[]       = "GenuineIntel";
00057 static const CHAR CmpAmdID[]         = "AuthenticAMD";
00058 static const CHAR CmpCyrixID[]       = "CyrixInstead";
00059 static const CHAR CmpTransmetaID[]   = "GenuineTMx86";
00060 static const CHAR CmpCentaurID[]     = "CentaurHauls";
00061 static const CHAR CmpRiseID[]        = "RiseRiseRise";
00062 
00063 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
00064 
00065 VOID
00066 NTAPI
00067 CPUID(IN ULONG InfoType,
00068       OUT PULONG CpuInfoEax,
00069       OUT PULONG CpuInfoEbx,
00070       OUT PULONG CpuInfoEcx,
00071       OUT PULONG CpuInfoEdx)
00072 {
00073     ULONG CpuInfo[4];
00074 
00075     /* Perform the CPUID Operation */
00076     __cpuid((int*)CpuInfo, InfoType);
00077 
00078     /* Return the results */
00079     *CpuInfoEax = CpuInfo[0];
00080     *CpuInfoEbx = CpuInfo[1];
00081     *CpuInfoEcx = CpuInfo[2];
00082     *CpuInfoEdx = CpuInfo[3];
00083 }
00084 
00085 VOID
00086 NTAPI
00087 WRMSR(IN ULONG Register,
00088       IN LONGLONG Value)
00089 {
00090    /* Write to the MSR */
00091     __writemsr(Register, Value);
00092 }
00093 
00094 LONGLONG
00095 FASTCALL
00096 RDMSR(IN ULONG Register)
00097 {
00098     /* Read from the MSR */
00099     return __readmsr(Register);
00100 }
00101 
00102 /* NSC/Cyrix CPU configuration register index */
00103 #define CX86_CCR1 0xc1
00104 
00105 /* NSC/Cyrix CPU indexed register access macros */
00106 static __inline
00107 UCHAR
00108 getCx86(UCHAR reg)
00109 {
00110     WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22, reg);
00111     return READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23);
00112 }
00113 
00114 static __inline
00115 void
00116 setCx86(UCHAR reg, UCHAR data)
00117 {
00118     WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22, reg);
00119     WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23, data);
00120 }
00121 
00122 
00123 /* FUNCTIONS *****************************************************************/
00124 
00125 VOID
00126 NTAPI
00127 INIT_FUNCTION
00128 KiSetProcessorType(VOID)
00129 {
00130     ULONG EFlags, NewEFlags;
00131     ULONG Reg, Dummy;
00132     ULONG Stepping, Type;
00133 
00134     /* Start by assuming no CPUID data */
00135     KeGetCurrentPrcb()->CpuID = 0;
00136 
00137     /* Save EFlags */
00138     EFlags = __readeflags();
00139 
00140     /* XOR out the ID bit and update EFlags */
00141     NewEFlags = EFlags ^ EFLAGS_ID;
00142     __writeeflags(NewEFlags);
00143 
00144     /* Get them back and see if they were modified */
00145     NewEFlags = __readeflags();
00146     if (NewEFlags != EFlags)
00147     {
00148         /* The modification worked, so CPUID exists. Set the ID Bit again. */
00149         EFlags |= EFLAGS_ID;
00150         __writeeflags(EFlags);
00151 
00152         /* Peform CPUID 0 to see if CPUID 1 is supported */
00153         CPUID(0, &Reg, &Dummy, &Dummy, &Dummy);
00154         if (Reg > 0)
00155         {
00156             /* Do CPUID 1 now */
00157             CPUID(1, &Reg, &Dummy, &Dummy, &Dummy);
00158 
00159             /*
00160              * Get the Stepping and Type. The stepping contains both the
00161              * Model and the Step, while the Type contains the returned Type.
00162              * We ignore the family.
00163              *
00164              * For the stepping, we convert this: zzzzzzxy into this: x0y
00165              */
00166             Stepping = Reg & 0xF0;
00167             Stepping <<= 4;
00168             Stepping += (Reg & 0xFF);
00169             Stepping &= 0xF0F;
00170             Type = Reg & 0xF00;
00171             Type >>= 8;
00172 
00173             /* Save them in the PRCB */
00174             KeGetCurrentPrcb()->CpuID = TRUE;
00175             KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
00176             KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
00177         }
00178         else
00179         {
00180             DPRINT1("CPUID Support lacking\n");
00181         }
00182     }
00183     else
00184     {
00185         DPRINT1("CPUID Support lacking\n");
00186     }
00187 
00188     /* Restore EFLAGS */
00189     __writeeflags(EFlags);
00190 }
00191 
00192 ULONG
00193 NTAPI
00194 INIT_FUNCTION
00195 KiGetCpuVendor(VOID)
00196 {
00197     PKPRCB Prcb = KeGetCurrentPrcb();
00198     ULONG Vendor[5];
00199     ULONG Temp;
00200 
00201     /* Assume no Vendor ID and fail if no CPUID Support. */
00202     Prcb->VendorString[0] = 0;
00203     if (!Prcb->CpuID) return 0;
00204 
00205     /* Get the Vendor ID and null-terminate it */
00206     CPUID(0, &Vendor[0], &Vendor[1], &Vendor[2], &Vendor[3]);
00207     Vendor[4] = 0;
00208 
00209     /* Re-arrange vendor string */
00210     Temp = Vendor[2];
00211     Vendor[2] = Vendor[3];
00212     Vendor[3] = Temp;
00213 
00214     /* Copy it to the PRCB and null-terminate it again */
00215     RtlCopyMemory(Prcb->VendorString,
00216                   &Vendor[1],
00217                   sizeof(Prcb->VendorString) - sizeof(CHAR));
00218     Prcb->VendorString[sizeof(Prcb->VendorString) - sizeof(CHAR)] = ANSI_NULL;
00219 
00220     /* Now check the CPU Type */
00221     if (!strcmp(Prcb->VendorString, CmpIntelID))
00222     {
00223         return CPU_INTEL;
00224     }
00225     else if (!strcmp(Prcb->VendorString, CmpAmdID))
00226     {
00227         return CPU_AMD;
00228     }
00229     else if (!strcmp(Prcb->VendorString, CmpCyrixID))
00230     {
00231         DPRINT1("Cyrix CPU support not fully tested!\n");
00232         return CPU_CYRIX;
00233     }
00234     else if (!strcmp(Prcb->VendorString, CmpTransmetaID))
00235     {
00236         DPRINT1("Transmeta CPU support not fully tested!\n");
00237         return CPU_TRANSMETA;
00238     }
00239     else if (!strcmp(Prcb->VendorString, CmpCentaurID))
00240     {
00241         DPRINT1("Centaur CPU support not fully tested!\n");
00242         return CPU_CENTAUR;
00243     }
00244     else if (!strcmp(Prcb->VendorString, CmpRiseID))
00245     {
00246         DPRINT1("Rise CPU support not fully tested!\n");
00247         return CPU_RISE;
00248     }
00249 
00250     /* Unknown CPU */
00251     DPRINT1("%s CPU support not fully tested!\n", Prcb->VendorString);
00252     return CPU_UNKNOWN;
00253 }
00254 
00255 ULONG
00256 NTAPI
00257 INIT_FUNCTION
00258 KiGetFeatureBits(VOID)
00259 {
00260     PKPRCB Prcb = KeGetCurrentPrcb();
00261     ULONG Vendor;
00262     ULONG FeatureBits = KF_WORKING_PTE;
00263     ULONG Reg[4], Dummy;
00264     UCHAR Ccr1;
00265     BOOLEAN ExtendedCPUID = TRUE;
00266     ULONG CpuFeatures = 0;
00267 
00268     /* Get the Vendor ID */
00269     Vendor = KiGetCpuVendor();
00270 
00271     /* Make sure we got a valid vendor ID at least. */
00272     if (!Vendor) return FeatureBits;
00273 
00274     /* Get the CPUID Info. Features are in Reg[3]. */
00275     CPUID(1, &Reg[0], &Reg[1], &Dummy, &Reg[3]);
00276 
00277     /* Set the initial APIC ID */
00278     Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24);
00279 
00280     switch (Vendor)
00281     {
00282         /* Intel CPUs */
00283         case CPU_INTEL:
00284 
00285             /* Check if it's a P6 */
00286             if (Prcb->CpuType == 6)
00287             {
00288                 /* Perform the special sequence to get the MicroCode Signature */
00289                 WRMSR(0x8B, 0);
00290                 CPUID(1, &Dummy, &Dummy, &Dummy, &Dummy);
00291                 Prcb->UpdateSignature.QuadPart = RDMSR(0x8B);
00292             }
00293             else if (Prcb->CpuType == 5)
00294             {
00295                 /* On P5, enable workaround for the LOCK errata. */
00296                 KiI386PentiumLockErrataPresent = TRUE;
00297             }
00298 
00299             /* Check for broken P6 with bad SMP PTE implementation */
00300             if (((Reg[0] & 0x0FF0) == 0x0610 && (Reg[0] & 0x000F) <= 0x9) ||
00301                 ((Reg[0] & 0x0FF0) == 0x0630 && (Reg[0] & 0x000F) <= 0x4))
00302             {
00303                 /* Remove support for correct PTE support. */
00304                 FeatureBits &= ~KF_WORKING_PTE;
00305             }
00306 
00307             /* Check if the CPU is too old to support SYSENTER */
00308             if ((Prcb->CpuType < 6) ||
00309                 ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303)))
00310             {
00311                 /* Disable it */
00312                 Reg[3] &= ~0x800;
00313             }
00314 
00315             break;
00316 
00317         /* AMD CPUs */
00318         case CPU_AMD:
00319 
00320             /* Check if this is a K5 or K6. (family 5) */
00321             if ((Reg[0] & 0x0F00) == 0x0500)
00322             {
00323                 /* Get the Model Number */
00324                 switch (Reg[0] & 0x00F0)
00325                 {
00326                     /* Model 1: K5 - 5k86 (initial models) */
00327                     case 0x0010:
00328 
00329                         /* Check if this is Step 0 or 1. They don't support PGE */
00330                         if ((Reg[0] & 0x000F) > 0x03) break;
00331 
00332                     /* Model 0: K5 - SSA5 */
00333                     case 0x0000:
00334 
00335                         /* Model 0 doesn't support PGE at all. */
00336                         Reg[3] &= ~0x2000;
00337                         break;
00338 
00339                     /* Model 8: K6-2 */
00340                     case 0x0080:
00341 
00342                         /* K6-2, Step 8 and over have support for MTRR. */
00343                         if ((Reg[0] & 0x000F) >= 0x8) FeatureBits |= KF_AMDK6MTRR;
00344                         break;
00345 
00346                     /* Model 9: K6-III
00347                        Model D: K6-2+, K6-III+ */
00348                     case 0x0090:
00349                     case 0x00D0:
00350 
00351                         FeatureBits |= KF_AMDK6MTRR;
00352                         break;
00353                 }
00354             }
00355             else if((Reg[0] & 0x0F00) < 0x0500)
00356             {
00357                 /* Families below 5 don't support PGE, PSE or CMOV at all */
00358                 Reg[3] &= ~(0x08 | 0x2000 | 0x8000);
00359 
00360                 /* They also don't support advanced CPUID functions. */
00361                 ExtendedCPUID = FALSE;
00362             }
00363 
00364             break;
00365 
00366         /* Cyrix CPUs */
00367         case CPU_CYRIX:
00368 
00369             /* Workaround the "COMA" bug on 6x family of Cyrix CPUs */
00370             if (Prcb->CpuType == 6 &&
00371                 Prcb->CpuStep <= 1)
00372             {
00373                 /* Get CCR1 value */
00374                 Ccr1 = getCx86(CX86_CCR1);
00375 
00376                 /* Enable the NO_LOCK bit */
00377                 Ccr1 |= 0x10;
00378 
00379                 /* Set the new CCR1 value */
00380                 setCx86(CX86_CCR1, Ccr1);
00381             }
00382 
00383             break;
00384 
00385         /* Transmeta CPUs */
00386         case CPU_TRANSMETA:
00387 
00388             /* Enable CMPXCHG8B if the family (>= 5), model and stepping (>= 4.2) support it */
00389             if ((Reg[0] & 0x0FFF) >= 0x0542)
00390             {
00391                 WRMSR(0x80860004, RDMSR(0x80860004) | 0x0100);
00392                 FeatureBits |= KF_CMPXCHG8B;
00393             }
00394 
00395             break;
00396 
00397         /* Centaur, IDT, Rise and VIA CPUs */
00398         case CPU_CENTAUR:
00399         case CPU_RISE:
00400 
00401             /* These CPUs don't report the presence of CMPXCHG8B through CPUID.
00402                However, this feature exists and operates properly without any additional steps. */
00403             FeatureBits |= KF_CMPXCHG8B;
00404 
00405             break;
00406     }
00407 
00408     /* Set the current features */
00409     CpuFeatures = Reg[3];
00410 
00411     /* Convert all CPUID Feature bits into our format */
00412     if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
00413     if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
00414     if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
00415     if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
00416     if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
00417     if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
00418     if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
00419     if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
00420     if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
00421     if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS;
00422     if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
00423     if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
00424     if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
00425     if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64;
00426 
00427     /* Check if the CPU has hyper-threading */
00428     if (CpuFeatures & 0x10000000)
00429     {
00430         /* Set the number of logical CPUs */
00431         Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16);
00432         if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
00433         {
00434             /* We're on dual-core */
00435             KiSMTProcessorsPresent = TRUE;
00436         }
00437     }
00438     else
00439     {
00440         /* We only have a single CPU */
00441         Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
00442     }
00443 
00444     /* Check if CPUID 0x80000000 is supported */
00445     if (ExtendedCPUID)
00446     {
00447         /* Do the call */
00448         CPUID(0x80000000, &Reg[0], &Dummy, &Dummy, &Dummy);
00449         if ((Reg[0] & 0xffffff00) == 0x80000000)
00450         {
00451             /* Check if CPUID 0x80000001 is supported */
00452             if (Reg[0] >= 0x80000001)
00453             {
00454                 /* Check which extended features are available. */
00455                 CPUID(0x80000001, &Dummy, &Dummy, &Dummy, &Reg[3]);
00456 
00457                 /* Check if NX-bit is supported */
00458                 if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT;
00459 
00460                 /* Now handle each features for each CPU Vendor */
00461                 switch (Vendor)
00462                 {
00463                     case CPU_AMD:
00464                     case CPU_CENTAUR:
00465                         if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
00466                         break;
00467                 }
00468             }
00469         }
00470     }
00471 
00472 #define print_supported(kf_value) ((FeatureBits & kf_value) ? #kf_value : "")
00473     DPRINT1("Supported CPU features : %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n",
00474     print_supported(KF_V86_VIS),
00475     print_supported(KF_RDTSC),
00476     print_supported(KF_CR4),
00477     print_supported(KF_CMOV),
00478     print_supported(KF_GLOBAL_PAGE),
00479     print_supported(KF_LARGE_PAGE),
00480     print_supported(KF_MTRR),
00481     print_supported(KF_CMPXCHG8B),
00482     print_supported(KF_MMX),
00483     print_supported(KF_WORKING_PTE),
00484     print_supported(KF_PAT),
00485     print_supported(KF_FXSR),
00486     print_supported(KF_FAST_SYSCALL),
00487     print_supported(KF_XMMI),
00488     print_supported(KF_3DNOW),
00489     print_supported(KF_AMDK6MTRR),
00490     print_supported(KF_XMMI64),
00491     print_supported(KF_DTS),
00492     print_supported(KF_NX_BIT),
00493     print_supported(KF_NX_DISABLED),
00494     print_supported(KF_NX_ENABLED));
00495 #undef print_supported
00496 
00497     /* Return the Feature Bits */
00498     return FeatureBits;
00499 }
00500 
00501 VOID
00502 NTAPI
00503 INIT_FUNCTION
00504 KiGetCacheInformation(VOID)
00505 {
00506     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00507     ULONG Vendor;
00508     ULONG Data[4], Dummy;
00509     ULONG CacheRequests = 0, i;
00510     ULONG CurrentRegister;
00511     UCHAR RegisterByte, Associativity = 0;
00512     ULONG Size, CacheLine = 64, CurrentSize = 0;
00513     BOOLEAN FirstPass = TRUE;
00514 
00515     /* Set default L2 size */
00516     Pcr->SecondLevelCacheSize = 0;
00517 
00518     /* Get the Vendor ID and make sure we support CPUID */
00519     Vendor = KiGetCpuVendor();
00520     if (!Vendor) return;
00521 
00522     /* Check the Vendor ID */
00523     switch (Vendor)
00524     {
00525         /* Handle Intel case */
00526         case CPU_INTEL:
00527 
00528             /*Check if we support CPUID 2 */
00529             CPUID(0, &Data[0], &Dummy, &Dummy, &Dummy);
00530             if (Data[0] >= 2)
00531             {
00532                 /* We need to loop for the number of times CPUID will tell us to */
00533                 do
00534                 {
00535                     /* Do the CPUID call */
00536                     CPUID(2, &Data[0], &Data[1], &Data[2], &Data[3]);
00537 
00538                     /* Check if it was the first call */
00539                     if (FirstPass)
00540                     {
00541                         /*
00542                          * The number of times to loop is the first byte. Read
00543                          * it and then destroy it so we don't get confused.
00544                          */
00545                         CacheRequests = Data[0] & 0xFF;
00546                         Data[0] &= 0xFFFFFF00;
00547 
00548                         /* Don't go over this again */
00549                         FirstPass = FALSE;
00550                     }
00551 
00552                     /* Loop all 4 registers */
00553                     for (i = 0; i < 4; i++)
00554                     {
00555                         /* Get the current register */
00556                         CurrentRegister = Data[i];
00557 
00558                         /*
00559                          * If the upper bit is set, then this register should
00560                          * be skipped.
00561                          */
00562                         if (CurrentRegister & 0x80000000) continue;
00563 
00564                         /* Keep looping for every byte inside this register */
00565                         while (CurrentRegister)
00566                         {
00567                             /* Read a byte, skip a byte. */
00568                             RegisterByte = (UCHAR)(CurrentRegister & 0xFF);
00569                             CurrentRegister >>= 8;
00570                             if (!RegisterByte) continue;
00571 
00572                             /*
00573                              * Valid values are from 0x40 (0 bytes) to 0x49
00574                              * (32MB), or from 0x80 to 0x89 (same size but
00575                              * 8-way associative.
00576                              */
00577                             if (((RegisterByte > 0x40) && (RegisterByte <= 0x47)) ||
00578                                 ((RegisterByte > 0x78) && (RegisterByte <= 0x7C)) ||
00579                                 ((RegisterByte > 0x80) && (RegisterByte <= 0x85)))
00580                             {
00581                                 /* Compute associativity */
00582                                 Associativity = 4;
00583                                 if (RegisterByte >= 0x79) Associativity = 8;
00584 
00585                                 /* Mask out only the first nibble */
00586                                 RegisterByte &= 0x07;
00587 
00588                                 /* Check if this cache is bigger than the last */
00589                                 Size = 0x10000 << RegisterByte;
00590                                 if ((Size / Associativity) > CurrentSize)
00591                                 {
00592                                     /* Set the L2 Cache Size and Associativity */
00593                                     CurrentSize = Size / Associativity;
00594                                     Pcr->SecondLevelCacheSize = Size;
00595                                     Pcr->SecondLevelCacheAssociativity = Associativity;
00596                                 }
00597                             }
00598                             else if ((RegisterByte > 0x21) && (RegisterByte <= 0x29))
00599                             {
00600                                 /* Set minimum cache line size */
00601                                 if (CacheLine < 128) CacheLine = 128;
00602 
00603                                 /* Hard-code size/associativity */
00604                                 Associativity = 8;
00605                                 switch (RegisterByte)
00606                                 {
00607                                     case 0x22:
00608                                         Size = 512 * 1024;
00609                                         Associativity = 4;
00610                                         break;
00611 
00612                                     case 0x23:
00613                                         Size = 1024 * 1024;
00614                                         break;
00615 
00616                                     case 0x25:
00617                                         Size = 2048 * 1024;
00618                                         break;
00619 
00620                                     case 0x29:
00621                                         Size = 4096 * 1024;
00622                                         break;
00623 
00624                                     default:
00625                                         Size = 0;
00626                                         break;
00627                                 }
00628 
00629                                 /* Check if this cache is bigger than the last */
00630                                 if ((Size / Associativity) > CurrentSize)
00631                                 {
00632                                     /* Set the L2 Cache Size and Associativity */
00633                                     CurrentSize = Size / Associativity;
00634                                     Pcr->SecondLevelCacheSize = Size;
00635                                     Pcr->SecondLevelCacheAssociativity = Associativity;
00636                                 }
00637                             }
00638                             else if (((RegisterByte > 0x65) && (RegisterByte < 0x69)) ||
00639                                       (RegisterByte == 0x2C) || (RegisterByte == 0xF0))
00640                             {
00641                                 /* Indicates L1 cache line of 64 bytes */
00642                                 KePrefetchNTAGranularity = 64;
00643                             }
00644                             else if (RegisterByte == 0xF1)
00645                             {
00646                                 /* Indicates L1 cache line of 128 bytes */
00647                                 KePrefetchNTAGranularity = 128;
00648                             }
00649                             else if (((RegisterByte >= 0x4A) && (RegisterByte <= 0x4C)) ||
00650                                       (RegisterByte == 0x78) ||
00651                                       (RegisterByte == 0x7D) ||
00652                                       (RegisterByte == 0x7F) ||
00653                                       (RegisterByte == 0x86) ||
00654                                       (RegisterByte == 0x87))
00655                             {
00656                                 /* Set minimum cache line size */
00657                                 if (CacheLine < 64) CacheLine = 64;
00658 
00659                                 /* Hard-code size/associativity */
00660                                 switch (RegisterByte)
00661                                 {
00662                                     case 0x4A:
00663                                         Size = 4 * 1024 * 1024;
00664                                         Associativity = 8;
00665                                         break;
00666 
00667                                     case 0x4B:
00668                                         Size = 6 * 1024 * 1024;
00669                                         Associativity = 12;
00670                                         break;
00671 
00672                                     case 0x4C:
00673                                         Size = 8 * 1024 * 1024;
00674                                         Associativity = 16;
00675                                         break;
00676 
00677                                     case 0x78:
00678                                         Size = 1 * 1024 * 1024;
00679                                         Associativity = 4;
00680                                         break;
00681 
00682                                     case 0x7D:
00683                                         Size = 2 * 1024 * 1024;
00684                                         Associativity = 8;
00685                                         break;
00686 
00687                                     case 0x7F:
00688                                         Size = 512 * 1024;
00689                                         Associativity = 2;
00690                                         break;
00691 
00692                                     case 0x86:
00693                                         Size = 512 * 1024;
00694                                         Associativity = 4;
00695                                         break;
00696 
00697                                     case 0x87:
00698                                         Size = 1 * 1024 * 1024;
00699                                         Associativity = 8;
00700                                         break;
00701 
00702                                     default:
00703                                         Size = 0;
00704                                         break;
00705                                 }
00706 
00707                                 /* Check if this cache is bigger than the last */
00708                                 if ((Size / Associativity) > CurrentSize)
00709                                 {
00710                                     /* Set the L2 Cache Size and Associativity */
00711                                     CurrentSize = Size / Associativity;
00712                                     Pcr->SecondLevelCacheSize = Size;
00713                                     Pcr->SecondLevelCacheAssociativity = Associativity;
00714                                 }
00715                             }
00716                         }
00717                     }
00718                 } while (--CacheRequests);
00719             }
00720             break;
00721 
00722         case CPU_AMD:
00723 
00724             /* Check if we support CPUID 0x80000005 */
00725             CPUID(0x80000000, &Data[0], &Data[1], &Data[2], &Data[3]);
00726             if (Data[0] >= 0x80000006)
00727             {
00728                 /* Get L1 size first */
00729                 CPUID(0x80000005, &Data[0], &Data[1], &Data[2], &Data[3]);
00730                 KePrefetchNTAGranularity = Data[2] & 0xFF;
00731 
00732                 /* Check if we support CPUID 0x80000006 */
00733                 CPUID(0x80000000, &Data[0], &Data[1], &Data[2], &Data[3]);
00734                 if (Data[0] >= 0x80000006)
00735                 {
00736                     /* Get 2nd level cache and tlb size */
00737                     CPUID(0x80000006, &Data[0], &Data[1], &Data[2], &Data[3]);
00738 
00739                     /* Cache line size */
00740                     CacheLine = Data[2] & 0xFF;
00741 
00742                     /* Hardcode associativity */
00743                     RegisterByte = (Data[2] >> 12) & 0xFF;
00744                     switch (RegisterByte)
00745                     {
00746                         case 2:
00747                             Associativity = 2;
00748                             break;
00749 
00750                         case 4:
00751                             Associativity = 4;
00752                             break;
00753 
00754                         case 6:
00755                             Associativity = 8;
00756                             break;
00757 
00758                         case 8:
00759                         case 15:
00760                             Associativity = 16;
00761                             break;
00762 
00763                         default:
00764                             Associativity = 1;
00765                             break;
00766                     }
00767 
00768                     /* Compute size */
00769                     Size = (Data[2] >> 16) << 10;
00770 
00771                     /* Hack for Model 6, Steping 300 */
00772                     if ((KeGetCurrentPrcb()->CpuType == 6) &&
00773                         (KeGetCurrentPrcb()->CpuStep == 0x300))
00774                     {
00775                         /* Stick 64K in there */
00776                         Size = 64 * 1024;
00777                     }
00778 
00779                     /* Set the L2 Cache Size and associativity */
00780                     Pcr->SecondLevelCacheSize = Size;
00781                     Pcr->SecondLevelCacheAssociativity = Associativity;
00782                 }
00783             }
00784             break;
00785 
00786         case CPU_CYRIX:
00787         case CPU_TRANSMETA:
00788         case CPU_CENTAUR:
00789         case CPU_RISE:
00790 
00791             /* FIXME */
00792             break;
00793     }
00794 
00795     /* Set the cache line */
00796     if (CacheLine > KeLargestCacheLine) KeLargestCacheLine = CacheLine;
00797     DPRINT1("Prefetch Cache: %d bytes\tL2 Cache: %d bytes\tL2 Cache Line: %d bytes\tL2 Cache Associativity: %d\n",
00798             KePrefetchNTAGranularity,
00799             Pcr->SecondLevelCacheSize,
00800             KeLargestCacheLine,
00801             Pcr->SecondLevelCacheAssociativity);
00802 }
00803 
00804 VOID
00805 NTAPI
00806 INIT_FUNCTION
00807 KiSetCR0Bits(VOID)
00808 {
00809     ULONG Cr0;
00810 
00811     /* Save current CR0 */
00812     Cr0 = __readcr0();
00813 
00814     /* If this is a 486, enable Write-Protection */
00815     if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP;
00816 
00817     /* Set new Cr0 */
00818     __writecr0(Cr0);
00819 }
00820 
00821 VOID
00822 NTAPI
00823 INIT_FUNCTION
00824 KiInitializeTSS2(IN PKTSS Tss,
00825                  IN PKGDTENTRY TssEntry OPTIONAL)
00826 {
00827     PUCHAR p;
00828 
00829     /* Make sure the GDT Entry is valid */
00830     if (TssEntry)
00831     {
00832         /* Set the Limit */
00833         TssEntry->LimitLow = sizeof(KTSS) - 1;
00834         TssEntry->HighWord.Bits.LimitHi = 0;
00835     }
00836 
00837     /* Now clear the I/O Map */
00838     ASSERT(IOPM_COUNT == 1);
00839     RtlFillMemory(Tss->IoMaps[0].IoMap, IOPM_FULL_SIZE, 0xFF);
00840 
00841     /* Initialize Interrupt Direction Maps */
00842     p = (PUCHAR)(Tss->IoMaps[0].DirectionMap);
00843     RtlZeroMemory(p, IOPM_DIRECTION_MAP_SIZE);
00844 
00845     /* Add DPMI support for interrupts */
00846     p[0] = 4;
00847     p[3] = 0x18;
00848     p[4] = 0x18;
00849 
00850     /* Initialize the default Interrupt Direction Map */
00851     p = Tss->IntDirectionMap;
00852     RtlZeroMemory(Tss->IntDirectionMap, IOPM_DIRECTION_MAP_SIZE);
00853 
00854     /* Add DPMI support */
00855     p[0] = 4;
00856     p[3] = 0x18;
00857     p[4] = 0x18;
00858 }
00859 
00860 VOID
00861 NTAPI
00862 KiInitializeTSS(IN PKTSS Tss)
00863 {
00864     /* Set an invalid map base */
00865     Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
00866 
00867     /* Disable traps during Task Switches */
00868     Tss->Flags = 0;
00869 
00870     /* Set LDT and Ring 0 SS */
00871     Tss->LDT = 0;
00872     Tss->Ss0 = KGDT_R0_DATA;
00873 }
00874 
00875 VOID
00876 FASTCALL
00877 INIT_FUNCTION
00878 Ki386InitializeTss(IN PKTSS Tss,
00879                    IN PKIDTENTRY Idt,
00880                    IN PKGDTENTRY Gdt)
00881 {
00882     PKGDTENTRY TssEntry, TaskGateEntry;
00883 
00884     /* Initialize the boot TSS. */
00885     TssEntry = &Gdt[KGDT_TSS / sizeof(KGDTENTRY)];
00886     TssEntry->HighWord.Bits.Type = I386_TSS;
00887     TssEntry->HighWord.Bits.Pres = 1;
00888     TssEntry->HighWord.Bits.Dpl = 0;
00889     KiInitializeTSS2(Tss, TssEntry);
00890     KiInitializeTSS(Tss);
00891 
00892     /* Load the task register */
00893     Ke386SetTr(KGDT_TSS);
00894 
00895     /* Setup the Task Gate for Double Fault Traps */
00896     TaskGateEntry = (PKGDTENTRY)&Idt[8];
00897     TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
00898     TaskGateEntry->HighWord.Bits.Pres = 1;
00899     TaskGateEntry->HighWord.Bits.Dpl = 0;
00900     ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_DF_TSS;
00901 
00902     /* Initialize the TSS used for handling double faults. */
00903     Tss = (PKTSS)KiDoubleFaultTSS;
00904     KiInitializeTSS(Tss);
00905     Tss->CR3 = __readcr3();
00906     Tss->Esp0 = KiDoubleFaultStack;
00907     Tss->Esp = KiDoubleFaultStack;
00908     Tss->Eip = PtrToUlong(KiTrap08);
00909     Tss->Cs = KGDT_R0_CODE;
00910     Tss->Fs = KGDT_R0_PCR;
00911     Tss->Ss = Ke386GetSs();
00912     Tss->Es = KGDT_R3_DATA | RPL_MASK;
00913     Tss->Ds = KGDT_R3_DATA | RPL_MASK;
00914 
00915     /* Setup the Double Trap TSS entry in the GDT */
00916     TssEntry = &Gdt[KGDT_DF_TSS / sizeof(KGDTENTRY)];
00917     TssEntry->HighWord.Bits.Type = I386_TSS;
00918     TssEntry->HighWord.Bits.Pres = 1;
00919     TssEntry->HighWord.Bits.Dpl = 0;
00920     TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
00921     TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
00922     TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
00923     TssEntry->LimitLow = KTSS_IO_MAPS;
00924 
00925     /* Now setup the NMI Task Gate */
00926     TaskGateEntry = (PKGDTENTRY)&Idt[2];
00927     TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
00928     TaskGateEntry->HighWord.Bits.Pres = 1;
00929     TaskGateEntry->HighWord.Bits.Dpl = 0;
00930     ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_NMI_TSS;
00931 
00932     /* Initialize the actual TSS */
00933     Tss = (PKTSS)KiNMITSS;
00934     KiInitializeTSS(Tss);
00935     Tss->CR3 = __readcr3();
00936     Tss->Esp0 = KiDoubleFaultStack;
00937     Tss->Esp = KiDoubleFaultStack;
00938     Tss->Eip = PtrToUlong(KiTrap02);
00939     Tss->Cs = KGDT_R0_CODE;
00940     Tss->Fs = KGDT_R0_PCR;
00941     Tss->Ss = Ke386GetSs();
00942     Tss->Es = KGDT_R3_DATA | RPL_MASK;
00943     Tss->Ds = KGDT_R3_DATA | RPL_MASK;
00944 
00945     /* And its associated TSS Entry */
00946     TssEntry = &Gdt[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
00947     TssEntry->HighWord.Bits.Type = I386_TSS;
00948     TssEntry->HighWord.Bits.Pres = 1;
00949     TssEntry->HighWord.Bits.Dpl = 0;
00950     TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
00951     TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
00952     TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
00953     TssEntry->LimitLow = KTSS_IO_MAPS;
00954 }
00955 
00956 VOID
00957 NTAPI
00958 KeFlushCurrentTb(VOID)
00959 {
00960     /* Flush the TLB by resetting CR3 */
00961     __writecr3(__readcr3());
00962 }
00963 
00964 VOID
00965 NTAPI
00966 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
00967 {
00968     PKGDTENTRY TssEntry;
00969 
00970     //
00971     // Restore the CR registers
00972     //
00973     __writecr0(ProcessorState->SpecialRegisters.Cr0);
00974     Ke386SetCr2(ProcessorState->SpecialRegisters.Cr2);
00975     __writecr3(ProcessorState->SpecialRegisters.Cr3);
00976     if (KeFeatureBits & KF_CR4) __writecr4(ProcessorState->SpecialRegisters.Cr4);
00977 
00978     //
00979     // Restore the DR registers
00980     //
00981     __writedr(0, ProcessorState->SpecialRegisters.KernelDr0);
00982     __writedr(1, ProcessorState->SpecialRegisters.KernelDr1);
00983     __writedr(2, ProcessorState->SpecialRegisters.KernelDr2);
00984     __writedr(3, ProcessorState->SpecialRegisters.KernelDr3);
00985     __writedr(6, ProcessorState->SpecialRegisters.KernelDr6);
00986     __writedr(7, ProcessorState->SpecialRegisters.KernelDr7);
00987 
00988     //
00989     // Restore GDT and IDT
00990     //
00991     Ke386SetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit);
00992     __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
00993 
00994     //
00995     // Clear the busy flag so we don't crash if we reload the same selector
00996     //
00997     TssEntry = (PKGDTENTRY)(ProcessorState->SpecialRegisters.Gdtr.Base +
00998                             ProcessorState->SpecialRegisters.Tr);
00999     TssEntry->HighWord.Bytes.Flags1 &= ~0x2;
01000 
01001     //
01002     // Restore TSS and LDT
01003     //
01004     Ke386SetTr(ProcessorState->SpecialRegisters.Tr);
01005     Ke386SetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr);
01006 }
01007 
01008 VOID
01009 NTAPI
01010 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
01011 {
01012     /* Save the CR registers */
01013     ProcessorState->SpecialRegisters.Cr0 = __readcr0();
01014     ProcessorState->SpecialRegisters.Cr2 = __readcr2();
01015     ProcessorState->SpecialRegisters.Cr3 = __readcr3();
01016     ProcessorState->SpecialRegisters.Cr4 = (KeFeatureBits & KF_CR4) ?
01017                                            __readcr4() : 0;
01018 
01019     /* Save the DR registers */
01020     ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0);
01021     ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1);
01022     ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2);
01023     ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3);
01024     ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6);
01025     ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7);
01026     __writedr(7, 0);
01027 
01028     /* Save GDT, IDT, LDT and TSS */
01029     Ke386GetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit);
01030     __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
01031     ProcessorState->SpecialRegisters.Tr = Ke386GetTr();
01032     ProcessorState->SpecialRegisters.Ldtr = Ke386GetLocalDescriptorTable();
01033 }
01034 
01035 VOID
01036 NTAPI
01037 INIT_FUNCTION
01038 KiInitializeMachineType(VOID)
01039 {
01040     /* Set the Machine Type we got from NTLDR */
01041     KeI386MachineType = KeLoaderBlock->u.I386.MachineType & 0x000FF;
01042 }
01043 
01044 ULONG_PTR
01045 NTAPI
01046 INIT_FUNCTION
01047 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context)
01048 {
01049     /* Set CS and ESP */
01050     WRMSR(0x174, KGDT_R0_CODE);
01051     WRMSR(0x175, (ULONG_PTR)KeGetCurrentPrcb()->DpcStack);
01052 
01053     /* Set LSTAR */
01054     WRMSR(0x176, (ULONG_PTR)KiFastCallEntry);
01055     return 0;
01056 }
01057 
01058 VOID
01059 NTAPI
01060 INIT_FUNCTION
01061 KiRestoreFastSyscallReturnState(VOID)
01062 {
01063     /* Check if the CPU Supports fast system call */
01064     if (KeFeatureBits & KF_FAST_SYSCALL)
01065     {
01066         /* Check if it has been disabled */
01067         if (KiFastSystemCallDisable)
01068         {
01069             /* Disable fast system call */
01070             KeFeatureBits &= ~KF_FAST_SYSCALL;
01071             KiFastCallExitHandler = KiSystemCallTrapReturn;
01072             DPRINT1("Support for SYSENTER disabled.\n");
01073         }
01074         else
01075         {
01076             /* Do an IPI to enable it */
01077             KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0);
01078 
01079             /* It's enabled, so use the proper exit stub */
01080             KiFastCallExitHandler = KiSystemCallSysExitReturn;
01081             DPRINT("Support for SYSENTER detected.\n");
01082         }
01083     }
01084     else
01085     {
01086         /* Use the IRET handler */
01087         KiFastCallExitHandler = KiSystemCallTrapReturn;
01088         DPRINT1("No support for SYSENTER detected.\n");
01089     }
01090 }
01091 
01092 ULONG_PTR
01093 NTAPI
01094 INIT_FUNCTION
01095 Ki386EnableDE(IN ULONG_PTR Context)
01096 {
01097     /* Enable DE */
01098     __writecr4(__readcr4() | CR4_DE);
01099     return 0;
01100 }
01101 
01102 ULONG_PTR
01103 NTAPI
01104 INIT_FUNCTION
01105 Ki386EnableFxsr(IN ULONG_PTR Context)
01106 {
01107     /* Enable FXSR */
01108     __writecr4(__readcr4() | CR4_FXSR);
01109     return 0;
01110 }
01111 
01112 ULONG_PTR
01113 NTAPI
01114 INIT_FUNCTION
01115 Ki386EnableXMMIExceptions(IN ULONG_PTR Context)
01116 {
01117     PKIDTENTRY IdtEntry;
01118 
01119     /* Get the IDT Entry for Interrupt 0x13 */
01120     IdtEntry = &((PKIPCR)KeGetPcr())->IDT[0x13];
01121 
01122     /* Set it up */
01123     IdtEntry->Selector = KGDT_R0_CODE;
01124     IdtEntry->Offset = ((ULONG_PTR)KiTrap13 & 0xFFFF);
01125     IdtEntry->ExtendedOffset = ((ULONG_PTR)KiTrap13 >> 16) & 0xFFFF;
01126     ((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0;
01127     ((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1;
01128     ((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE;
01129 
01130     /* Enable XMMI exceptions */
01131     __writecr4(__readcr4() | CR4_XMMEXCPT);
01132     return 0;
01133 }
01134 
01135 VOID
01136 NTAPI
01137 INIT_FUNCTION
01138 KiI386PentiumLockErrataFixup(VOID)
01139 {
01140     KDESCRIPTOR IdtDescriptor;
01141     PKIDTENTRY NewIdt, NewIdt2;
01142 
01143     /* Allocate memory for a new IDT */
01144     NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE);
01145 
01146     /* Put everything after the first 7 entries on a new page */
01147     NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY)));
01148 
01149     /* Disable interrupts */
01150     _disable();
01151 
01152     /* Get the current IDT and copy it */
01153     __sidt(&IdtDescriptor.Limit);
01154     RtlCopyMemory(NewIdt2,
01155                   (PVOID)IdtDescriptor.Base,
01156                   IdtDescriptor.Limit + 1);
01157     IdtDescriptor.Base = (ULONG)NewIdt2;
01158 
01159     /* Set the new IDT */
01160     __lidt(&IdtDescriptor.Limit);
01161     ((PKIPCR)KeGetPcr())->IDT = NewIdt2;
01162 
01163     /* Restore interrupts */
01164     _enable();
01165 
01166     /* Set the first 7 entries as read-only to produce a fault */
01167     MmSetPageProtect(NULL, NewIdt, PAGE_READONLY);
01168 }
01169 
01170 BOOLEAN
01171 NTAPI
01172 KeInvalidateAllCaches(VOID)
01173 {
01174     /* Only supported on Pentium Pro and higher */
01175     if (KeI386CpuType < 6) return FALSE;
01176 
01177     /* Invalidate all caches */
01178     __wbinvd();
01179     return TRUE;
01180 }
01181 
01182 VOID
01183 FASTCALL
01184 KeZeroPages(IN PVOID Address,
01185             IN ULONG Size)
01186 {
01187     /* Not using XMMI in this routine */
01188     RtlZeroMemory(Address, Size);
01189 }
01190 
01191 VOID
01192 NTAPI
01193 KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame,
01194                      IN PKEXCEPTION_FRAME ExceptionFrame)
01195 {
01196     PKPRCB Prcb = KeGetCurrentPrcb();
01197 
01198     //
01199     // Save full context
01200     //
01201     Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_FULL |
01202                                                      CONTEXT_DEBUG_REGISTERS;
01203     KeTrapFrameToContext(TrapFrame, NULL, &Prcb->ProcessorState.ContextFrame);
01204 
01205     //
01206     // Save control registers
01207     //
01208     KiSaveProcessorControlState(&Prcb->ProcessorState);
01209 }
01210 
01211 BOOLEAN
01212 NTAPI
01213 INIT_FUNCTION
01214 KiIsNpxPresent(VOID)
01215 {
01216     ULONG Cr0;
01217     USHORT Magic;
01218 
01219     /* Set magic */
01220     Magic = 0xFFFF;
01221 
01222     /* Read CR0 and mask out FPU flags */
01223     Cr0 = __readcr0() & ~(CR0_MP | CR0_TS | CR0_EM | CR0_ET);
01224 
01225     /* Store on FPU stack */
01226 #ifdef _MSC_VER
01227     __asm fninit;
01228     __asm fnstsw Magic;
01229 #else
01230     asm volatile ("fninit;" "fnstsw %0" : "+m"(Magic));
01231 #endif
01232 
01233     /* Magic should now be cleared */
01234     if (Magic & 0xFF)
01235     {
01236         /* You don't have an FPU -- enable emulation for now */
01237         __writecr0(Cr0 | CR0_EM | CR0_TS);
01238         return FALSE;
01239     }
01240 
01241     /* You have an FPU, enable it */
01242     Cr0 |= CR0_ET;
01243 
01244     /* Enable INT 16 on 486 and higher */
01245     if (KeGetCurrentPrcb()->CpuType >= 3) Cr0 |= CR0_NE;
01246 
01247     /* Set FPU state */
01248     __writecr0(Cr0 | CR0_EM | CR0_TS);
01249     return TRUE;
01250 }
01251 
01252 BOOLEAN
01253 NTAPI
01254 INIT_FUNCTION
01255 KiIsNpxErrataPresent(VOID)
01256 {
01257     static double Value1 = 4195835.0, Value2 = 3145727.0;
01258     INT ErrataPresent;
01259     ULONG Cr0;
01260 
01261     /* Disable interrupts */
01262     _disable();
01263 
01264     /* Read CR0 and remove FPU flags */
01265     Cr0 = __readcr0();
01266     __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
01267 
01268     /* Initialize FPU state */
01269     Ke386FnInit();
01270 
01271     /* Multiply the magic values and divide, we should get the result back */
01272 #ifdef __GNUC__
01273     __asm__ __volatile__
01274     (
01275         "fldl %1\n\t"
01276         "fdivl %2\n\t"
01277         "fmull %2\n\t"
01278         "fldl %1\n\t"
01279         "fsubp\n\t"
01280         "fistpl %0\n\t"
01281         : "=m" (ErrataPresent)
01282         : "m" (Value1),
01283           "m" (Value2)
01284     );
01285 #else
01286     __asm
01287     {
01288         fld Value1
01289         fdiv Value2
01290         fmul Value2
01291         fld Value1
01292         fsubp st(1), st(0)
01293         fistp ErrataPresent
01294     };
01295 #endif
01296 
01297     /* Restore CR0 */
01298     __writecr0(Cr0);
01299 
01300     /* Enable interrupts */
01301     _enable();
01302 
01303     /* Return if there's an errata */
01304     return ErrataPresent != 0;
01305 }
01306 
01307 VOID
01308 NTAPI
01309 KiFlushNPXState(IN PFLOATING_SAVE_AREA SaveArea)
01310 {
01311     ULONG EFlags, Cr0;
01312     PKTHREAD Thread, NpxThread;
01313     PFX_SAVE_AREA FxSaveArea;
01314 
01315     /* Save volatiles and disable interrupts */
01316     EFlags = __readeflags();
01317     _disable();
01318 
01319     /* Save the PCR and get the current thread */
01320     Thread = KeGetCurrentThread();
01321 
01322     /* Check if we're already loaded */
01323     if (Thread->NpxState != NPX_STATE_LOADED)
01324     {
01325         /* If there's nothing to load, quit */
01326         if (!SaveArea)
01327         {
01328             /* Restore interrupt state and return */
01329             __writeeflags(EFlags);
01330             return;
01331         }
01332 
01333         /* Need FXSR support for this */
01334         ASSERT(KeI386FxsrPresent == TRUE);
01335 
01336         /* Check for sane CR0 */
01337         Cr0 = __readcr0();
01338         if (Cr0 & (CR0_MP | CR0_TS | CR0_EM))
01339         {
01340             /* Mask out FPU flags */
01341             __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
01342         }
01343 
01344         /* Get the NPX thread and check its FPU state */
01345         NpxThread = KeGetCurrentPrcb()->NpxThread;
01346         if ((NpxThread) && (NpxThread->NpxState == NPX_STATE_LOADED))
01347         {
01348             /* Get the FX frame and store the state there */
01349             FxSaveArea = KiGetThreadNpxArea(NpxThread);
01350             Ke386FxSave(FxSaveArea);
01351 
01352             /* NPX thread has lost its state */
01353             NpxThread->NpxState = NPX_STATE_NOT_LOADED;
01354         }
01355 
01356         /* Now load NPX state from the NPX area */
01357         FxSaveArea = KiGetThreadNpxArea(Thread);
01358         Ke386FxStore(FxSaveArea);
01359     }
01360     else
01361     {
01362         /* Check for sane CR0 */
01363         Cr0 = __readcr0();
01364         if (Cr0 & (CR0_MP | CR0_TS | CR0_EM))
01365         {
01366             /* Mask out FPU flags */
01367             __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
01368         }
01369 
01370         /* Get FX frame */
01371         FxSaveArea = KiGetThreadNpxArea(Thread);
01372         Thread->NpxState = NPX_STATE_NOT_LOADED;
01373 
01374         /* Save state if supported by CPU */
01375         if (KeI386FxsrPresent) Ke386FxSave(FxSaveArea);
01376     }
01377 
01378     /* Now save the FN state wherever it was requested */
01379     if (SaveArea) Ke386FnSave(SaveArea);
01380 
01381     /* Clear NPX thread */
01382     KeGetCurrentPrcb()->NpxThread = NULL;
01383 
01384     /* Add the CR0 from the NPX frame */
01385     Cr0 |= NPX_STATE_NOT_LOADED;
01386     Cr0 |= FxSaveArea->Cr0NpxState;
01387     __writecr0(Cr0);
01388 
01389     /* Restore interrupt state */
01390     __writeeflags(EFlags);
01391 }
01392 
01393 /* PUBLIC FUNCTIONS **********************************************************/
01394 
01395 /*
01396  * @implemented
01397  */
01398 VOID
01399 NTAPI
01400 KiCoprocessorError(VOID)
01401 {
01402     PFX_SAVE_AREA NpxArea;
01403 
01404     /* Get the FPU area */
01405     NpxArea = KiGetThreadNpxArea(KeGetCurrentThread());
01406 
01407     /* Set CR0_TS */
01408     NpxArea->Cr0NpxState = CR0_TS;
01409     __writecr0(__readcr0() | CR0_TS);
01410 }
01411 
01412 /*
01413  * @implemented
01414  */
01415 NTSTATUS
01416 NTAPI
01417 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save)
01418 {
01419     PFNSAVE_FORMAT FpState;
01420     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
01421     DPRINT1("%s is not really implemented\n", __FUNCTION__);
01422 
01423     /* check if we are doing software emulation */
01424     if (!KeI386NpxPresent) return STATUS_ILLEGAL_FLOAT_CONTEXT;
01425 
01426     FpState = ExAllocatePool(NonPagedPool, sizeof (FNSAVE_FORMAT));
01427     if (!FpState) return STATUS_INSUFFICIENT_RESOURCES;
01428 
01429     *((PVOID *) Save) = FpState;
01430 #ifdef __GNUC__
01431     asm volatile("fnsave %0\n\t" : "=m" (*FpState));
01432 #else
01433     __asm
01434     {
01435         fnsave [FpState]
01436     };
01437 #endif
01438 
01439     KeGetCurrentThread()->Header.NpxIrql = KeGetCurrentIrql();
01440     return STATUS_SUCCESS;
01441 }
01442 
01443 /*
01444  * @implemented
01445  */
01446 NTSTATUS
01447 NTAPI
01448 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save)
01449 {
01450     PFNSAVE_FORMAT FpState = *((PVOID *) Save);
01451     ASSERT(KeGetCurrentThread()->Header.NpxIrql == KeGetCurrentIrql());
01452     DPRINT1("%s is not really implemented\n", __FUNCTION__);
01453 
01454 #ifdef __GNUC__
01455     asm volatile("fnclex\n\t");
01456     asm volatile("frstor %0\n\t" : "=m" (*FpState));
01457 #else
01458     __asm
01459     {
01460         fnclex
01461         frstor [FpState]
01462     };
01463 #endif
01464 
01465     ExFreePool(FpState);
01466     return STATUS_SUCCESS;
01467 }
01468 
01469 /*
01470  * @implemented
01471  */
01472 ULONG
01473 NTAPI
01474 KeGetRecommendedSharedDataAlignment(VOID)
01475 {
01476     /* Return the global variable */
01477     return KeLargestCacheLine;
01478 }
01479 
01480 VOID
01481 NTAPI
01482 KiFlushTargetEntireTb(IN PKIPI_CONTEXT PacketContext,
01483                       IN PVOID Ignored1,
01484                       IN PVOID Ignored2,
01485                       IN PVOID Ignored3)
01486 {
01487     /* Signal this packet as done */
01488     KiIpiSignalPacketDone(PacketContext);
01489 
01490     /* Flush the TB for the Current CPU */
01491     KeFlushCurrentTb();
01492 }
01493 
01494 /*
01495  * @implemented
01496  */
01497 VOID
01498 NTAPI
01499 KeFlushEntireTb(IN BOOLEAN Invalid,
01500                 IN BOOLEAN AllProcessors)
01501 {
01502     KIRQL OldIrql;
01503 #ifdef CONFIG_SMP
01504     KAFFINITY TargetAffinity;
01505     PKPRCB Prcb = KeGetCurrentPrcb();
01506 #endif
01507 
01508     /* Raise the IRQL for the TB Flush */
01509     OldIrql = KeRaiseIrqlToSynchLevel();
01510 
01511 #ifdef CONFIG_SMP
01512     /* FIXME: Use KiTbFlushTimeStamp to synchronize TB flush */
01513 
01514     /* Get the current processor affinity, and exclude ourselves */
01515     TargetAffinity = KeActiveProcessors;
01516     TargetAffinity &= ~Prcb->SetMember;
01517 
01518     /* Make sure this is MP */
01519     if (TargetAffinity)
01520     {
01521         /* Send an IPI TB flush to the other processors */
01522         KiIpiSendPacket(TargetAffinity,
01523                         KiFlushTargetEntireTb,
01524                         NULL,
01525                         0,
01526                         NULL);
01527     }
01528 #endif
01529 
01530     /* Flush the TB for the Current CPU, and update the flush stamp */
01531     KeFlushCurrentTb();
01532 
01533 #ifdef CONFIG_SMP
01534     /* If this is MP, wait for the other processors to finish */
01535     if (TargetAffinity)
01536     {
01537         /* Sanity check */
01538         ASSERT(Prcb == (volatile PKPRCB)KeGetCurrentPrcb());
01539 
01540         /* FIXME: TODO */
01541         ASSERTMSG("Not yet implemented\n", FALSE);
01542     }
01543 #endif
01544 
01545     /* Update the flush stamp and return to original IRQL */
01546     InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1);
01547     KeLowerIrql(OldIrql);
01548 }
01549 
01550 /*
01551  * @implemented
01552  */
01553 VOID
01554 NTAPI
01555 KeSetDmaIoCoherency(IN ULONG Coherency)
01556 {
01557     /* Save the coherency globally */
01558     KiDmaIoCoherency = Coherency;
01559 }
01560 
01561 /*
01562  * @implemented
01563  */
01564 KAFFINITY
01565 NTAPI
01566 KeQueryActiveProcessors(VOID)
01567 {
01568     PAGED_CODE();
01569 
01570     /* Simply return the number of active processors */
01571     return KeActiveProcessors;
01572 }
01573 
01574 /*
01575  * @implemented
01576  */
01577 VOID
01578 __cdecl
01579 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State)
01580 {
01581     /* Capture the context */
01582     RtlCaptureContext(&State->ContextFrame);
01583 
01584     /* Capture the control state */
01585     KiSaveProcessorControlState(State);
01586 }

Generated on Sat May 26 2012 04:36:18 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.