1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/i386/cpu.c 5 * PURPOSE: Routines for CPU-level support 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS *******************************************************************/ 16 17 /* The TSS to use for Double Fault Traps (INT 0x9) */ 18 UCHAR KiDoubleFaultTSS[KTSS_IO_MAPS]; 19 20 /* The TSS to use for NMI Fault Traps (INT 0x2) */ 21 UCHAR KiNMITSS[KTSS_IO_MAPS]; 22 23 /* CPU Features and Flags */ 24 ULONG KeI386CpuType; 25 ULONG KeI386CpuStep; 26 ULONG KiFastSystemCallDisable = 0; 27 ULONG KeI386NpxPresent = 0; 28 ULONG KiMXCsrMask = 0; 29 ULONG MxcsrFeatureMask = 0; 30 ULONG KeI386XMMIPresent = 0; 31 ULONG KeI386FxsrPresent = 0; 32 ULONG KeI386MachineType; 33 ULONG Ke386Pae = FALSE; 34 ULONG Ke386NoExecute = FALSE; 35 ULONG KeLargestCacheLine = 0x40; 36 ULONG KeDcacheFlushCount = 0; 37 ULONG KeIcacheFlushCount = 0; 38 ULONG KiDmaIoCoherency = 0; 39 ULONG KePrefetchNTAGranularity = 32; 40 BOOLEAN KiI386PentiumLockErrataPresent; 41 BOOLEAN KiSMTProcessorsPresent; 42 43 /* The distance between SYSEXIT and IRETD return modes */ 44 UCHAR KiSystemCallExitAdjust; 45 46 /* The offset that was applied -- either 0 or the value above */ 47 UCHAR KiSystemCallExitAdjusted; 48 49 /* Whether the adjustment was already done once */ 50 BOOLEAN KiFastCallCopyDoneOnce; 51 52 /* Flush data */ 53 volatile LONG KiTbFlushTimeStamp; 54 55 /* CPU Signatures */ 56 static const CHAR CmpIntelID[] = "GenuineIntel"; 57 static const CHAR CmpAmdID[] = "AuthenticAMD"; 58 static const CHAR CmpCyrixID[] = "CyrixInstead"; 59 static const CHAR CmpTransmetaID[] = "GenuineTMx86"; 60 static const CHAR CmpCentaurID[] = "CentaurHauls"; 61 static const CHAR CmpRiseID[] = "RiseRiseRise"; 62 63 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/ 64 65 /* NSC/Cyrix CPU configuration register index */ 66 #define CX86_CCR1 0xc1 67 68 /* NSC/Cyrix CPU indexed register access macros */ 69 static __inline 70 UCHAR 71 getCx86(UCHAR reg) 72 { 73 WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22, reg); 74 return READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23); 75 } 76 77 static __inline 78 void 79 setCx86(UCHAR reg, UCHAR data) 80 { 81 WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22, reg); 82 WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23, data); 83 } 84 85 86 /* FUNCTIONS *****************************************************************/ 87 88 CODE_SEG("INIT") 89 VOID 90 NTAPI 91 KiSetProcessorType(VOID) 92 { 93 ULONG EFlags, NewEFlags; 94 CPU_INFO CpuInfo; 95 ULONG Stepping, Type; 96 97 /* Start by assuming no CPUID data */ 98 KeGetCurrentPrcb()->CpuID = 0; 99 100 /* Save EFlags */ 101 EFlags = __readeflags(); 102 103 /* XOR out the ID bit and update EFlags */ 104 NewEFlags = EFlags ^ EFLAGS_ID; 105 __writeeflags(NewEFlags); 106 107 /* Get them back and see if they were modified */ 108 NewEFlags = __readeflags(); 109 if (NewEFlags != EFlags) 110 { 111 /* The modification worked, so CPUID exists. Set the ID Bit again. */ 112 EFlags |= EFLAGS_ID; 113 __writeeflags(EFlags); 114 115 /* Peform CPUID 0 to see if CPUID 1 is supported */ 116 KiCpuId(&CpuInfo, 0); 117 if (CpuInfo.Eax > 0) 118 { 119 /* Do CPUID 1 now */ 120 KiCpuId(&CpuInfo, 1); 121 122 /* 123 * Get the Stepping and Type. The stepping contains both the 124 * Model and the Step, while the Type contains the returned Type. 125 * We ignore the family. 126 * 127 * For the stepping, we convert this: zzzzzzxy into this: x0y 128 */ 129 Stepping = CpuInfo.Eax & 0xF0; 130 Stepping <<= 4; 131 Stepping += (CpuInfo.Eax & 0xFF); 132 Stepping &= 0xF0F; 133 Type = CpuInfo.Eax & 0xF00; 134 Type >>= 8; 135 136 /* Save them in the PRCB */ 137 KeGetCurrentPrcb()->CpuID = TRUE; 138 KeGetCurrentPrcb()->CpuType = (UCHAR)Type; 139 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping; 140 } 141 else 142 { 143 DPRINT1("CPUID Support lacking\n"); 144 } 145 } 146 else 147 { 148 DPRINT1("CPUID Support lacking\n"); 149 } 150 151 /* Restore EFLAGS */ 152 __writeeflags(EFlags); 153 } 154 155 CODE_SEG("INIT") 156 ULONG 157 NTAPI 158 KiGetCpuVendor(VOID) 159 { 160 PKPRCB Prcb = KeGetCurrentPrcb(); 161 CPU_INFO CpuInfo; 162 163 /* Assume no Vendor ID and fail if no CPUID Support. */ 164 Prcb->VendorString[0] = 0; 165 if (!Prcb->CpuID) return 0; 166 167 /* Get the Vendor ID */ 168 KiCpuId(&CpuInfo, 0); 169 170 /* Copy it to the PRCB and null-terminate it */ 171 *(ULONG*)&Prcb->VendorString[0] = CpuInfo.Ebx; 172 *(ULONG*)&Prcb->VendorString[4] = CpuInfo.Edx; 173 *(ULONG*)&Prcb->VendorString[8] = CpuInfo.Ecx; 174 Prcb->VendorString[12] = 0; 175 176 /* Now check the CPU Type */ 177 if (!strcmp(Prcb->VendorString, CmpIntelID)) 178 { 179 return CPU_INTEL; 180 } 181 else if (!strcmp(Prcb->VendorString, CmpAmdID)) 182 { 183 return CPU_AMD; 184 } 185 else if (!strcmp(Prcb->VendorString, CmpCyrixID)) 186 { 187 DPRINT1("Cyrix CPU support not fully tested!\n"); 188 return CPU_CYRIX; 189 } 190 else if (!strcmp(Prcb->VendorString, CmpTransmetaID)) 191 { 192 DPRINT1("Transmeta CPU support not fully tested!\n"); 193 return CPU_TRANSMETA; 194 } 195 else if (!strcmp(Prcb->VendorString, CmpCentaurID)) 196 { 197 DPRINT1("Centaur CPU support not fully tested!\n"); 198 return CPU_CENTAUR; 199 } 200 else if (!strcmp(Prcb->VendorString, CmpRiseID)) 201 { 202 DPRINT1("Rise CPU support not fully tested!\n"); 203 return CPU_RISE; 204 } 205 206 /* Unknown CPU */ 207 DPRINT1("%s CPU support not fully tested!\n", Prcb->VendorString); 208 return CPU_UNKNOWN; 209 } 210 211 CODE_SEG("INIT") 212 ULONG 213 NTAPI 214 KiGetFeatureBits(VOID) 215 { 216 PKPRCB Prcb = KeGetCurrentPrcb(); 217 ULONG Vendor; 218 ULONG FeatureBits = KF_WORKING_PTE; 219 CPU_INFO CpuInfo, DummyCpuInfo; 220 UCHAR Ccr1; 221 BOOLEAN ExtendedCPUID = TRUE; 222 ULONG CpuFeatures = 0; 223 224 /* Get the Vendor ID */ 225 Vendor = KiGetCpuVendor(); 226 227 /* Make sure we got a valid vendor ID at least. */ 228 if (!Vendor) return FeatureBits; 229 230 /* Get the CPUID Info. Features are in Reg[3]. */ 231 KiCpuId(&CpuInfo, 1); 232 233 /* Set the initial APIC ID */ 234 Prcb->InitialApicId = (UCHAR)(CpuInfo.Ebx >> 24); 235 236 switch (Vendor) 237 { 238 /* Intel CPUs */ 239 case CPU_INTEL: 240 241 /* Check if it's a P6 */ 242 if (Prcb->CpuType == 6) 243 { 244 /* Perform the special sequence to get the MicroCode Signature */ 245 __writemsr(0x8B, 0); 246 KiCpuId(&DummyCpuInfo, 1); 247 Prcb->UpdateSignature.QuadPart = __readmsr(0x8B); 248 } 249 else if (Prcb->CpuType == 5) 250 { 251 /* On P5, enable workaround for the LOCK errata. */ 252 KiI386PentiumLockErrataPresent = TRUE; 253 } 254 255 /* Check for broken P6 with bad SMP PTE implementation */ 256 if (((CpuInfo.Eax & 0x0FF0) == 0x0610 && (CpuInfo.Eax & 0x000F) <= 0x9) || 257 ((CpuInfo.Eax & 0x0FF0) == 0x0630 && (CpuInfo.Eax & 0x000F) <= 0x4)) 258 { 259 /* Remove support for correct PTE support. */ 260 FeatureBits &= ~KF_WORKING_PTE; 261 } 262 263 /* Check if the CPU is too old to support SYSENTER */ 264 if ((Prcb->CpuType < 6) || 265 ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303))) 266 { 267 /* Disable it */ 268 CpuInfo.Edx &= ~0x800; 269 } 270 271 break; 272 273 /* AMD CPUs */ 274 case CPU_AMD: 275 276 /* Check if this is a K5 or K6. (family 5) */ 277 if ((CpuInfo.Eax & 0x0F00) == 0x0500) 278 { 279 /* Get the Model Number */ 280 switch (CpuInfo.Eax & 0x00F0) 281 { 282 /* Model 1: K5 - 5k86 (initial models) */ 283 case 0x0010: 284 285 /* Check if this is Step 0 or 1. They don't support PGE */ 286 if ((CpuInfo.Eax & 0x000F) > 0x03) break; 287 288 /* Model 0: K5 - SSA5 */ 289 case 0x0000: 290 291 /* Model 0 doesn't support PGE at all. */ 292 CpuInfo.Edx &= ~0x2000; 293 break; 294 295 /* Model 8: K6-2 */ 296 case 0x0080: 297 298 /* K6-2, Step 8 and over have support for MTRR. */ 299 if ((CpuInfo.Eax & 0x000F) >= 0x8) FeatureBits |= KF_AMDK6MTRR; 300 break; 301 302 /* Model 9: K6-III 303 Model D: K6-2+, K6-III+ */ 304 case 0x0090: 305 case 0x00D0: 306 307 FeatureBits |= KF_AMDK6MTRR; 308 break; 309 } 310 } 311 else if((CpuInfo.Eax & 0x0F00) < 0x0500) 312 { 313 /* Families below 5 don't support PGE, PSE or CMOV at all */ 314 CpuInfo.Edx &= ~(0x08 | 0x2000 | 0x8000); 315 316 /* They also don't support advanced CPUID functions. */ 317 ExtendedCPUID = FALSE; 318 } 319 320 break; 321 322 /* Cyrix CPUs */ 323 case CPU_CYRIX: 324 325 /* Workaround the "COMA" bug on 6x family of Cyrix CPUs */ 326 if (Prcb->CpuType == 6 && 327 Prcb->CpuStep <= 1) 328 { 329 /* Get CCR1 value */ 330 Ccr1 = getCx86(CX86_CCR1); 331 332 /* Enable the NO_LOCK bit */ 333 Ccr1 |= 0x10; 334 335 /* Set the new CCR1 value */ 336 setCx86(CX86_CCR1, Ccr1); 337 } 338 339 break; 340 341 /* Transmeta CPUs */ 342 case CPU_TRANSMETA: 343 344 /* Enable CMPXCHG8B if the family (>= 5), model and stepping (>= 4.2) support it */ 345 if ((CpuInfo.Eax & 0x0FFF) >= 0x0542) 346 { 347 __writemsr(0x80860004, __readmsr(0x80860004) | 0x0100); 348 FeatureBits |= KF_CMPXCHG8B; 349 } 350 351 break; 352 353 /* Centaur, IDT, Rise and VIA CPUs */ 354 case CPU_CENTAUR: 355 case CPU_RISE: 356 357 /* These CPUs don't report the presence of CMPXCHG8B through CPUID. 358 However, this feature exists and operates properly without any additional steps. */ 359 FeatureBits |= KF_CMPXCHG8B; 360 361 break; 362 } 363 364 /* Set the current features */ 365 CpuFeatures = CpuInfo.Edx; 366 367 /* Convert all CPUID Feature bits into our format */ 368 if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4; 369 if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4; 370 if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC; 371 if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B; 372 if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL; 373 if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR; 374 if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4; 375 if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV; 376 if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT; 377 if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS; 378 if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX; 379 if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR; 380 if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI; 381 if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64; 382 383 if (CpuFeatures & 0x00000040) 384 { 385 DPRINT1("Support PAE\n"); 386 } 387 388 /* Check if the CPU has hyper-threading */ 389 if (CpuFeatures & 0x10000000) 390 { 391 /* Set the number of logical CPUs */ 392 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(CpuInfo.Ebx >> 16); 393 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) 394 { 395 /* We're on dual-core */ 396 KiSMTProcessorsPresent = TRUE; 397 } 398 } 399 else 400 { 401 /* We only have a single CPU */ 402 Prcb->LogicalProcessorsPerPhysicalProcessor = 1; 403 } 404 405 /* Check if CPUID 0x80000000 is supported */ 406 if (ExtendedCPUID) 407 { 408 /* Do the call */ 409 KiCpuId(&CpuInfo, 0x80000000); 410 if ((CpuInfo.Eax & 0xffffff00) == 0x80000000) 411 { 412 /* Check if CPUID 0x80000001 is supported */ 413 if (CpuInfo.Eax >= 0x80000001) 414 { 415 /* Check which extended features are available. */ 416 KiCpuId(&CpuInfo, 0x80000001); 417 418 /* Check if NX-bit is supported */ 419 if (CpuInfo.Edx & 0x00100000) FeatureBits |= KF_NX_BIT; 420 421 /* Now handle each features for each CPU Vendor */ 422 switch (Vendor) 423 { 424 case CPU_AMD: 425 case CPU_CENTAUR: 426 if (CpuInfo.Edx & 0x80000000) FeatureBits |= KF_3DNOW; 427 break; 428 } 429 } 430 } 431 } 432 433 #define print_supported(kf_value) ((FeatureBits & kf_value) ? #kf_value : "") 434 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", 435 print_supported(KF_V86_VIS), 436 print_supported(KF_RDTSC), 437 print_supported(KF_CR4), 438 print_supported(KF_CMOV), 439 print_supported(KF_GLOBAL_PAGE), 440 print_supported(KF_LARGE_PAGE), 441 print_supported(KF_MTRR), 442 print_supported(KF_CMPXCHG8B), 443 print_supported(KF_MMX), 444 print_supported(KF_WORKING_PTE), 445 print_supported(KF_PAT), 446 print_supported(KF_FXSR), 447 print_supported(KF_FAST_SYSCALL), 448 print_supported(KF_XMMI), 449 print_supported(KF_3DNOW), 450 print_supported(KF_AMDK6MTRR), 451 print_supported(KF_XMMI64), 452 print_supported(KF_DTS), 453 print_supported(KF_NX_BIT), 454 print_supported(KF_NX_DISABLED), 455 print_supported(KF_NX_ENABLED)); 456 #undef print_supported 457 458 /* Return the Feature Bits */ 459 return FeatureBits; 460 } 461 462 CODE_SEG("INIT") 463 VOID 464 NTAPI 465 KiGetCacheInformation(VOID) 466 { 467 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 468 ULONG Vendor; 469 CPU_INFO CpuInfo; 470 ULONG CacheRequests = 0, i; 471 ULONG CurrentRegister; 472 UCHAR RegisterByte, Associativity = 0; 473 ULONG Size, CacheLine = 64, CurrentSize = 0; 474 BOOLEAN FirstPass = TRUE; 475 476 /* Set default L2 size */ 477 Pcr->SecondLevelCacheSize = 0; 478 479 /* Get the Vendor ID and make sure we support CPUID */ 480 Vendor = KiGetCpuVendor(); 481 if (!Vendor) return; 482 483 /* Check the Vendor ID */ 484 switch (Vendor) 485 { 486 /* Handle Intel case */ 487 case CPU_INTEL: 488 489 /*Check if we support CPUID 2 */ 490 KiCpuId(&CpuInfo, 0); 491 if (CpuInfo.Eax >= 2) 492 { 493 /* We need to loop for the number of times CPUID will tell us to */ 494 do 495 { 496 /* Do the CPUID call */ 497 KiCpuId(&CpuInfo, 2); 498 499 /* Check if it was the first call */ 500 if (FirstPass) 501 { 502 /* 503 * The number of times to loop is the first byte. Read 504 * it and then destroy it so we don't get confused. 505 */ 506 CacheRequests = CpuInfo.Eax & 0xFF; 507 CpuInfo.Eax &= 0xFFFFFF00; 508 509 /* Don't go over this again */ 510 FirstPass = FALSE; 511 } 512 513 /* Loop all 4 registers */ 514 for (i = 0; i < 4; i++) 515 { 516 /* Get the current register */ 517 CurrentRegister = CpuInfo.AsUINT32[i]; 518 519 /* 520 * If the upper bit is set, then this register should 521 * be skipped. 522 */ 523 if (CurrentRegister & 0x80000000) continue; 524 525 /* Keep looping for every byte inside this register */ 526 while (CurrentRegister) 527 { 528 /* Read a byte, skip a byte. */ 529 RegisterByte = (UCHAR)(CurrentRegister & 0xFF); 530 CurrentRegister >>= 8; 531 if (!RegisterByte) continue; 532 533 Size = 0; 534 switch (RegisterByte) 535 { 536 case 0x06: 537 case 0x08: 538 KePrefetchNTAGranularity = 32; 539 break; 540 case 0x09: 541 KePrefetchNTAGranularity = 64; 542 break; 543 case 0x0a: 544 case 0x0c: 545 KePrefetchNTAGranularity = 32; 546 break; 547 case 0x0d: 548 case 0x0e: 549 KePrefetchNTAGranularity = 64; 550 break; 551 case 0x1d: 552 Size = 128 * 1024; 553 Associativity = 2; 554 break; 555 case 0x21: 556 Size = 256 * 1024; 557 Associativity = 8; 558 break; 559 case 0x24: 560 Size = 1024 * 1024; 561 Associativity = 16; 562 break; 563 case 0x2c: 564 case 0x30: 565 KePrefetchNTAGranularity = 64; 566 break; 567 case 0x41: 568 case 0x42: 569 case 0x43: 570 case 0x44: 571 case 0x45: 572 Size = (1 << (RegisterByte - 0x41)) * 128 * 1024; 573 Associativity = 4; 574 break; 575 case 0x48: 576 Size = 3 * 1024 * 1024; 577 Associativity = 12; 578 break; 579 case 0x49: 580 Size = 4 * 1024 * 1024; 581 Associativity = 16; 582 break; 583 case 0x4e: 584 Size = 6 * 1024 * 1024; 585 Associativity = 24; 586 break; 587 case 0x60: 588 case 0x66: 589 case 0x67: 590 case 0x68: 591 KePrefetchNTAGranularity = 64; 592 break; 593 case 0x78: 594 Size = 1024 * 1024; 595 Associativity = 4; 596 break; 597 case 0x79: 598 case 0x7a: 599 case 0x7b: 600 case 0x7c: 601 case 0x7d: 602 Size = (1 << (RegisterByte - 0x79)) * 128 * 1024; 603 Associativity = 8; 604 break; 605 case 0x7f: 606 Size = 512 * 1024; 607 Associativity = 2; 608 break; 609 case 0x80: 610 Size = 512 * 1024; 611 Associativity = 8; 612 break; 613 case 0x82: 614 case 0x83: 615 case 0x84: 616 case 0x85: 617 Size = (1 << (RegisterByte - 0x82)) * 256 * 1024; 618 Associativity = 8; 619 break; 620 case 0x86: 621 Size = 512 * 1024; 622 Associativity = 4; 623 break; 624 case 0x87: 625 Size = 1024 * 1024; 626 Associativity = 8; 627 break; 628 case 0xf0: 629 KePrefetchNTAGranularity = 64; 630 break; 631 case 0xf1: 632 KePrefetchNTAGranularity = 128; 633 break; 634 } 635 if (Size && (Size / Associativity) > CurrentSize) 636 { 637 /* Set the L2 Cache Size and Associativity */ 638 CurrentSize = Size / Associativity; 639 Pcr->SecondLevelCacheSize = Size; 640 Pcr->SecondLevelCacheAssociativity = Associativity; 641 } 642 } 643 } 644 } while (--CacheRequests); 645 } 646 break; 647 648 case CPU_AMD: 649 650 /* Check if we support CPUID 0x80000005 */ 651 KiCpuId(&CpuInfo, 0x80000000); 652 if (CpuInfo.Eax >= 0x80000005) 653 { 654 /* Get L1 size first */ 655 KiCpuId(&CpuInfo, 0x80000005); 656 KePrefetchNTAGranularity = CpuInfo.Ecx & 0xFF; 657 658 /* Check if we support CPUID 0x80000006 */ 659 KiCpuId(&CpuInfo, 0x80000000); 660 if (CpuInfo.Eax >= 0x80000006) 661 { 662 /* Get 2nd level cache and tlb size */ 663 KiCpuId(&CpuInfo, 0x80000006); 664 665 /* Cache line size */ 666 CacheLine = CpuInfo.Ecx & 0xFF; 667 668 /* Hardcode associativity */ 669 RegisterByte = (CpuInfo.Ecx >> 12) & 0xFF; 670 switch (RegisterByte) 671 { 672 case 2: 673 Associativity = 2; 674 break; 675 676 case 4: 677 Associativity = 4; 678 break; 679 680 case 6: 681 Associativity = 8; 682 break; 683 684 case 8: 685 case 15: 686 Associativity = 16; 687 break; 688 689 default: 690 Associativity = 1; 691 break; 692 } 693 694 /* Compute size */ 695 Size = (CpuInfo.Ecx >> 16) << 10; 696 697 /* Hack for Model 6, Steping 300 */ 698 if ((KeGetCurrentPrcb()->CpuType == 6) && 699 (KeGetCurrentPrcb()->CpuStep == 0x300)) 700 { 701 /* Stick 64K in there */ 702 Size = 64 * 1024; 703 } 704 705 /* Set the L2 Cache Size and associativity */ 706 Pcr->SecondLevelCacheSize = Size; 707 Pcr->SecondLevelCacheAssociativity = Associativity; 708 } 709 } 710 break; 711 712 case CPU_CYRIX: 713 case CPU_TRANSMETA: 714 case CPU_CENTAUR: 715 case CPU_RISE: 716 717 /* FIXME */ 718 break; 719 } 720 721 /* Set the cache line */ 722 if (CacheLine > KeLargestCacheLine) KeLargestCacheLine = CacheLine; 723 DPRINT1("Prefetch Cache: %lu bytes\tL2 Cache: %lu bytes\tL2 Cache Line: %lu bytes\tL2 Cache Associativity: %lu\n", 724 KePrefetchNTAGranularity, 725 Pcr->SecondLevelCacheSize, 726 KeLargestCacheLine, 727 Pcr->SecondLevelCacheAssociativity); 728 } 729 730 CODE_SEG("INIT") 731 VOID 732 NTAPI 733 KiSetCR0Bits(VOID) 734 { 735 ULONG Cr0; 736 737 /* Save current CR0 */ 738 Cr0 = __readcr0(); 739 740 /* If this is a 486, enable Write-Protection */ 741 if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP; 742 743 /* Set new Cr0 */ 744 __writecr0(Cr0); 745 } 746 747 CODE_SEG("INIT") 748 VOID 749 NTAPI 750 KiInitializeTSS2(IN PKTSS Tss, 751 IN PKGDTENTRY TssEntry OPTIONAL) 752 { 753 PUCHAR p; 754 755 /* Make sure the GDT Entry is valid */ 756 if (TssEntry) 757 { 758 /* Set the Limit */ 759 TssEntry->LimitLow = sizeof(KTSS) - 1; 760 TssEntry->HighWord.Bits.LimitHi = 0; 761 } 762 763 /* Now clear the I/O Map */ 764 ASSERT(IOPM_COUNT == 1); 765 RtlFillMemory(Tss->IoMaps[0].IoMap, IOPM_FULL_SIZE, 0xFF); 766 767 /* Initialize Interrupt Direction Maps */ 768 p = (PUCHAR)(Tss->IoMaps[0].DirectionMap); 769 RtlZeroMemory(p, IOPM_DIRECTION_MAP_SIZE); 770 771 /* Add DPMI support for interrupts */ 772 p[0] = 4; 773 p[3] = 0x18; 774 p[4] = 0x18; 775 776 /* Initialize the default Interrupt Direction Map */ 777 p = Tss->IntDirectionMap; 778 RtlZeroMemory(Tss->IntDirectionMap, IOPM_DIRECTION_MAP_SIZE); 779 780 /* Add DPMI support */ 781 p[0] = 4; 782 p[3] = 0x18; 783 p[4] = 0x18; 784 } 785 786 VOID 787 NTAPI 788 KiInitializeTSS(IN PKTSS Tss) 789 { 790 /* Set an invalid map base */ 791 Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 792 793 /* Disable traps during Task Switches */ 794 Tss->Flags = 0; 795 796 /* Set LDT and Ring 0 SS */ 797 Tss->LDT = 0; 798 Tss->Ss0 = KGDT_R0_DATA; 799 } 800 801 CODE_SEG("INIT") 802 VOID 803 FASTCALL 804 Ki386InitializeTss(IN PKTSS Tss, 805 IN PKIDTENTRY Idt, 806 IN PKGDTENTRY Gdt) 807 { 808 PKGDTENTRY TssEntry, TaskGateEntry; 809 810 /* Initialize the boot TSS. */ 811 TssEntry = &Gdt[KGDT_TSS / sizeof(KGDTENTRY)]; 812 TssEntry->HighWord.Bits.Type = I386_TSS; 813 TssEntry->HighWord.Bits.Pres = 1; 814 TssEntry->HighWord.Bits.Dpl = 0; 815 KiInitializeTSS2(Tss, TssEntry); 816 KiInitializeTSS(Tss); 817 818 /* Load the task register */ 819 Ke386SetTr(KGDT_TSS); 820 821 /* Setup the Task Gate for Double Fault Traps */ 822 TaskGateEntry = (PKGDTENTRY)&Idt[8]; 823 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE; 824 TaskGateEntry->HighWord.Bits.Pres = 1; 825 TaskGateEntry->HighWord.Bits.Dpl = 0; 826 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_DF_TSS; 827 828 /* Initialize the TSS used for handling double faults. */ 829 Tss = (PKTSS)KiDoubleFaultTSS; 830 KiInitializeTSS(Tss); 831 Tss->CR3 = __readcr3(); 832 Tss->Esp0 = KiDoubleFaultStack; 833 Tss->Esp = KiDoubleFaultStack; 834 Tss->Eip = PtrToUlong(KiTrap08); 835 Tss->Cs = KGDT_R0_CODE; 836 Tss->Fs = KGDT_R0_PCR; 837 Tss->Ss = Ke386GetSs(); 838 Tss->Es = KGDT_R3_DATA | RPL_MASK; 839 Tss->Ds = KGDT_R3_DATA | RPL_MASK; 840 841 /* Setup the Double Trap TSS entry in the GDT */ 842 TssEntry = &Gdt[KGDT_DF_TSS / sizeof(KGDTENTRY)]; 843 TssEntry->HighWord.Bits.Type = I386_TSS; 844 TssEntry->HighWord.Bits.Pres = 1; 845 TssEntry->HighWord.Bits.Dpl = 0; 846 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF); 847 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16); 848 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24); 849 TssEntry->LimitLow = KTSS_IO_MAPS; 850 851 /* Now setup the NMI Task Gate */ 852 TaskGateEntry = (PKGDTENTRY)&Idt[2]; 853 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE; 854 TaskGateEntry->HighWord.Bits.Pres = 1; 855 TaskGateEntry->HighWord.Bits.Dpl = 0; 856 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_NMI_TSS; 857 858 /* Initialize the actual TSS */ 859 Tss = (PKTSS)KiNMITSS; 860 KiInitializeTSS(Tss); 861 Tss->CR3 = __readcr3(); 862 Tss->Esp0 = KiDoubleFaultStack; 863 Tss->Esp = KiDoubleFaultStack; 864 Tss->Eip = PtrToUlong(KiTrap02); 865 Tss->Cs = KGDT_R0_CODE; 866 Tss->Fs = KGDT_R0_PCR; 867 Tss->Ss = Ke386GetSs(); 868 Tss->Es = KGDT_R3_DATA | RPL_MASK; 869 Tss->Ds = KGDT_R3_DATA | RPL_MASK; 870 871 /* And its associated TSS Entry */ 872 TssEntry = &Gdt[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; 873 TssEntry->HighWord.Bits.Type = I386_TSS; 874 TssEntry->HighWord.Bits.Pres = 1; 875 TssEntry->HighWord.Bits.Dpl = 0; 876 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF); 877 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16); 878 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24); 879 TssEntry->LimitLow = KTSS_IO_MAPS; 880 } 881 882 VOID 883 NTAPI 884 KeFlushCurrentTb(VOID) 885 { 886 887 #if !defined(_GLOBAL_PAGES_ARE_AWESOME_) 888 889 /* Flush the TLB by resetting CR3 */ 890 __writecr3(__readcr3()); 891 892 #else 893 894 /* Check if global pages are enabled */ 895 if (KeFeatureBits & KF_GLOBAL_PAGE) 896 { 897 ULONG Cr4; 898 899 /* Disable PGE (Note: may not have been enabled yet) */ 900 Cr4 = __readcr4(); 901 __writecr4(Cr4 & ~CR4_PGE); 902 903 /* Flush everything */ 904 __writecr3(__readcr3()); 905 906 /* Re-enable PGE */ 907 __writecr4(Cr4); 908 } 909 else 910 { 911 /* No global pages, resetting CR3 is enough */ 912 __writecr3(__readcr3()); 913 } 914 915 #endif 916 917 } 918 919 VOID 920 NTAPI 921 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState) 922 { 923 PKGDTENTRY TssEntry; 924 925 // 926 // Restore the CR registers 927 // 928 __writecr0(ProcessorState->SpecialRegisters.Cr0); 929 Ke386SetCr2(ProcessorState->SpecialRegisters.Cr2); 930 __writecr3(ProcessorState->SpecialRegisters.Cr3); 931 if (KeFeatureBits & KF_CR4) __writecr4(ProcessorState->SpecialRegisters.Cr4); 932 933 // 934 // Restore the DR registers 935 // 936 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0); 937 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1); 938 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2); 939 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3); 940 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6); 941 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7); 942 943 // 944 // Restore GDT and IDT 945 // 946 Ke386SetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit); 947 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 948 949 // 950 // Clear the busy flag so we don't crash if we reload the same selector 951 // 952 TssEntry = (PKGDTENTRY)(ProcessorState->SpecialRegisters.Gdtr.Base + 953 ProcessorState->SpecialRegisters.Tr); 954 TssEntry->HighWord.Bytes.Flags1 &= ~0x2; 955 956 // 957 // Restore TSS and LDT 958 // 959 Ke386SetTr(ProcessorState->SpecialRegisters.Tr); 960 Ke386SetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr); 961 } 962 963 VOID 964 NTAPI 965 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState) 966 { 967 /* Save the CR registers */ 968 ProcessorState->SpecialRegisters.Cr0 = __readcr0(); 969 ProcessorState->SpecialRegisters.Cr2 = __readcr2(); 970 ProcessorState->SpecialRegisters.Cr3 = __readcr3(); 971 ProcessorState->SpecialRegisters.Cr4 = (KeFeatureBits & KF_CR4) ? 972 __readcr4() : 0; 973 974 /* Save the DR registers */ 975 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0); 976 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1); 977 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2); 978 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3); 979 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6); 980 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7); 981 __writedr(7, 0); 982 983 /* Save GDT, IDT, LDT and TSS */ 984 Ke386GetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit); 985 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 986 ProcessorState->SpecialRegisters.Tr = Ke386GetTr(); 987 Ke386GetLocalDescriptorTable(&ProcessorState->SpecialRegisters.Ldtr); 988 } 989 990 CODE_SEG("INIT") 991 VOID 992 NTAPI 993 KiInitializeMachineType(VOID) 994 { 995 /* Set the Machine Type we got from NTLDR */ 996 KeI386MachineType = KeLoaderBlock->u.I386.MachineType & 0x000FF; 997 } 998 999 CODE_SEG("INIT") 1000 ULONG_PTR 1001 NTAPI 1002 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context) 1003 { 1004 /* Set CS and ESP */ 1005 __writemsr(0x174, KGDT_R0_CODE); 1006 __writemsr(0x175, (ULONG_PTR)KeGetCurrentPrcb()->DpcStack); 1007 1008 /* Set LSTAR */ 1009 __writemsr(0x176, (ULONG_PTR)KiFastCallEntry); 1010 return 0; 1011 } 1012 1013 CODE_SEG("INIT") 1014 VOID 1015 NTAPI 1016 KiRestoreFastSyscallReturnState(VOID) 1017 { 1018 /* Check if the CPU Supports fast system call */ 1019 if (KeFeatureBits & KF_FAST_SYSCALL) 1020 { 1021 /* Check if it has been disabled */ 1022 if (KiFastSystemCallDisable) 1023 { 1024 /* Disable fast system call */ 1025 KeFeatureBits &= ~KF_FAST_SYSCALL; 1026 KiFastCallExitHandler = KiSystemCallTrapReturn; 1027 DPRINT1("Support for SYSENTER disabled.\n"); 1028 } 1029 else 1030 { 1031 /* Do an IPI to enable it */ 1032 KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); 1033 1034 /* It's enabled, so use the proper exit stub */ 1035 KiFastCallExitHandler = KiSystemCallSysExitReturn; 1036 DPRINT("Support for SYSENTER detected.\n"); 1037 } 1038 } 1039 else 1040 { 1041 /* Use the IRET handler */ 1042 KiFastCallExitHandler = KiSystemCallTrapReturn; 1043 DPRINT1("No support for SYSENTER detected.\n"); 1044 } 1045 } 1046 1047 CODE_SEG("INIT") 1048 ULONG_PTR 1049 NTAPI 1050 Ki386EnableDE(IN ULONG_PTR Context) 1051 { 1052 /* Enable DE */ 1053 __writecr4(__readcr4() | CR4_DE); 1054 return 0; 1055 } 1056 1057 CODE_SEG("INIT") 1058 ULONG_PTR 1059 NTAPI 1060 Ki386EnableFxsr(IN ULONG_PTR Context) 1061 { 1062 /* Enable FXSR */ 1063 __writecr4(__readcr4() | CR4_FXSR); 1064 return 0; 1065 } 1066 1067 CODE_SEG("INIT") 1068 ULONG_PTR 1069 NTAPI 1070 Ki386EnableXMMIExceptions(IN ULONG_PTR Context) 1071 { 1072 PKIDTENTRY IdtEntry; 1073 1074 /* Get the IDT Entry for Interrupt 0x13 */ 1075 IdtEntry = &((PKIPCR)KeGetPcr())->IDT[0x13]; 1076 1077 /* Set it up */ 1078 IdtEntry->Selector = KGDT_R0_CODE; 1079 IdtEntry->Offset = ((ULONG_PTR)KiTrap13 & 0xFFFF); 1080 IdtEntry->ExtendedOffset = ((ULONG_PTR)KiTrap13 >> 16) & 0xFFFF; 1081 ((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0; 1082 ((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1; 1083 ((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE; 1084 1085 /* Enable XMMI exceptions */ 1086 __writecr4(__readcr4() | CR4_XMMEXCPT); 1087 return 0; 1088 } 1089 1090 CODE_SEG("INIT") 1091 VOID 1092 NTAPI 1093 KiI386PentiumLockErrataFixup(VOID) 1094 { 1095 KDESCRIPTOR IdtDescriptor = {0, 0, 0}; 1096 PKIDTENTRY NewIdt, NewIdt2; 1097 PMMPTE PointerPte; 1098 1099 /* Allocate memory for a new IDT */ 1100 NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE); 1101 1102 /* Put everything after the first 7 entries on a new page */ 1103 NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY))); 1104 1105 /* Disable interrupts */ 1106 _disable(); 1107 1108 /* Get the current IDT and copy it */ 1109 __sidt(&IdtDescriptor.Limit); 1110 RtlCopyMemory(NewIdt2, 1111 (PVOID)IdtDescriptor.Base, 1112 IdtDescriptor.Limit + 1); 1113 IdtDescriptor.Base = (ULONG)NewIdt2; 1114 1115 /* Set the new IDT */ 1116 __lidt(&IdtDescriptor.Limit); 1117 ((PKIPCR)KeGetPcr())->IDT = NewIdt2; 1118 1119 /* Restore interrupts */ 1120 _enable(); 1121 1122 /* Set the first 7 entries as read-only to produce a fault */ 1123 PointerPte = MiAddressToPte(NewIdt); 1124 ASSERT(PointerPte->u.Hard.Write == 1); 1125 PointerPte->u.Hard.Write = 0; 1126 KeInvalidateTlbEntry(NewIdt); 1127 } 1128 1129 BOOLEAN 1130 NTAPI 1131 KeInvalidateAllCaches(VOID) 1132 { 1133 /* Only supported on Pentium Pro and higher */ 1134 if (KeI386CpuType < 6) return FALSE; 1135 1136 /* Invalidate all caches */ 1137 __wbinvd(); 1138 return TRUE; 1139 } 1140 1141 VOID 1142 NTAPI 1143 KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame, 1144 IN PKEXCEPTION_FRAME ExceptionFrame) 1145 { 1146 PKPRCB Prcb = KeGetCurrentPrcb(); 1147 1148 // 1149 // Save full context 1150 // 1151 Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_FULL | 1152 CONTEXT_DEBUG_REGISTERS; 1153 KeTrapFrameToContext(TrapFrame, NULL, &Prcb->ProcessorState.ContextFrame); 1154 1155 // 1156 // Save control registers 1157 // 1158 KiSaveProcessorControlState(&Prcb->ProcessorState); 1159 } 1160 1161 CODE_SEG("INIT") 1162 BOOLEAN 1163 NTAPI 1164 KiIsNpxPresent(VOID) 1165 { 1166 ULONG Cr0; 1167 USHORT Magic; 1168 1169 /* Set magic */ 1170 Magic = 0xFFFF; 1171 1172 /* Read CR0 and mask out FPU flags */ 1173 Cr0 = __readcr0() & ~(CR0_MP | CR0_TS | CR0_EM | CR0_ET); 1174 1175 /* Store on FPU stack */ 1176 #ifdef _MSC_VER 1177 __asm fninit; 1178 __asm fnstsw Magic; 1179 #else 1180 asm volatile ("fninit;" "fnstsw %0" : "+m"(Magic)); 1181 #endif 1182 1183 /* Magic should now be cleared */ 1184 if (Magic & 0xFF) 1185 { 1186 /* You don't have an FPU -- enable emulation for now */ 1187 __writecr0(Cr0 | CR0_EM | CR0_TS); 1188 return FALSE; 1189 } 1190 1191 /* You have an FPU, enable it */ 1192 Cr0 |= CR0_ET; 1193 1194 /* Enable INT 16 on 486 and higher */ 1195 if (KeGetCurrentPrcb()->CpuType >= 3) Cr0 |= CR0_NE; 1196 1197 /* Set FPU state */ 1198 __writecr0(Cr0 | CR0_EM | CR0_TS); 1199 return TRUE; 1200 } 1201 1202 CODE_SEG("INIT") 1203 BOOLEAN 1204 NTAPI 1205 KiIsNpxErrataPresent(VOID) 1206 { 1207 static double Value1 = 4195835.0, Value2 = 3145727.0; 1208 INT ErrataPresent; 1209 ULONG Cr0; 1210 1211 /* Disable interrupts */ 1212 _disable(); 1213 1214 /* Read CR0 and remove FPU flags */ 1215 Cr0 = __readcr0(); 1216 __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM)); 1217 1218 /* Initialize FPU state */ 1219 Ke386FnInit(); 1220 1221 /* Multiply the magic values and divide, we should get the result back */ 1222 #ifdef __GNUC__ 1223 __asm__ __volatile__ 1224 ( 1225 "fldl %1\n\t" 1226 "fdivl %2\n\t" 1227 "fmull %2\n\t" 1228 "fldl %1\n\t" 1229 "fsubp\n\t" 1230 "fistpl %0\n\t" 1231 : "=m" (ErrataPresent) 1232 : "m" (Value1), 1233 "m" (Value2) 1234 ); 1235 #else 1236 __asm 1237 { 1238 fld Value1 1239 fdiv Value2 1240 fmul Value2 1241 fld Value1 1242 fsubp st(1), st(0) 1243 fistp ErrataPresent 1244 }; 1245 #endif 1246 1247 /* Restore CR0 */ 1248 __writecr0(Cr0); 1249 1250 /* Enable interrupts */ 1251 _enable(); 1252 1253 /* Return if there's an errata */ 1254 return ErrataPresent != 0; 1255 } 1256 1257 VOID 1258 NTAPI 1259 KiFlushNPXState(IN PFLOATING_SAVE_AREA SaveArea) 1260 { 1261 ULONG EFlags, Cr0; 1262 PKTHREAD Thread, NpxThread; 1263 PFX_SAVE_AREA FxSaveArea; 1264 1265 /* Save volatiles and disable interrupts */ 1266 EFlags = __readeflags(); 1267 _disable(); 1268 1269 /* Save the PCR and get the current thread */ 1270 Thread = KeGetCurrentThread(); 1271 1272 /* Check if we're already loaded */ 1273 if (Thread->NpxState != NPX_STATE_LOADED) 1274 { 1275 /* If there's nothing to load, quit */ 1276 if (!SaveArea) 1277 { 1278 /* Restore interrupt state and return */ 1279 __writeeflags(EFlags); 1280 return; 1281 } 1282 1283 /* Need FXSR support for this */ 1284 ASSERT(KeI386FxsrPresent == TRUE); 1285 1286 /* Check for sane CR0 */ 1287 Cr0 = __readcr0(); 1288 if (Cr0 & (CR0_MP | CR0_TS | CR0_EM)) 1289 { 1290 /* Mask out FPU flags */ 1291 __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM)); 1292 } 1293 1294 /* Get the NPX thread and check its FPU state */ 1295 NpxThread = KeGetCurrentPrcb()->NpxThread; 1296 if ((NpxThread) && (NpxThread->NpxState == NPX_STATE_LOADED)) 1297 { 1298 /* Get the FX frame and store the state there */ 1299 FxSaveArea = KiGetThreadNpxArea(NpxThread); 1300 Ke386FxSave(FxSaveArea); 1301 1302 /* NPX thread has lost its state */ 1303 NpxThread->NpxState = NPX_STATE_NOT_LOADED; 1304 } 1305 1306 /* Now load NPX state from the NPX area */ 1307 FxSaveArea = KiGetThreadNpxArea(Thread); 1308 Ke386FxStore(FxSaveArea); 1309 } 1310 else 1311 { 1312 /* Check for sane CR0 */ 1313 Cr0 = __readcr0(); 1314 if (Cr0 & (CR0_MP | CR0_TS | CR0_EM)) 1315 { 1316 /* Mask out FPU flags */ 1317 __writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM)); 1318 } 1319 1320 /* Get FX frame */ 1321 FxSaveArea = KiGetThreadNpxArea(Thread); 1322 Thread->NpxState = NPX_STATE_NOT_LOADED; 1323 1324 /* Save state if supported by CPU */ 1325 if (KeI386FxsrPresent) Ke386FxSave(FxSaveArea); 1326 } 1327 1328 /* Now save the FN state wherever it was requested */ 1329 if (SaveArea) Ke386FnSave(SaveArea); 1330 1331 /* Clear NPX thread */ 1332 KeGetCurrentPrcb()->NpxThread = NULL; 1333 1334 /* Add the CR0 from the NPX frame */ 1335 Cr0 |= NPX_STATE_NOT_LOADED; 1336 Cr0 |= FxSaveArea->Cr0NpxState; 1337 __writecr0(Cr0); 1338 1339 /* Restore interrupt state */ 1340 __writeeflags(EFlags); 1341 } 1342 1343 /* PUBLIC FUNCTIONS **********************************************************/ 1344 1345 /* 1346 * @implemented 1347 */ 1348 VOID 1349 NTAPI 1350 KiCoprocessorError(VOID) 1351 { 1352 PFX_SAVE_AREA NpxArea; 1353 1354 /* Get the FPU area */ 1355 NpxArea = KiGetThreadNpxArea(KeGetCurrentThread()); 1356 1357 /* Set CR0_TS */ 1358 NpxArea->Cr0NpxState = CR0_TS; 1359 __writecr0(__readcr0() | CR0_TS); 1360 } 1361 1362 /* 1363 * @implemented 1364 */ 1365 NTSTATUS 1366 NTAPI 1367 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save) 1368 { 1369 PFNSAVE_FORMAT FpState; 1370 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 1371 UNIMPLEMENTED_ONCE; 1372 1373 /* check if we are doing software emulation */ 1374 if (!KeI386NpxPresent) return STATUS_ILLEGAL_FLOAT_CONTEXT; 1375 1376 FpState = ExAllocatePool(NonPagedPool, sizeof (FNSAVE_FORMAT)); 1377 if (!FpState) return STATUS_INSUFFICIENT_RESOURCES; 1378 1379 *((PVOID *) Save) = FpState; 1380 #ifdef __GNUC__ 1381 asm volatile("fnsave %0\n\t" : "=m" (*FpState)); 1382 #else 1383 __asm 1384 { 1385 mov eax, [FpState] 1386 fnsave [eax] 1387 }; 1388 #endif 1389 1390 KeGetCurrentThread()->Header.NpxIrql = KeGetCurrentIrql(); 1391 return STATUS_SUCCESS; 1392 } 1393 1394 /* 1395 * @implemented 1396 */ 1397 NTSTATUS 1398 NTAPI 1399 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save) 1400 { 1401 PFNSAVE_FORMAT FpState = *((PVOID *) Save); 1402 ASSERT(KeGetCurrentThread()->Header.NpxIrql == KeGetCurrentIrql()); 1403 UNIMPLEMENTED_ONCE; 1404 1405 #ifdef __GNUC__ 1406 asm volatile("fnclex\n\t"); 1407 asm volatile("frstor %0\n\t" : "=m" (*FpState)); 1408 #else 1409 __asm 1410 { 1411 fnclex 1412 mov eax, [FpState] 1413 frstor [eax] 1414 }; 1415 #endif 1416 1417 ExFreePool(FpState); 1418 return STATUS_SUCCESS; 1419 } 1420 1421 /* 1422 * @implemented 1423 */ 1424 ULONG 1425 NTAPI 1426 KeGetRecommendedSharedDataAlignment(VOID) 1427 { 1428 /* Return the global variable */ 1429 return KeLargestCacheLine; 1430 } 1431 1432 VOID 1433 NTAPI 1434 KiFlushTargetEntireTb(IN PKIPI_CONTEXT PacketContext, 1435 IN PVOID Ignored1, 1436 IN PVOID Ignored2, 1437 IN PVOID Ignored3) 1438 { 1439 /* Signal this packet as done */ 1440 KiIpiSignalPacketDone(PacketContext); 1441 1442 /* Flush the TB for the Current CPU */ 1443 KeFlushCurrentTb(); 1444 } 1445 1446 /* 1447 * @implemented 1448 */ 1449 VOID 1450 NTAPI 1451 KeFlushEntireTb(IN BOOLEAN Invalid, 1452 IN BOOLEAN AllProcessors) 1453 { 1454 KIRQL OldIrql; 1455 #ifdef CONFIG_SMP 1456 KAFFINITY TargetAffinity; 1457 PKPRCB Prcb = KeGetCurrentPrcb(); 1458 #endif 1459 1460 /* Raise the IRQL for the TB Flush */ 1461 OldIrql = KeRaiseIrqlToSynchLevel(); 1462 1463 #ifdef CONFIG_SMP 1464 /* FIXME: Use KiTbFlushTimeStamp to synchronize TB flush */ 1465 1466 /* Get the current processor affinity, and exclude ourselves */ 1467 TargetAffinity = KeActiveProcessors; 1468 TargetAffinity &= ~Prcb->SetMember; 1469 1470 /* Make sure this is MP */ 1471 if (TargetAffinity) 1472 { 1473 /* Send an IPI TB flush to the other processors */ 1474 KiIpiSendPacket(TargetAffinity, 1475 KiFlushTargetEntireTb, 1476 NULL, 1477 0, 1478 NULL); 1479 } 1480 #endif 1481 1482 /* Flush the TB for the Current CPU, and update the flush stamp */ 1483 KeFlushCurrentTb(); 1484 1485 #ifdef CONFIG_SMP 1486 /* If this is MP, wait for the other processors to finish */ 1487 if (TargetAffinity) 1488 { 1489 /* Sanity check */ 1490 ASSERT(Prcb == KeGetCurrentPrcb()); 1491 1492 /* FIXME: TODO */ 1493 ASSERTMSG("Not yet implemented\n", FALSE); 1494 } 1495 #endif 1496 1497 /* Update the flush stamp and return to original IRQL */ 1498 InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1); 1499 KeLowerIrql(OldIrql); 1500 } 1501 1502 /* 1503 * @implemented 1504 */ 1505 VOID 1506 NTAPI 1507 KeSetDmaIoCoherency(IN ULONG Coherency) 1508 { 1509 /* Save the coherency globally */ 1510 KiDmaIoCoherency = Coherency; 1511 } 1512 1513 /* 1514 * @implemented 1515 */ 1516 KAFFINITY 1517 NTAPI 1518 KeQueryActiveProcessors(VOID) 1519 { 1520 PAGED_CODE(); 1521 1522 /* Simply return the number of active processors */ 1523 return KeActiveProcessors; 1524 } 1525 1526 /* 1527 * @implemented 1528 */ 1529 VOID 1530 __cdecl 1531 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State) 1532 { 1533 /* Capture the context */ 1534 RtlCaptureContext(&State->ContextFrame); 1535 1536 /* Capture the control state */ 1537 KiSaveProcessorControlState(State); 1538 } 1539