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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 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 /* Check if the CPU has hyper-threading */ 384 if (CpuFeatures & 0x10000000) 385 { 386 /* Set the number of logical CPUs */ 387 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(CpuInfo.Ebx >> 16); 388 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) 389 { 390 /* We're on dual-core */ 391 KiSMTProcessorsPresent = TRUE; 392 } 393 } 394 else 395 { 396 /* We only have a single CPU */ 397 Prcb->LogicalProcessorsPerPhysicalProcessor = 1; 398 } 399 400 /* Check if CPUID 0x80000000 is supported */ 401 if (ExtendedCPUID) 402 { 403 /* Do the call */ 404 KiCpuId(&CpuInfo, 0x80000000); 405 if ((CpuInfo.Eax & 0xffffff00) == 0x80000000) 406 { 407 /* Check if CPUID 0x80000001 is supported */ 408 if (CpuInfo.Eax >= 0x80000001) 409 { 410 /* Check which extended features are available. */ 411 KiCpuId(&CpuInfo, 0x80000001); 412 413 /* Check if NX-bit is supported */ 414 if (CpuInfo.Edx & 0x00100000) FeatureBits |= KF_NX_BIT; 415 416 /* Now handle each features for each CPU Vendor */ 417 switch (Vendor) 418 { 419 case CPU_AMD: 420 case CPU_CENTAUR: 421 if (CpuInfo.Edx & 0x80000000) FeatureBits |= KF_3DNOW; 422 break; 423 } 424 } 425 } 426 } 427 428 #define print_supported(kf_value) ((FeatureBits & kf_value) ? #kf_value : "") 429 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", 430 print_supported(KF_V86_VIS), 431 print_supported(KF_RDTSC), 432 print_supported(KF_CR4), 433 print_supported(KF_CMOV), 434 print_supported(KF_GLOBAL_PAGE), 435 print_supported(KF_LARGE_PAGE), 436 print_supported(KF_MTRR), 437 print_supported(KF_CMPXCHG8B), 438 print_supported(KF_MMX), 439 print_supported(KF_WORKING_PTE), 440 print_supported(KF_PAT), 441 print_supported(KF_FXSR), 442 print_supported(KF_FAST_SYSCALL), 443 print_supported(KF_XMMI), 444 print_supported(KF_3DNOW), 445 print_supported(KF_AMDK6MTRR), 446 print_supported(KF_XMMI64), 447 print_supported(KF_DTS), 448 print_supported(KF_NX_BIT), 449 print_supported(KF_NX_DISABLED), 450 print_supported(KF_NX_ENABLED)); 451 #undef print_supported 452 453 /* Return the Feature Bits */ 454 return FeatureBits; 455 } 456 457 INIT_FUNCTION 458 VOID 459 NTAPI 460 KiGetCacheInformation(VOID) 461 { 462 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 463 ULONG Vendor; 464 CPU_INFO CpuInfo; 465 ULONG CacheRequests = 0, i; 466 ULONG CurrentRegister; 467 UCHAR RegisterByte, Associativity = 0; 468 ULONG Size, CacheLine = 64, CurrentSize = 0; 469 BOOLEAN FirstPass = TRUE; 470 471 /* Set default L2 size */ 472 Pcr->SecondLevelCacheSize = 0; 473 474 /* Get the Vendor ID and make sure we support CPUID */ 475 Vendor = KiGetCpuVendor(); 476 if (!Vendor) return; 477 478 /* Check the Vendor ID */ 479 switch (Vendor) 480 { 481 /* Handle Intel case */ 482 case CPU_INTEL: 483 484 /*Check if we support CPUID 2 */ 485 KiCpuId(&CpuInfo, 0); 486 if (CpuInfo.Eax >= 2) 487 { 488 /* We need to loop for the number of times CPUID will tell us to */ 489 do 490 { 491 /* Do the CPUID call */ 492 KiCpuId(&CpuInfo, 2); 493 494 /* Check if it was the first call */ 495 if (FirstPass) 496 { 497 /* 498 * The number of times to loop is the first byte. Read 499 * it and then destroy it so we don't get confused. 500 */ 501 CacheRequests = CpuInfo.Eax & 0xFF; 502 CpuInfo.Eax &= 0xFFFFFF00; 503 504 /* Don't go over this again */ 505 FirstPass = FALSE; 506 } 507 508 /* Loop all 4 registers */ 509 for (i = 0; i < 4; i++) 510 { 511 /* Get the current register */ 512 CurrentRegister = CpuInfo.AsUINT32[i]; 513 514 /* 515 * If the upper bit is set, then this register should 516 * be skipped. 517 */ 518 if (CurrentRegister & 0x80000000) continue; 519 520 /* Keep looping for every byte inside this register */ 521 while (CurrentRegister) 522 { 523 /* Read a byte, skip a byte. */ 524 RegisterByte = (UCHAR)(CurrentRegister & 0xFF); 525 CurrentRegister >>= 8; 526 if (!RegisterByte) continue; 527 528 Size = 0; 529 switch (RegisterByte) 530 { 531 case 0x06: 532 case 0x08: 533 KePrefetchNTAGranularity = 32; 534 break; 535 case 0x09: 536 KePrefetchNTAGranularity = 64; 537 break; 538 case 0x0a: 539 case 0x0c: 540 KePrefetchNTAGranularity = 32; 541 break; 542 case 0x0d: 543 case 0x0e: 544 KePrefetchNTAGranularity = 64; 545 break; 546 case 0x1d: 547 Size = 128 * 1024; 548 Associativity = 2; 549 break; 550 case 0x21: 551 Size = 256 * 1024; 552 Associativity = 8; 553 break; 554 case 0x24: 555 Size = 1024 * 1024; 556 Associativity = 16; 557 break; 558 case 0x2c: 559 case 0x30: 560 KePrefetchNTAGranularity = 64; 561 break; 562 case 0x41: 563 case 0x42: 564 case 0x43: 565 case 0x44: 566 case 0x45: 567 Size = (1 << (RegisterByte - 0x41)) * 128 * 1024; 568 Associativity = 4; 569 break; 570 case 0x48: 571 Size = 3 * 1024 * 1024; 572 Associativity = 12; 573 break; 574 case 0x49: 575 Size = 4 * 1024 * 1024; 576 Associativity = 16; 577 break; 578 case 0x4e: 579 Size = 6 * 1024 * 1024; 580 Associativity = 24; 581 break; 582 case 0x60: 583 case 0x66: 584 case 0x67: 585 case 0x68: 586 KePrefetchNTAGranularity = 64; 587 break; 588 case 0x78: 589 Size = 1024 * 1024; 590 Associativity = 4; 591 break; 592 case 0x79: 593 case 0x7a: 594 case 0x7b: 595 case 0x7c: 596 case 0x7d: 597 Size = (1 << (RegisterByte - 0x79)) * 128 * 1024; 598 Associativity = 8; 599 break; 600 case 0x7f: 601 Size = 512 * 1024; 602 Associativity = 2; 603 break; 604 case 0x80: 605 Size = 512 * 1024; 606 Associativity = 8; 607 break; 608 case 0x82: 609 case 0x83: 610 case 0x84: 611 case 0x85: 612 Size = (1 << (RegisterByte - 0x82)) * 256 * 1024; 613 Associativity = 8; 614 break; 615 case 0x86: 616 Size = 512 * 1024; 617 Associativity = 4; 618 break; 619 case 0x87: 620 Size = 1024 * 1024; 621 Associativity = 8; 622 break; 623 case 0xf0: 624 KePrefetchNTAGranularity = 64; 625 break; 626 case 0xf1: 627 KePrefetchNTAGranularity = 128; 628 break; 629 } 630 if (Size && (Size / Associativity) > CurrentSize) 631 { 632 /* Set the L2 Cache Size and Associativity */ 633 CurrentSize = Size / Associativity; 634 Pcr->SecondLevelCacheSize = Size; 635 Pcr->SecondLevelCacheAssociativity = Associativity; 636 } 637 } 638 } 639 } while (--CacheRequests); 640 } 641 break; 642 643 case CPU_AMD: 644 645 /* Check if we support CPUID 0x80000005 */ 646 KiCpuId(&CpuInfo, 0x80000000); 647 if (CpuInfo.Eax >= 0x80000005) 648 { 649 /* Get L1 size first */ 650 KiCpuId(&CpuInfo, 0x80000005); 651 KePrefetchNTAGranularity = CpuInfo.Ecx & 0xFF; 652 653 /* Check if we support CPUID 0x80000006 */ 654 KiCpuId(&CpuInfo, 0x80000000); 655 if (CpuInfo.Eax >= 0x80000006) 656 { 657 /* Get 2nd level cache and tlb size */ 658 KiCpuId(&CpuInfo, 0x80000006); 659 660 /* Cache line size */ 661 CacheLine = CpuInfo.Ecx & 0xFF; 662 663 /* Hardcode associativity */ 664 RegisterByte = (CpuInfo.Ecx >> 12) & 0xFF; 665 switch (RegisterByte) 666 { 667 case 2: 668 Associativity = 2; 669 break; 670 671 case 4: 672 Associativity = 4; 673 break; 674 675 case 6: 676 Associativity = 8; 677 break; 678 679 case 8: 680 case 15: 681 Associativity = 16; 682 break; 683 684 default: 685 Associativity = 1; 686 break; 687 } 688 689 /* Compute size */ 690 Size = (CpuInfo.Ecx >> 16) << 10; 691 692 /* Hack for Model 6, Steping 300 */ 693 if ((KeGetCurrentPrcb()->CpuType == 6) && 694 (KeGetCurrentPrcb()->CpuStep == 0x300)) 695 { 696 /* Stick 64K in there */ 697 Size = 64 * 1024; 698 } 699 700 /* Set the L2 Cache Size and associativity */ 701 Pcr->SecondLevelCacheSize = Size; 702 Pcr->SecondLevelCacheAssociativity = Associativity; 703 } 704 } 705 break; 706 707 case CPU_CYRIX: 708 case CPU_TRANSMETA: 709 case CPU_CENTAUR: 710 case CPU_RISE: 711 712 /* FIXME */ 713 break; 714 } 715 716 /* Set the cache line */ 717 if (CacheLine > KeLargestCacheLine) KeLargestCacheLine = CacheLine; 718 DPRINT1("Prefetch Cache: %lu bytes\tL2 Cache: %lu bytes\tL2 Cache Line: %lu bytes\tL2 Cache Associativity: %lu\n", 719 KePrefetchNTAGranularity, 720 Pcr->SecondLevelCacheSize, 721 KeLargestCacheLine, 722 Pcr->SecondLevelCacheAssociativity); 723 } 724 725 INIT_FUNCTION 726 VOID 727 NTAPI 728 KiSetCR0Bits(VOID) 729 { 730 ULONG Cr0; 731 732 /* Save current CR0 */ 733 Cr0 = __readcr0(); 734 735 /* If this is a 486, enable Write-Protection */ 736 if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP; 737 738 /* Set new Cr0 */ 739 __writecr0(Cr0); 740 } 741 742 INIT_FUNCTION 743 VOID 744 NTAPI 745 KiInitializeTSS2(IN PKTSS Tss, 746 IN PKGDTENTRY TssEntry OPTIONAL) 747 { 748 PUCHAR p; 749 750 /* Make sure the GDT Entry is valid */ 751 if (TssEntry) 752 { 753 /* Set the Limit */ 754 TssEntry->LimitLow = sizeof(KTSS) - 1; 755 TssEntry->HighWord.Bits.LimitHi = 0; 756 } 757 758 /* Now clear the I/O Map */ 759 ASSERT(IOPM_COUNT == 1); 760 RtlFillMemory(Tss->IoMaps[0].IoMap, IOPM_FULL_SIZE, 0xFF); 761 762 /* Initialize Interrupt Direction Maps */ 763 p = (PUCHAR)(Tss->IoMaps[0].DirectionMap); 764 RtlZeroMemory(p, IOPM_DIRECTION_MAP_SIZE); 765 766 /* Add DPMI support for interrupts */ 767 p[0] = 4; 768 p[3] = 0x18; 769 p[4] = 0x18; 770 771 /* Initialize the default Interrupt Direction Map */ 772 p = Tss->IntDirectionMap; 773 RtlZeroMemory(Tss->IntDirectionMap, IOPM_DIRECTION_MAP_SIZE); 774 775 /* Add DPMI support */ 776 p[0] = 4; 777 p[3] = 0x18; 778 p[4] = 0x18; 779 } 780 781 VOID 782 NTAPI 783 KiInitializeTSS(IN PKTSS Tss) 784 { 785 /* Set an invalid map base */ 786 Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 787 788 /* Disable traps during Task Switches */ 789 Tss->Flags = 0; 790 791 /* Set LDT and Ring 0 SS */ 792 Tss->LDT = 0; 793 Tss->Ss0 = KGDT_R0_DATA; 794 } 795 796 INIT_FUNCTION 797 VOID 798 FASTCALL 799 Ki386InitializeTss(IN PKTSS Tss, 800 IN PKIDTENTRY Idt, 801 IN PKGDTENTRY Gdt) 802 { 803 PKGDTENTRY TssEntry, TaskGateEntry; 804 805 /* Initialize the boot TSS. */ 806 TssEntry = &Gdt[KGDT_TSS / sizeof(KGDTENTRY)]; 807 TssEntry->HighWord.Bits.Type = I386_TSS; 808 TssEntry->HighWord.Bits.Pres = 1; 809 TssEntry->HighWord.Bits.Dpl = 0; 810 KiInitializeTSS2(Tss, TssEntry); 811 KiInitializeTSS(Tss); 812 813 /* Load the task register */ 814 Ke386SetTr(KGDT_TSS); 815 816 /* Setup the Task Gate for Double Fault Traps */ 817 TaskGateEntry = (PKGDTENTRY)&Idt[8]; 818 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE; 819 TaskGateEntry->HighWord.Bits.Pres = 1; 820 TaskGateEntry->HighWord.Bits.Dpl = 0; 821 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_DF_TSS; 822 823 /* Initialize the TSS used for handling double faults. */ 824 Tss = (PKTSS)KiDoubleFaultTSS; 825 KiInitializeTSS(Tss); 826 Tss->CR3 = __readcr3(); 827 Tss->Esp0 = KiDoubleFaultStack; 828 Tss->Esp = KiDoubleFaultStack; 829 Tss->Eip = PtrToUlong(KiTrap08); 830 Tss->Cs = KGDT_R0_CODE; 831 Tss->Fs = KGDT_R0_PCR; 832 Tss->Ss = Ke386GetSs(); 833 Tss->Es = KGDT_R3_DATA | RPL_MASK; 834 Tss->Ds = KGDT_R3_DATA | RPL_MASK; 835 836 /* Setup the Double Trap TSS entry in the GDT */ 837 TssEntry = &Gdt[KGDT_DF_TSS / sizeof(KGDTENTRY)]; 838 TssEntry->HighWord.Bits.Type = I386_TSS; 839 TssEntry->HighWord.Bits.Pres = 1; 840 TssEntry->HighWord.Bits.Dpl = 0; 841 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF); 842 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16); 843 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24); 844 TssEntry->LimitLow = KTSS_IO_MAPS; 845 846 /* Now setup the NMI Task Gate */ 847 TaskGateEntry = (PKGDTENTRY)&Idt[2]; 848 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE; 849 TaskGateEntry->HighWord.Bits.Pres = 1; 850 TaskGateEntry->HighWord.Bits.Dpl = 0; 851 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_NMI_TSS; 852 853 /* Initialize the actual TSS */ 854 Tss = (PKTSS)KiNMITSS; 855 KiInitializeTSS(Tss); 856 Tss->CR3 = __readcr3(); 857 Tss->Esp0 = KiDoubleFaultStack; 858 Tss->Esp = KiDoubleFaultStack; 859 Tss->Eip = PtrToUlong(KiTrap02); 860 Tss->Cs = KGDT_R0_CODE; 861 Tss->Fs = KGDT_R0_PCR; 862 Tss->Ss = Ke386GetSs(); 863 Tss->Es = KGDT_R3_DATA | RPL_MASK; 864 Tss->Ds = KGDT_R3_DATA | RPL_MASK; 865 866 /* And its associated TSS Entry */ 867 TssEntry = &Gdt[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; 868 TssEntry->HighWord.Bits.Type = I386_TSS; 869 TssEntry->HighWord.Bits.Pres = 1; 870 TssEntry->HighWord.Bits.Dpl = 0; 871 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF); 872 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16); 873 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24); 874 TssEntry->LimitLow = KTSS_IO_MAPS; 875 } 876 877 VOID 878 NTAPI 879 KeFlushCurrentTb(VOID) 880 { 881 882 #if !defined(_GLOBAL_PAGES_ARE_AWESOME_) 883 884 /* Flush the TLB by resetting CR3 */ 885 __writecr3(__readcr3()); 886 887 #else 888 889 /* Check if global pages are enabled */ 890 if (KeFeatureBits & KF_GLOBAL_PAGE) 891 { 892 ULONG Cr4; 893 894 /* Disable PGE (Note: may not have been enabled yet) */ 895 Cr4 = __readcr4(); 896 __writecr4(Cr4 & ~CR4_PGE); 897 898 /* Flush everything */ 899 __writecr3(__readcr3()); 900 901 /* Re-enable PGE */ 902 __writecr4(Cr4); 903 } 904 else 905 { 906 /* No global pages, resetting CR3 is enough */ 907 __writecr3(__readcr3()); 908 } 909 910 #endif 911 912 } 913 914 VOID 915 NTAPI 916 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState) 917 { 918 PKGDTENTRY TssEntry; 919 920 // 921 // Restore the CR registers 922 // 923 __writecr0(ProcessorState->SpecialRegisters.Cr0); 924 Ke386SetCr2(ProcessorState->SpecialRegisters.Cr2); 925 __writecr3(ProcessorState->SpecialRegisters.Cr3); 926 if (KeFeatureBits & KF_CR4) __writecr4(ProcessorState->SpecialRegisters.Cr4); 927 928 // 929 // Restore the DR registers 930 // 931 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0); 932 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1); 933 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2); 934 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3); 935 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6); 936 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7); 937 938 // 939 // Restore GDT and IDT 940 // 941 Ke386SetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit); 942 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 943 944 // 945 // Clear the busy flag so we don't crash if we reload the same selector 946 // 947 TssEntry = (PKGDTENTRY)(ProcessorState->SpecialRegisters.Gdtr.Base + 948 ProcessorState->SpecialRegisters.Tr); 949 TssEntry->HighWord.Bytes.Flags1 &= ~0x2; 950 951 // 952 // Restore TSS and LDT 953 // 954 Ke386SetTr(ProcessorState->SpecialRegisters.Tr); 955 Ke386SetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr); 956 } 957 958 VOID 959 NTAPI 960 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState) 961 { 962 /* Save the CR registers */ 963 ProcessorState->SpecialRegisters.Cr0 = __readcr0(); 964 ProcessorState->SpecialRegisters.Cr2 = __readcr2(); 965 ProcessorState->SpecialRegisters.Cr3 = __readcr3(); 966 ProcessorState->SpecialRegisters.Cr4 = (KeFeatureBits & KF_CR4) ? 967 __readcr4() : 0; 968 969 /* Save the DR registers */ 970 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0); 971 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1); 972 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2); 973 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3); 974 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6); 975 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7); 976 __writedr(7, 0); 977 978 /* Save GDT, IDT, LDT and TSS */ 979 Ke386GetGlobalDescriptorTable(&ProcessorState->SpecialRegisters.Gdtr.Limit); 980 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit); 981 ProcessorState->SpecialRegisters.Tr = Ke386GetTr(); 982 ProcessorState->SpecialRegisters.Ldtr = Ke386GetLocalDescriptorTable(); 983 } 984 985 INIT_FUNCTION 986 VOID 987 NTAPI 988 KiInitializeMachineType(VOID) 989 { 990 /* Set the Machine Type we got from NTLDR */ 991 KeI386MachineType = KeLoaderBlock->u.I386.MachineType & 0x000FF; 992 } 993 994 INIT_FUNCTION 995 ULONG_PTR 996 NTAPI 997 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context) 998 { 999 /* Set CS and ESP */ 1000 __writemsr(0x174, KGDT_R0_CODE); 1001 __writemsr(0x175, (ULONG_PTR)KeGetCurrentPrcb()->DpcStack); 1002 1003 /* Set LSTAR */ 1004 __writemsr(0x176, (ULONG_PTR)KiFastCallEntry); 1005 return 0; 1006 } 1007 1008 INIT_FUNCTION 1009 VOID 1010 NTAPI 1011 KiRestoreFastSyscallReturnState(VOID) 1012 { 1013 /* Check if the CPU Supports fast system call */ 1014 if (KeFeatureBits & KF_FAST_SYSCALL) 1015 { 1016 /* Check if it has been disabled */ 1017 if (KiFastSystemCallDisable) 1018 { 1019 /* Disable fast system call */ 1020 KeFeatureBits &= ~KF_FAST_SYSCALL; 1021 KiFastCallExitHandler = KiSystemCallTrapReturn; 1022 DPRINT1("Support for SYSENTER disabled.\n"); 1023 } 1024 else 1025 { 1026 /* Do an IPI to enable it */ 1027 KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0); 1028 1029 /* It's enabled, so use the proper exit stub */ 1030 KiFastCallExitHandler = KiSystemCallSysExitReturn; 1031 DPRINT("Support for SYSENTER detected.\n"); 1032 } 1033 } 1034 else 1035 { 1036 /* Use the IRET handler */ 1037 KiFastCallExitHandler = KiSystemCallTrapReturn; 1038 DPRINT1("No support for SYSENTER detected.\n"); 1039 } 1040 } 1041 1042 INIT_FUNCTION 1043 ULONG_PTR 1044 NTAPI 1045 Ki386EnableDE(IN ULONG_PTR Context) 1046 { 1047 /* Enable DE */ 1048 __writecr4(__readcr4() | CR4_DE); 1049 return 0; 1050 } 1051 1052 INIT_FUNCTION 1053 ULONG_PTR 1054 NTAPI 1055 Ki386EnableFxsr(IN ULONG_PTR Context) 1056 { 1057 /* Enable FXSR */ 1058 __writecr4(__readcr4() | CR4_FXSR); 1059 return 0; 1060 } 1061 1062 INIT_FUNCTION 1063 ULONG_PTR 1064 NTAPI 1065 Ki386EnableXMMIExceptions(IN ULONG_PTR Context) 1066 { 1067 PKIDTENTRY IdtEntry; 1068 1069 /* Get the IDT Entry for Interrupt 0x13 */ 1070 IdtEntry = &((PKIPCR)KeGetPcr())->IDT[0x13]; 1071 1072 /* Set it up */ 1073 IdtEntry->Selector = KGDT_R0_CODE; 1074 IdtEntry->Offset = ((ULONG_PTR)KiTrap13 & 0xFFFF); 1075 IdtEntry->ExtendedOffset = ((ULONG_PTR)KiTrap13 >> 16) & 0xFFFF; 1076 ((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0; 1077 ((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1; 1078 ((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE; 1079 1080 /* Enable XMMI exceptions */ 1081 __writecr4(__readcr4() | CR4_XMMEXCPT); 1082 return 0; 1083 } 1084 1085 INIT_FUNCTION 1086 VOID 1087 NTAPI 1088 KiI386PentiumLockErrataFixup(VOID) 1089 { 1090 KDESCRIPTOR IdtDescriptor = {0, 0, 0}; 1091 PKIDTENTRY NewIdt, NewIdt2; 1092 1093 /* Allocate memory for a new IDT */ 1094 NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE); 1095 1096 /* Put everything after the first 7 entries on a new page */ 1097 NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY))); 1098 1099 /* Disable interrupts */ 1100 _disable(); 1101 1102 /* Get the current IDT and copy it */ 1103 __sidt(&IdtDescriptor.Limit); 1104 RtlCopyMemory(NewIdt2, 1105 (PVOID)IdtDescriptor.Base, 1106 IdtDescriptor.Limit + 1); 1107 IdtDescriptor.Base = (ULONG)NewIdt2; 1108 1109 /* Set the new IDT */ 1110 __lidt(&IdtDescriptor.Limit); 1111 ((PKIPCR)KeGetPcr())->IDT = NewIdt2; 1112 1113 /* Restore interrupts */ 1114 _enable(); 1115 1116 /* Set the first 7 entries as read-only to produce a fault */ 1117 MmSetPageProtect(NULL, NewIdt, PAGE_READONLY); 1118 } 1119 1120 BOOLEAN 1121 NTAPI 1122 KeInvalidateAllCaches(VOID) 1123 { 1124 /* Only supported on Pentium Pro and higher */ 1125 if (KeI386CpuType < 6) return FALSE; 1126 1127 /* Invalidate all caches */ 1128 __wbinvd(); 1129 return TRUE; 1130 } 1131 1132 VOID 1133 FASTCALL 1134 KeZeroPages(IN PVOID Address, 1135 IN ULONG Size) 1136 { 1137 /* Not using XMMI in this routine */ 1138 RtlZeroMemory(Address, Size); 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 INIT_FUNCTION 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 INIT_FUNCTION 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 DPRINT1("%s is not really implemented\n", __FUNCTION__); 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 DPRINT1("%s is not really implemented\n", __FUNCTION__); 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