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 + -
显示快捷键?