📄 cpu.c
字号:
{
switch (cpu.model)
{
case 0x1: result = "U5D"; break;
case 0x2: result = "U5S"; break;
} break;
}
default: result = "Unknown";
}
}
if (cpu.manufacturer == idRise)
{
switch (cpu.family)
{
case 0x5:
{
switch (cpu.model)
{
case 0x0: result = "mP6 iDragon (0.25鎚)"; break;
case 0x2: result = "mP6 iDragon (0.18鎚)"; break;
case 0x8: result = "mP6 iDragon II (0.25鎚)"; break;
case 0x9: result = "mP6 iDragon II (0.18鎚)"; break;
} break;
}
default: result = "Unknown";
}
}
if (cpu.manufacturer == idSiS)
{
switch (cpu.family)
{
case 0x5:
{
switch (cpu.model)
{
case 0x0: result = "mP6 iDragon (0.25鎚)"; break;
case 0x2: result = "mP6 iDragon (0.18鎚)"; break;
case 0x8: result = "mP6 iDragon II (0.25鎚)"; break;
case 0x9: result = "mP6 iDragon II (0.18鎚)"; break;
} break;
}
default: result = "Unknown";
}
}
if (cpu.manufacturer == idNSC)
{
switch (cpu.family)
{
case 0x5:
{
switch (cpu.model)
{
case 0x0: result = "mP6 iDragon (0.25鎚)"; break;
case 0x2: result = "mP6 iDragon (0.18鎚)"; break;
case 0x8: result = "mP6 iDragon II (0.25鎚)"; break;
case 0x9: result = "mP6 iDragon II (0.18鎚)"; break;
} break;
}
default: result = "Unknown";
}
}
return result;
}
static int is_486(void)
{
int result;
asm (
"pushf ;" /* save EFLAGS */
"popl %%eax ;" /* get EFLAGS */
"movl %%eax, %%ecx ;" /* temp storage EFLAGS */
"xorl $0x40000, %%eax ;" /* change AC bit in EFLAGS */
"pushl %%eax ;" /* put new EFLAGS value on stack */
"popf ;" /* replace current EFLAGS value */
"pushf ;" /* get EFLAGS */
"popl %%eax ;" /* save new EFLAGS in EAX */
"cmpl %%ecx, %%eax ;" /* compare temp and new EFLAGS */
"movl $0,%%eax ;"
"jz 0f ;"
"incl %%eax ;" /* 80486 present */
"0:"
"pushl %%ecx ;" /* get original EFLAGS */
"popf ;" /* restore EFLAGS */
: "=a" (result)
:
: "ecx" );
return result;
}
static int is_386DX(void) /* return TRUE for 386DX, and FALSE for 386SX */
{
int result;
asm (
"movl %%cr0,%%edx ;" /* Get CR0 */
"pushl %%edx ;" /* save CR0 */
"andb $0xEF, %%dl ;" /* clear bit4 */
"movl %%edx, %%cr0 ;" /* set CR0 */
"movl %%cr0, %%edx ;" /* and read CR0 */
"andb $0x10, %%dl ;" /* bit4 forced high? */
"popl %%edx ;" /* restore reg w/ CR0 */
"movl %%edx, %%cr0 ;" /* restore CR0 */
"movl $1, %%eax ;" /* TRUE, 386DX */
"jz 0f ;"
"movl $0, %%eax ;" /* FALSE, 386SX */
"0:"
: "=a" (result)
:
: "%edx", "memory"
);
return result;
}
static int is_486DX(void) /* return TRUE for 486DX, and FALSE for 486SX */
{
dword memory_location = 0x00;
__asm__ (
"fninit ;"
"fnstsw %0 ;"
: "=g" (memory_location)
);
return (memory_location == 0x37F) ? 1 : 0;
}
static int is_fpu(void)
{
int result;
asm (
"fninit ;"
"movl $0x5a5a, %%eax ;"
"fnstsw %%eax ;"
"cmpl $0, %%eax ;"
"jne 0f ;"
"movl $1, %%eax ;"
"jmp 1f ;"
"0:"
"movl $0, %%eax ;"
"1:"
: "=a" (result)
:
: "memory" );
return result;
}
static int is_cyrix(void)
{
int result;
asm (
"xorw %%ax, %%ax ;" /* clear eax */
"sahf ;" /* clear flags, bit 1 is always 1 in flags */
"movw $5, %%ax ;"
"movw $2, %%bx ;"
"div %%bl ;" /* do an operation that does not change flags */
"lahf ;" /* get flags */
"cmpb $2, %%ah ;" /* check for change in flags */
"movl $0, %%eax ;" /* FALSE NON-Cyrix CPU */
"jne 0f ;" /* flags changed not Cyrix */
"incl %%eax ;" /* TRUE Cyrix CPU */
"0:"
: "=a" (result)
:
: "ebx"
);
return result;
}
static void cx_w(char index, char value)
{
int ints_were_enabled = interrupts_disable();
outportb(0x22, index); /* tell CPU which config. register */
outportb(0x23, value); /* write to CPU config. register */
if (ints_were_enabled)
interrupts_enable();
}
static char cx_r(char index)
{
char value;
int ints_were_enabled = interrupts_disable();
outportb(0x22, index); /* tell CPU which config. register */
value = inportb(0x23); /* read CPU config, register */
if (ints_were_enabled)
interrupts_enable();
return value;
}
#define UNKNOWN 0xff
#define Cx486_pr 0xfd /* ID Register not supported, software created */
#define Cx486S_a 0xfe /* ID Register not supported, software created */
#define CR2_MASK 0x4 /* LockNW */
#define CR3_MASK 0x80 /* Resereved bit 7 */
static char cyrix_type(void)
{
char orgc2, newc2, orgc3, newc3;
int cr2_rw=0, cr3_rw=0, type;
int ints_were_enabled = interrupts_disable();
type = UNKNOWN;
/* Test Cyrix c2 register read/writable */
orgc2 = cx_r (0xc2); /* get current c2 value */
newc2 = orgc2 ^ CR2_MASK; /* toggle test bit */
cx_w (0xc2, newc2); /* write test value to c2 */
cx_r (0xc0); /* dummy read to change bus */
if (cx_r (0xc2) != orgc2) /* did test bit toggle */
cr2_rw = 1; /* yes bit changed */
cx_w (0xc2, orgc2); /* return c2 to original value */
/* end c2 read writeable test */
/* Test Cyrix c3 register read/writable */
orgc3 = cx_r (0xc3); /* get current c3 value */
newc3 = orgc3 ^ CR3_MASK; /* toggle test bit */
cx_w (0xc3, newc3); /* write test value to c3 */
cx_r (0xc0); /* dummy read to change bus */
if (cx_r (0xc3) != orgc3) /* did test bit change */
cr3_rw = 1; /* yes it did */
cx_w (0xc3, orgc3); /* return c3 to original value */
/* end c3 read writeable test */
if ((cr2_rw && cr3_rw) || (!cr2_rw && cr3_rw)) /*DEV ID register ok */
{
/* <<<<<<< READ DEVICE ID Reg >>>>>>>> */
type = cx_r (0xfe); /* lower byte gets IDIR0 */
}
else if (cr2_rw && !cr3_rw) /* Cx486S A step */
{
type = Cx486S_a; /* lower byte */
}
else if (!cr2_rw && !cr3_rw) /* Pre ID Regs. Cx486SLC or DLC */
{
type = Cx486_pr; /* lower byte */
}
/* This could be broken down more, but is it needed? */
if (type < 0x30 || type > 0xfc)
{
cpu.family = 4; /* 486 class-including 5x86 */
cpu.model = 0xFF; /* Unknown */
}
else if (type < 0x50)
{
cpu.family = 5; /* Pentium class-6x86 and Media GX */
cpu.model = 0xFF; /* Unknown */
}
else
{
cpu.family = 6; /* Pentium || class- 6x86MX */
cpu.model = 0xFF; /* Unknown */
cpu.flags |= cpu_mmx;
}
if (ints_were_enabled)
interrupts_enable();
return type;
}
void check_cache(void)
{
static unsigned proc_cache_l1[4] = { 0, 0, 0, 0 };
static unsigned proc_cache_l2[4] = { 0, 0, 0, 0 };
// query L1 cache information
get_cpuid(0x80000005, proc_cache_l1[0], proc_cache_l1[1],
proc_cache_l1[2], proc_cache_l1[3]);
// query L2 cache information
get_cpuid(0x80000006, proc_cache_l2[0], proc_cache_l2[1],
proc_cache_l2[2], proc_cache_l2[3]);
if (cpu.manufacturer == idAMD)
{
// K5/K6 supports a restricted range
cpu.cache.CPU_L1_DTLB_ASSOC = (proc_cache_l1[1] >> 24) & 0xff;
cpu.cache.CPU_L1_DTLB_ENTRIES = (proc_cache_l1[1] >> 16) & 0xff;
cpu.cache.CPU_L1_ITLB_ASSOC = (proc_cache_l1[1] >> 8) & 0xff;
cpu.cache.CPU_L1_ITLB_ENTRIES = (proc_cache_l1[1] >> 0) & 0xff;
cpu.cache.CPU_L1_DCACHE_SIZE = (proc_cache_l1[2] >> 24) & 0xff;
cpu.cache.CPU_L1_DCACHE_ASSOC = (proc_cache_l1[2] >> 16) & 0xff;
cpu.cache.CPU_L1_DCACHE_LINES = (proc_cache_l1[2] >> 8) & 0xff;
cpu.cache.CPU_L1_DCACHE_LSIZE = (proc_cache_l1[2] >> 0) & 0xff;
cpu.cache.CPU_L1_ICACHE_SIZE = (proc_cache_l1[3] >> 24) & 0xff;
cpu.cache.CPU_L1_ICACHE_ASSOC = (proc_cache_l1[3] >> 16) & 0xff;
cpu.cache.CPU_L1_ICACHE_LINES = (proc_cache_l1[3] >> 8) & 0xff;
cpu.cache.CPU_L1_ICACHE_LSIZE = (proc_cache_l1[3] >> 0) & 0xff;
cpu.cache.CPU_L2_CACHE_SIZE = (proc_cache_l2[2] >> 16) & 0xffff;
cpu.cache.CPU_L2_CACHE_ASSOC = (proc_cache_l2[2] >> 12) & 0x0f;
cpu.cache.CPU_L2_CACHE_LINES = (proc_cache_l2[2] >> 8) & 0x0f;
cpu.cache.CPU_L2_CACHE_LSIZE = (proc_cache_l2[2] >> 0) & 0xff;
if (cpu.family == 0x06) // AMD ATHLON
{
// Athlon supports these additional parameters
cpu.cache.CPU_L1_EDTLB_ASSOC = (proc_cache_l1[0] >> 24) & 0xff;
cpu.cache.CPU_L1_EDTLB_ENTRIES = (proc_cache_l1[0] >> 16) & 0xff;
cpu.cache.CPU_L1_EITLB_ASSOC = (proc_cache_l1[0] >> 8) & 0xff;
cpu.cache.CPU_L1_EITLB_ENTRIES = (proc_cache_l1[0] >> 0) & 0xff;
cpu.cache.CPU_L2_DTLB_ASSOC = (proc_cache_l2[0] >> 28) & 0x0f;
cpu.cache.CPU_L2_DTLB_ENTRIES = (proc_cache_l2[0] >> 16) & 0xfff;
cpu.cache.CPU_L2_UTLB_ASSOC = (proc_cache_l2[0] >> 12) & 0x0f;
cpu.cache.CPU_L2_UTLB_ENTRIES = (proc_cache_l2[0] >> 0) & 0xfff;
cpu.cache.CPU_L2_EDTLB_ASSOC = (proc_cache_l2[1] >> 28) & 0x0f;
cpu.cache.CPU_L2_EDTLB_ENTRIES = (proc_cache_l2[1] >> 16) & 0xfff;
cpu.cache.CPU_L2_EUTLB_ASSOC = (proc_cache_l2[1] >> 12) & 0x0f;
cpu.cache.CPU_L2_EUTLB_ENTRIES = (proc_cache_l2[1] >> 0) & 0xfff;
}
}
}
void check_cpu(void)
{
unsigned cpuid_levels, reg_eax, reg_ebx, reg_ecx, reg_edx, tmp;
unsigned char b;
if (is_cpuid_supported())
{
cpu.flags |= cpu_cpuid;
get_cpuid(0, cpuid_levels, reg_ebx, reg_ecx, reg_edx);
cpu.levels = cpuid_levels;
cpu.vendor[ 0] = LOBYTE(LOWORD(reg_ebx));
cpu.vendor[ 1] = HIBYTE(LOWORD(reg_ebx));
cpu.vendor[ 2] = LOBYTE(HIWORD(reg_ebx));
cpu.vendor[ 3] = HIBYTE(HIWORD(reg_ebx));
cpu.vendor[ 4] = LOBYTE(LOWORD(reg_edx));
cpu.vendor[ 5] = HIBYTE(LOWORD(reg_edx));
cpu.vendor[ 6] = LOBYTE(HIWORD(reg_edx));
cpu.vendor[ 7] = HIBYTE(HIWORD(reg_edx));
cpu.vendor[ 8] = LOBYTE(LOWORD(reg_ecx));
cpu.vendor[ 9] = HIBYTE(LOWORD(reg_ecx));
cpu.vendor[10] = LOBYTE(HIWORD(reg_ecx));
cpu.vendor[11] = HIBYTE(HIWORD(reg_ecx));
cpu.vendor[12] = '\0';
cpu.manufacturer = 0xFF;
for (tmp=0; tmp<9; tmp++)
{
if (strcmp(cpu.vendor, manufacturers[tmp]) == 0)
{
cpu.manufacturer = tmp;
break;
}
}
if (cpuid_levels > 0)
{
get_cpuid (1, reg_eax, tmp, tmp, reg_edx);
cpu.family = (reg_eax & CPUID_FAM) >> 8;
cpu.model = (reg_eax & CPUID_MOD) >> 4;
cpu.stepping = (reg_eax & CPUID_STEP);
cpu.ext_family = (reg_eax & CPUID_XFAM);
cpu.features = reg_edx;
checkname(cpu.name);
// fill extended info structure for intel's
fillinfo();
check_cache();
if (cpu.features & HAS_FPU) cpu.flags |= cpu_fpu;
if (cpu.features & HAS_MMX) cpu.flags |= cpu_mmx;
if (cpu.features & HAS_SSE) cpu.flags |= cpu_isse;
}
}
else
{
cpu.vendor[0] = 'U';
cpu.vendor[1] = 'n';
cpu.vendor[2] = 'k';
cpu.vendor[3] = 'n';
cpu.vendor[4] = 'o';
cpu.vendor[5] = 'w';
cpu.vendor[6] = 'n';
cpu.vendor[7] = '\0';
if (is_fpu())
cpu.flags |= cpu_fpu;
if (!is_486())
{
if (is_386DX())
{
cpu.main_family = 3; // 386
cpu.model = 0; // DX
}
else // It is a 386SX
{
cpu.main_family = 3; // 386
cpu.model = 1; // SX
}
}
else
{
if (is_cyrix())
{
cpu.manufacturer = idCyrix;
b = cyrix_type();
strcpy(cpu.name, cyrix_name[b]);
}
else
if (is_486DX())
{
cpu.main_family = 4; // 486
cpu.model = 0; // DX
}
else
{
cpu.main_family = 4; // 486
cpu.model = 1; // SX
}
}
}
}
void cpu_init(void)
{
dprintf("\ncpu: Checking CPU...");
strcpy(cpu.name, "Unknown Processor");
check_cpu();
dprintf("OK\n");
if (cpu.flags & cpu_cpuid)
{
dprintf("cpu: CPUID supported (");
dprintf(cpu.vendor);
if (cpu.levels)
dprintf(", %ld levels", cpu.levels);
dprintf("), %02X/%02X/%02X\n", cpu.family, cpu.model, cpu.stepping);
dprintf("cpu: Identified as %s %s\n", display[cpu.manufacturer], cpu.name);
dprintf("cpu: L1 D Cache: %ldKB, L1 I Cache: %ldKB", cpu.cache.CPU_L1_DCACHE_SIZE,
cpu.cache.CPU_L1_ICACHE_SIZE);
if (cpu.cache.CPU_L2_CACHE_SIZE)
dprintf(", L2 Cache: %ldKB", cpu.cache.CPU_L2_CACHE_SIZE);
cpu.clockrate = get_clockrate(cpu.features & HAS_TSC);
dprintf("\ncpu: Speed CPU: %ldMHz\n", cpu.clockrate);
check_popad();
check_pentium_f00f();
}
else
{
dprintf("cpu: %d86 ", cpu.main_family);
if (cpu.model != 0xFF)
dprintf("%s", (cpu.model == 0x00) ? "DX " : "SX ");
dprintf("detected\n");
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -