cpudetect.c
来自「一个微型操作系统源码」· C语言 代码 · 共 283 行
C
283 行
/* * OSV * Copyright (C) 2002 Ciprian DOSOFTEI <rocksoul@mail.com> * All rights reserved. * * http://backster.free.fr/osv * * This file is part of the OSV project. OSV is free software, also known as * "open source"; you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the author at rocksoul@mail.com or +40740649907. * * OSV is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have * received a copy of the GPL along with OSV; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */#include <processor.h>#include <printk.h>#include <debug.h>static int __get_model_name(struct cpuinfo_x86 *c) { uint *v; char *p, *q; if (cpuid_eax(0x80000000) < 0x80000004) return 0; v = (uint *) c->x86_model_id; cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); c->x86_model_id[48] = 0; p = q = &c->x86_model_id[0]; while ( *p == ' ' ) p++; if ( p != q ) { while ( *p ) *q++ = *p++; while ( q <= &c->x86_model_id[48] ) *q++ = '\0'; } return 1;}static void __get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; if (!strcmp(v, "GenuineIntel")) c->x86_vendor = X86_VENDOR_INTEL; else if (!strcmp(v, "AuthenticAMD")) c->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(v, "CyrixInstead")) c->x86_vendor = X86_VENDOR_CYRIX; else if (!strcmp(v, "UMC UMC UMC ")) c->x86_vendor = X86_VENDOR_UMC; else if (!strcmp(v, "CentaurHauls")) c->x86_vendor = X86_VENDOR_CENTAUR; else if (!strcmp(v, "NexGenDriven")) c->x86_vendor = X86_VENDOR_NEXGEN; else if (!strcmp(v, "RiseRiseRise")) c->x86_vendor = X86_VENDOR_RISE; else if (!strcmp(v, "GenuineTMx86") || !strcmp(v, "TransmetaCPU")) c->x86_vendor = X86_VENDOR_TRANSMETA; else c->x86_vendor = X86_VENDOR_UNKNOWN;}struct cpu_model_info { int vendor; int family; char *model_names[16];};static struct cpu_model_info cpu_models[] = { { X86_VENDOR_INTEL, 4, { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 5, { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200", "OverDrive PODP5V83", "Pentium MMX", NULL, NULL, "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, "Pentium III (Cascades)", NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }}, { X86_VENDOR_AMD, 5, { "K5/SSA5", "K5", "K5", "K5", NULL, NULL, "K6", "K6", "K6-2", "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 6, { "Athlon", "Athlon", "Athlon", NULL, "Athlon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_UMC, 4, { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_NEXGEN, 5, { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_RISE, 5, { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},}; static char *__table_lookup_model(struct cpuinfo_x86 *c) { struct cpu_model_info *info = cpu_models; int i; if ( c->x86_model >= 16 ) return NULL; /* Range check */ for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) { if ( info->vendor == c->x86_vendor && info->family == c->x86 ) return info->model_names[c->x86_model]; info++; } return NULL;}static inline int __flag_is_changeable_p(uint flag) { uint f1, f2; asm("pushfl\n\t" "pushfl\n\t" "popl %0\n\t" "movl %0,%1\n\t" "xorl %2,%0\n\t" "pushl %0\n\t" "popfl\n\t" "pushfl\n\t" "popl %0\n\t" "popfl\n\t" : "=&r" (f1), "=&r" (f2) : "ir" (flag)); return ((f1^f2) & flag) != 0;}static int __have_cpuid_p(void) { return __flag_is_changeable_p(X86_EFLAGS_ID);}static int __deep_magic_nexgen_probe(void) { int ret; __asm__ __volatile__ ( " movw $0x5555, %%ax\n" " xorw %%dx,%%dx\n" " movw $2, %%cx\n" " divw %%cx\n" " movl $0, %%eax\n" " jnz 1f\n" " movl $1, %%eax\n" "1:\n" : "=a" (ret) : : "cx", "dx" ); return ret;}static inline int __test_cyrix_52div(void) { unsigned int test; __asm__ __volatile__( "sahf\n\t" "div %b2\n\t" "lahf" : "=a" (test) : "0" (5), "q" (2) : "cc"); return (unsigned char) (test >> 8) == 0x02;}static int id_and_try_enable_cpuid(struct cpuinfo_x86 *c) { if ( __flag_is_changeable_p(X86_EFLAGS_AC) ) c->x86 = 4; else c->x86 = 3; if ( c->x86 == 4 && __test_cyrix_52div() ) { strcpy(c->x86_vendor_id, "CyrixInstead"); c->x86_vendor = X86_VENDOR_CYRIX; } else if ( __deep_magic_nexgen_probe() ) { strcpy(c->x86_vendor_id, "NexGenDriven"); } return __have_cpuid_p(); /* Check to see if CPUID now enabled? */}void identifyCPU(struct cpuinfo_x86 *c) { int junk; uint xlvl, tfms; c->x86_cache_size = -1; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_model_id[0] = '\0'; /* Unset */ memset(&c->x86_capability, 0, sizeof c->x86_capability); if ( !__have_cpuid_p() && !id_and_try_enable_cpuid(c) ) { } else { cpuid(0x00000000, &c->cpuid_level, (int *)&c->x86_vendor_id[0], (int *)&c->x86_vendor_id[8], (int *)&c->x86_vendor_id[4]); __get_cpu_vendor(c); if ( c->cpuid_level >= 0x00000001 ) { cpuid(0x00000001, &tfms, &junk, &junk, &c->x86_capability[0]); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; c->x86_mask = tfms & 15; } else { c->x86 = 4; } xlvl = cpuid_eax(0x80000000); if ( (xlvl & 0xffff0000) == 0x80000000 ) { if ( xlvl >= 0x80000001 ) c->x86_capability[1] = cpuid_edx(0x80000001); if ( xlvl >= 0x80000004 ) __get_model_name(c); /* Default name */ } xlvl = cpuid_eax(0x80860000); if ( (xlvl & 0xffff0000) == 0x80860000 ) { if ( xlvl >= 0x80860001 ) c->x86_capability[2] = cpuid_edx(0x80860001); } } if ( !c->x86_model_id[0] ) { char *p; p = __table_lookup_model(c); if ( p ) strcpy(c->x86_model_id, p); else printk(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); }}static char *cpu_vendor_names[] = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };void displayCPUInfo(struct cpuinfo_x86 *c){ char *vendor = NULL; printk(" %c ", 0xAF); if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *)) vendor = cpu_vendor_names[c->x86_vendor]; else if (c->cpuid_level >= 0) vendor = c->x86_vendor_id; if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) printk("%s ", vendor); if (!c->x86_model_id[0]) printk("%d86", c->x86); else printk("%s", c->x86_model_id); if (c->x86_mask || c->cpuid_level >= 0) printk(" (stepping %x) processor found\n", c->x86_mask); else printk("\n");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?