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/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
1.7.6.1
|