📄 cpu.c
字号:
/*
* CPU detection (CPUID, possible bugs etc.) *
* v0.1: TDS (20.04.2001) *
* - detection of all known processors *
* - L1+L2 Cache *
* - bug checking (PopAd, F0 0F) *
* - special cyrix detection *
* v0.2: TDS (30.03.2004) *
* - small bug fixes *
* - NucleusKL compatible *
*/
#include <datatypes.h>
#include <interrupts.h>
#include <stdio.h>
#include <support.h>
#include <string.h>
#include <drivers/cpu/cpu.h>
#include <drivers/cpu/cpu_mhz.h>
#include <drivers/cpu/bugs.h>
struct cpu_struct cpu;
static char * manufacturers[] =
{
"AuthenticAMD",
"CentaurHauls",
"CyrixInstead",
"GenuineIntel",
"NexGenDriven",
"UMC UMC UMC ",
"RiseRiseRise",
"GenuineTMx86",
"SiS SiS SiS ",
"Geode by NSC"
};
static char * display[] =
{
"AMD",
"Centaur/IDT",
"Cyrix",
"Intel",
"NexGen",
"UMC",
"Rise",
"Transmeta",
"SiS",
"National Semiconductor"
};
//AMD
static char *amd_0x04[16] =
{
NULL, "80486 DX", NULL, "80486 DX2-WT", NULL, NULL, NULL,
"80486 DX2, WB", "80486DX4-WT / 5x86-WT", "80486DX4-WB / 5x86-WB",
"Elan SC400", NULL, NULL, NULL, "Am5x86 WT", "Am5x86 WB"
};
static char *amd_0x05[16]=
{
"SSA5 (PR75, PR90, PR100)", "5k86 (PR120, PR133)",
"5k86 (PR166)", "5k86 (PR200)", NULL, NULL,
"K6 (0.30鎚)", "K6 (0.25鎚)", "K6-II", "K6-III",
NULL, NULL, "K6-II+ (0.18鎚)", "K6-III+ (0.18鎚)", NULL, NULL
};
static char *amd_0x06[16]=
{
NULL, "K7 (0.25鎚)", "Athlon (0.18鎚)", "Duron (Spitfire Core)",
"Athlon (0.18鎚, Thunderbird)", NULL, "Athlon (Palomino)",
"Duron (Morgan)", "Athlon XP", NULL, "Athlon (Barton)",
NULL, NULL, NULL, NULL, NULL
};
static char *amd_ext_0x00[16]=
{
NULL, NULL, NULL, NULL, "Athlon 64 (0.13鎚 754)", "Athlon 64 FX or Opteron (0.13鎚)",
NULL, "Athlon 64 (0.13鎚 939)", "Athlon 64 (0.13鎚 754)", NULL, NULL,
"Athlon 64 (0.13鎚 939)", "Athlon 64 (0.13鎚 754)", NULL, NULL,
"Athlon 64 (0.13鎚 939)"
};
static struct AMD_0x06_ext
{
char model, stepping;
char name[40];
} amd_0x06_ext[14] =
{
{1, 1, "Rev C1"},
{1, 2, "Rev C2"},
{2, 1, "Rev A1"},
{2, 2, "Rev A2"},
{3, 0, "Rev A0"},
{3, 1, "Rev A2"},
{4, 0, "Rev A1"},
{4, 1, "Rev A2"},
{4, 2, "Rev A4-A8"},
{4, 3, "Rev A9"},
{6, 0, "Rev A0-A1"},
{6, 1, "Rev A2"},
{7, 0, "Rev A0"},
{7, 1, "Rev A1"}
};
// Intel
static char *intel_0x03[16]=
{
"i80386DX", NULL, "i80386SX", NULL, "i80386SL", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static char *intel_0x04[16]=
{
"i80486DX-25/33", "i80486DX-50", "i80486SX", "i80486DX2",
"i80486SL", "i80486SX2", NULL, "i80486DX2 WB",
"i80486DX4", "i80486DX4 WB", NULL, NULL, NULL, NULL, NULL, NULL
};
static char *intel_0x05[16]=
{
"P5 60/66 A-step", "P5 60/66", "P54C 75-200", "P24T Overdrive PODP5V83",
"P55C MMX", NULL, NULL, "P54C Mobile Pentium 75-200",
"P55C (0.25鎚) Mobile Pentium MMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static char *intel_0x06[16]=
{
"P6 PentiumPro A-Step", "P6 PentiumPro", NULL, "PII (0.28鎚) Klamath", NULL,
"PII (0.25鎚) Deschutes", "PII (on-die L2 Cache) Mobile Pentium",
"PIII (0.25鎚) Katmai", "PIII (0.18鎚) (256KB on-die L2 cache) Coppermine",
"PIII (0.13鎚) (512KB or 1MB on-die L2 cache) Coppermine",
"PIII (0.18鎚) (1MB or 2MB on-die L2 cache) Cascades",
"PIII (0.13鎚) (256KB or 512KB on-die L2 cache)", NULL, NULL, NULL, NULL
};
static char *intel_ext_0x00[16]=
{
"P4 (0.18鎚)", "P4 (0.18鎚)", "P4 (0.13鎚)", "P4 (0.09鎚)",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
//Cyrix
static char *cyrix_name[128]=
{
/***********************/
/** 486 DLC and SLC **/
/***********************/
"Cx486_SLC", "Cx486_DLC", "Cx486_SLC2", "Cx486_DLC2",
"Cx486_SRx (Retail Upgrade Cx486SLC)",
"Cx486_DRx (Retail Upgrade Cx486DLC)",
"Cx486_SRx2 (Retail Upgrade 2x Cx486SLC)",
"Cx486_DRx2 (Retail Upgrade 2x Cx486DLC)",
"", "", "", "", "", "", "",
/***********************/
/* 486 S, DX, DX2, DX4 */
/***********************/
"Cx486S B step", "Cx486S2 B step", "Cx486Se B step",
"Cx486S2e B step", "", "", "", "", "", "",
"Cx486DX", "Cx486DX2", "", "", "", "Cx486DX4",
/***********************/
/*** 5x86 ***/
/***********************/
"", "", "", "", "", "", "", "",
"5x86_1xs (5x86 1x Core/Bus Clock)",
"5x86_2xs (5x86 2x Core/Bus Clock)",
"5x86_1xp (5x86 1x Core/Bus Clock)",
"5x86_2xp (5x86 2x Core/Bus Clock)",
"5x86_4xs (5x86 4x Core/Bus Clock)",
"5x86_3xs (5x86 3x Core/Bus Clock)",
"5x86_4xp (5x86 4x Core/Bus Clock)",
"5x86_3xp (5x86 3x Core/Bus Clock)",
/***********************/
/*** 6x86 ***/
/***********************/
"6x86_1xs (6x86 1x Core/Bus Clock)",
"6x86_2xs (6x86 2x Core/Bus Clock)",
"6x86_1xp (6x86 1x Core/Bus Clock)",
"6x86_2xp (6x86 2x Core/Bus Clock)",
"6x86_4xs (6x86 4x Core/Bus Clock)",
"6x86_3xs (6x86 3x Core/Bus Clock)",
"6x86_4xp (6x86 4x Core/Bus Clock)",
"6x86_3xp (6x86 3x Core/Bus Clock)",
"", "", "", "", "", "", "", "",
/***********************/
/*** Gx86 ***/
/***********************/
"", "", "", "",
"Gx86_4xs (Gx86 4x Core/Bus Clock)",
"Gx86_3xs (Gx86 3x Core/Bus Clock)",
"Gx86_4xp (Gx86 4x Core/Bus Clock)",
"Gx86_3xp (Gx86 3x Core/Bus Clock)",
"", "", "", "", "", "", "", "", "",
/***********************/
/*** m2 ***/ // Now called 6x86MX
/***********************/
// m2s_base 0x50 // m2 s base 1x
"m2_1xs (m2 1x Core/Bus Clock)",
"m2_2xs (m2 2x Core/Bus Clock)",
"m2_2p5xs (m2 2.5x Core/Bus Clock)",
"m2_3xs (m2 3x Core/Bus Clock)",
"m2_3p5xs (m2 3.5x Core/Bus Clock)",
"m2_4xs (m2 4x Core/Bus Clock)",
"m2_4p5xs (m2 4.5x Core/Bus Clock)",
"m2_5xs (m2 5x Core/Bus Clock)",
// m2p_base 0x58 // m2 p base 1x
"m2_1xp (m2 1x Core/Bus Clock)",
"m2_2xp (m2 2x Core/Bus Clock)",
"m2_2p5xp (m2 2.5x Core/Bus Clock)",
"m2_3xp (m2 3x Core/Bus Clock)",
"m2_3p5xp (m2 3.5x Core/Bus Clock)",
"m2_4xp (m2 4x Core/Bus Clock)",
"m2_4p5xp (m2 4.5x Core/Bus Clock)",
"m2_5xp (m2 5x Core/Bus Clock)"
};
int is_cpuid_supported(void)
{
int result;
asm(
"pushfl\n\r" /* get extended flags */
"popl %%eax\n\r"
"movl %%eax, %%ebx\n\r" /* save current flags */
"xorl $0x200000, %%eax\n\r" /* toggle bit 21 */
"pushl %%eax\n\r" /* put new flags on stack */
"popfl\n\r" /* flags updated now in flags */
"pushfl\n\r" /* get extended flags */
"popl %%eax\n\r"
"xorl %%ebx, %%eax\n\r" /* if bit 21 r/w then supports cpuid */
"mov $0,%%eax\n\r"
"jz 0f\n\r"
"incl %%eax\n\r"
"0:\n\r"
: "=a" (result)
:
: "ebx"
);
return result;
}
#define get_cpuid(in, a, b, c, d) asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
void get_serial_number(unsigned long *a, unsigned long *b, unsigned long *c)
{
unsigned long tmp;
get_cpuid(1, a, tmp, tmp, tmp);
get_cpuid(3, tmp, tmp, b, c);
}
unsigned long moreinfo[4];
char cyrix_type(void);
void fillinfo(void)
{
get_cpuid(2, moreinfo[0], moreinfo[4], moreinfo[8], moreinfo[12]);
}
static char *checkname(char *result)
{
unsigned char x;
unsigned long reg_eax, reg_ebx, reg_ecx, reg_edx;
if (cpu.manufacturer == idAMD)
{
// enable write-back mode
switch (cpu.family)
{
case 0x04: strcpy(result, amd_0x04[cpu.model]); break;
case 0x05: if (cpu.stepping > 7)
result = "K6-II (CXT core)";
else
strcpy(result, amd_0x05[cpu.model]); break;
case 0x06: if (cpu.model == 0x06 && cpu.stepping == 0x02)
{
if (cpu.cache.CPU_L2_CACHE_SIZE < 256)
{
strcpy(result, "Mobile Duron");
}
else
{
get_cpuid (0x80000001, reg_eax, reg_ebx, reg_ecx, reg_edx);
if ((reg_edx & (1<<19)) == 0)
{
strcpy(result, "Athlon XP");
}
else
{
strcpy(result, "Athlon MP");
}
}
}
else
if (cpu.model == 0x08)
{
if (cpu.cache.CPU_L2_CACHE_SIZE < 256)
{
strcpy(result, "Duron");
}
else
{
get_cpuid (0x80000001, reg_eax, reg_ebx, reg_ecx, reg_edx);
if ((reg_edx & (1<<19)) == 0)
{
strcpy(result, "Athlon XP (Thoroughbred)");
}
else
{
strcpy(result, "Athlon MP (Thoroughbred)");
}
}
}
else
strcpy(result, amd_0x06[cpu.model]);
break;
case 0x0F: switch(cpu.ext_family)
{
case 0x00: strcpy(result, amd_ext_0x00[cpu.model]); break;
default: result = "K8";
} break;
default: result = "Unknown";
}
}
if (cpu.manufacturer == idIntel)
{
if (moreinfo[0] == 0x01)
{
for (x=1;x<16;x++)
{
switch (moreinfo[x])
{
case 0x40: result = "P2 Celeron"; break;
case 0x41: result = "P2 Celeron A"; break;
case 0x42: result = "PPro"; break;
case 0x43: result = "P2"; break;
case 0x44: result = "P2 Xeon (1MB L2 cache)"; break;
case 0x45: result = "P2 Xeon (2MB L2 cache XEON, Xena?)"; break;
}
}
if (cpu.flags & cpu_isse)
{
if (strcmp(result, "P2")) result = "P3";
if (strcmp(result, "P2 Celeron A")) result = "P3 Celeron A";
if (strcmp(result, "Xeon")) result = "P3 Xeon";
}
}
switch (cpu.family)
{
case 0x03: strcpy(result, intel_0x03[cpu.model]); break;
case 0x04: strcpy(result, intel_0x04[cpu.model]); break;
case 0x05: strcpy(result, intel_0x05[cpu.model]); break;
case 0x06:
if (cpu.model == 0x05)
{
if( cpu.cache.CPU_L2_CACHE_SIZE == 512) strcpy(result, intel_0x06[cpu.model]);
if( cpu.cache.CPU_L2_CACHE_SIZE < 512) strcpy(result, "Celeron");
if( cpu.cache.CPU_L2_CACHE_SIZE > 512) strcpy(result, "Pentium II Xeon");
}
else
strcpy(result, intel_0x06[cpu.model]);
break;
case 0x07: result = "Itanium (IA-64)";
case 0x0F:
switch(cpu.ext_family)
{
case 0x00: strcpy(result, intel_ext_0x00[cpu.model]); break;
case 0x01: result = "Itanium 2"; break;
default: result = "K8";
} break;
default: result = "Unknown";
}
}
if (cpu.manufacturer == idIDT)
{
switch (cpu.family)
{
case 0x05:
{
switch (cpu.model)
{
case 0x4: result = "Winchip C6"; break;
case 0x8: switch (cpu.stepping)
{
default: result = "Winchip C2"; break;
case 7: case 8: case 9: result = "Winchip 2A"; break;
case 10: case 11: case 12: case 13:
case 14: case 15: result = "Winchip 2B"; break;
}
break;
case 0x9: result = "Winchip C3"; break;
} break;
}
/* Family 6 is when VIA bought out Cyrix & IDT
* This is the CyrixIII family. */
case 0x06:
{
switch (cpu.model)
{
case 0x06: result = "VIA Cyrix III"; break;
case 0x07: result = "VIA C3";
if (cpu.stepping > 0x07)
result = "\"Ezra\"";
break;
}
}
break;
default: result = "Unknown";
}
}
if (cpu.manufacturer == idCyrix)
{
switch (cpu.family)
{
case 0x4:
{
switch (cpu.model)
{
case 0x4: result = "GX"; break;
case 0x5: result = "MediaGX"; break;
case 0x9: result = "5x86"; break;
} break;
}
case 0x5:
{
switch (cpu.model)
{
case 0x2: result = "6x86MX"; break;
case 0x4: result = "GXm"; break;
} break;
}
case 0x6:
{
switch (cpu.model)
{
case 0x0: result = "6x86/MX"; break;
case 0x2: result = "MII"; break;
} break;
}
default: x = cyrix_type(); strcpy(result, cyrix_name[x]);
}
}
if (cpu.manufacturer == idNexGen)
{
switch (cpu.family)
{
case 0x5:
{
switch (cpu.model)
{
case 0x0: result = "Nx586 / Nx586 FPU"; break;
}
} break;
default: result = "Unknown";
}
}
if (cpu.manufacturer == idUMC)
{
switch (cpu.family)
{
case 0x4:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -