Index: ntoskrnl/ke/i386/cpu.c =================================================================== --- ntoskrnl/ke/i386/cpu.c (revision 48757) +++ ntoskrnl/ke/i386/cpu.c (working copy) @@ -105,6 +105,84 @@ return __readmsr(Register); } +/* + * NSC/Cyrix CPU configuration register indexes + */ +#define CX86_CCR0 0xc0 +#define CX86_CCR1 0xc1 +#define CX86_CCR2 0xc2 +#define CX86_CCR3 0xc3 +#define CX86_CCR4 0xe8 +#define CX86_CCR5 0xe9 +#define CX86_CCR6 0xea +#define CX86_CCR7 0xeb +#define CX86_DIR0 0xfe +#define CX86_DIR1 0xff +#define CX86_ARR_BASE 0xc4 +#define CX86_RCR_BASE 0xdc + +/* + * NSC/Cyrix CPU indexed register access macros + */ + +#define getCx86(reg) ({ WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22,(reg)); READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23); }) + +#define setCx86(reg, data) do { \ + WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x22,(reg)); \ + WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)0x23,(data)); \ +} while (0) + + + +/* + * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU + */ +VOID +NTAPI +GetCyrixDevID(PUCHAR dir0,PUCHAR dir1) +{ + UCHAR ccr2; + UCHAR ccr3; + //UCHAR flags; + + /* we test for DEVID by checking whether CCR3 is writable */ + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, ccr3 ^ 0x80); + /* dummy to change bus */ + getCx86(CX86_CCR0); + + if (getCx86(CX86_CCR3) == ccr3) + { + /* no DEVID regs. */ + ccr2 = getCx86(CX86_CCR2); + setCx86(CX86_CCR2, ccr2 ^ 0x04); + /* dummy */ + getCx86(CX86_CCR0); + + if (getCx86(CX86_CCR2) == ccr2) + { + /* old Cx486SLC/DLC */ + *dir0 = 0xfd; + } + else + { + /* Cx486S A step */ + setCx86(CX86_CCR2, ccr2); + *dir0 = 0xfe; + } + } + else + { + /* restore CCR3 */ + setCx86(CX86_CCR3, ccr3); + /* read DIR0 and DIR1 CPU registers */ + *dir0 = getCx86(CX86_DIR0); + *dir1 = getCx86(CX86_DIR1); + } +} + + + /* FUNCTIONS *****************************************************************/ VOID @@ -242,6 +320,10 @@ ULONG Vendor; ULONG FeatureBits = KF_WORKING_PTE; ULONG Reg[4], Dummy; + UCHAR dir0; + UCHAR dir0_msn; + UCHAR dir0_lsn; + UCHAR dir1 = 0; BOOLEAN ExtendedCPUID = TRUE; ULONG CpuFeatures = 0; @@ -351,10 +433,63 @@ /* Cyrix CPUs */ case CPU_CYRIX: + GetCyrixDevID(&dir0,&dir1); + + /*Cx86_dir0_msb = */ + dir0_msn = dir0 >> 4; /* identifies CPU "family" */ + dir0_lsn = dir0 & 0xf; /* model or clock multiplier */ - /* FIXME: CMPXCGH8B */ + /* common case step number/rev -- exceptions handled below */ + //c->x86_model = (dir1 >> 4) + 1; + //c->x86_mask = dir1 & 0xf; - break; + /* Now cook; the original recipe is by Channing Corn, from Cyrix. + * We do the same thing for each generation: we work out + * the model, multiplier and stepping. Black magic included, + * to make the silicon step/rev numbers match the printed ones. + */ + switch (dir0_msn) + { + case 0: + /* Cx486SLC/DLC/SRx/DRx */ + DPRINT1("Cx486SLC/DLC/SRx/DRx\n"); + break; + case 1: + /* Cx486S/DX/DX2/DX4 */ + DPRINT1("Cx486S/DX/DX2/DX4\n"); + break; + case 2: + /* 5x86 */ + DPRINT1("5x86\n"); + break; + case 3: + /* 6x86/6x86L */ + DPRINT1("6x86/6x86L\n"); + break; + case 4: + /* MediaGX/GXm or Geode GXM/GXLV/GX1 */ + DPRINT1("MediaGX/GXm or Geode GXM/GXLV/GX1\n"); + if ((Reg[0] & 0xFFFF) >= 0x0400) + { + /* set the cpu features flags */ + CpuFeatures = Reg[3]; + } + break; + case 5: + /* 6x86MX/M II */ + DPRINT1("6x86MX/M II\n"); + break; + case 0xF: + /* Cyrix 486 without DEVID registers */ + DPRINT1("Cyrix 486 without DEVID registers\n"); + break; + default: + /* unknown (shouldn't happen, we know everyone ;-) */ + DPRINT1("unknown (shouldn't happen, we know everyone ;-)\n"); + break; + } + + break; /* Transmeta CPUs */ case CPU_TRANSMETA: @@ -729,6 +864,31 @@ break; case CPU_CYRIX: + /*Check if we support CPUID 2 */ + CPUID(0, &Data[0], &Dummy, &Dummy, &Dummy); + if (Data[0] >= 2) + { + CPUID(2, &Data[0], &Data[1], &Data[2], &Data[3]); + if ((Data[0] & 0x000000FF) == 0x00000001) + { + /* The CPUID instruction needs + be executed only once with an + input value of 02h to retrieve + complete information about the + cache and TLB. + */ + } + if ((Data[0] & 0x0000FF00) == 0x00007000) + { + /* TLB is 32 entry, 4-way set associative, and has 4 KB pages.*/ + } + if ((Data[3] & 0x000000FF) == 0x00000080) + { + /* L1 cache is 16 KB, 4-way set associated, and has 16 bytes per line.*/ + KePrefetchNTAGranularity = 16; + } + } + break; case CPU_TRANSMETA: case CPU_CENTAUR: case CPU_RISE: