2011-12-11 03:34:10 +04:00
/* vim: tabstop=4 shiftwidth=4 noexpandtab
*
2011-03-27 06:36:49 +04:00
* Copyright ( c ) 2006 - 2007 - http : //brynet.biz.tm - <brynet@gmail.com>
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED WARRANTIES ,
* INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ;
* OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR
* OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
*
*/
/* You need to include a file with fairly(ish) compliant printf prototype, Decimal and String support like %s and %d and this is truely all you need! */
2012-02-20 05:39:18 +04:00
# include <stdio.h> /* for printf(); */
2011-03-27 06:36:49 +04:00
2012-02-20 05:39:18 +04:00
# define asm __asm__
2011-03-27 06:36:49 +04:00
/* Required Declarations */
int do_intel ( void ) ;
int do_amd ( void ) ;
void printregs ( int eax , int ebx , int ecx , int edx ) ;
2016-12-03 04:56:16 +03:00
# if defined(__PIC__)
# define cpuid(in, a, b, c, d) asm("xchg{l} {%%}ebx, %k1 \n cpuid \n xchg{l} {%%}ebx, %k1" \
: " =a " ( a ) , " =&r " ( b ) , " =c " ( c ) , " =d " ( d ) : " 0 " ( in ) )
# else
2011-10-31 10:17:26 +04:00
# define cpuid(in, a, b, c, d) asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
2016-12-03 04:56:16 +03:00
# endif
2011-03-27 06:36:49 +04:00
/* Simply call this function detect_cpu(); */
2012-02-20 05:39:18 +04:00
int main ( void ) { /* or main() if your trying to port this as an independant application */
2011-03-27 06:36:49 +04:00
unsigned long ebx , unused ;
cpuid ( 0 , unused , ebx , unused , unused ) ;
switch ( ebx ) {
case 0x756e6547 : /* Intel Magic Code */
do_intel ( ) ;
break ;
case 0x68747541 : /* AMD Magic Code */
do_amd ( ) ;
break ;
default :
2012-02-20 05:39:18 +04:00
printf ( " Unknown x86 CPU Detected \n " ) ;
2011-03-27 06:36:49 +04:00
break ;
}
return 0 ;
}
/* Intel Specific brand list */
char * Intel [ ] = {
" Brand ID Not Supported. " ,
" Intel(R) Celeron(R) processor " ,
" Intel(R) Pentium(R) III processor " ,
" Intel(R) Pentium(R) III Xeon(R) processor " ,
" Intel(R) Pentium(R) III processor " ,
" Reserved " ,
" Mobile Intel(R) Pentium(R) III processor-M " ,
" Mobile Intel(R) Celeron(R) processor " ,
" Intel(R) Pentium(R) 4 processor " ,
" Intel(R) Pentium(R) 4 processor " ,
" Intel(R) Celeron(R) processor " ,
" Intel(R) Xeon(R) Processor " ,
" Intel(R) Xeon(R) processor MP " ,
" Reserved " ,
" Mobile Intel(R) Pentium(R) 4 processor-M " ,
" Mobile Intel(R) Pentium(R) Celeron(R) processor " ,
" Reserved " ,
" Mobile Genuine Intel(R) processor " ,
" Intel(R) Celeron(R) M processor " ,
" Mobile Intel(R) Celeron(R) processor " ,
" Intel(R) Celeron(R) processor " ,
" Mobile Geniune Intel(R) processor " ,
" Intel(R) Pentium(R) M processor " ,
" Mobile Intel(R) Celeron(R) processor "
} ;
/* This table is for those brand strings that have two values depending on the processor signature. It should have the same number of entries as the above table. */
char * Intel_Other [ ] = {
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Intel(R) Celeron(R) processor " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Intel(R) Xeon(R) processor MP " ,
" Reserved " ,
" Reserved " ,
" Intel(R) Xeon(R) processor " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved " ,
" Reserved "
} ;
/* Intel-specific information */
int do_intel ( void ) {
2012-02-20 05:39:18 +04:00
printf ( " Intel Specific Features: \n " ) ;
2011-03-27 06:36:49 +04:00
unsigned long eax , ebx , ecx , edx , max_eax , signature , unused ;
int model , family , type , brand , stepping , reserved ;
int extended_family = - 1 ;
cpuid ( 1 , eax , ebx , unused , unused ) ;
model = ( eax > > 4 ) & 0xf ;
family = ( eax > > 8 ) & 0xf ;
type = ( eax > > 12 ) & 0x3 ;
brand = ebx & 0xff ;
stepping = eax & 0xf ;
reserved = eax > > 14 ;
signature = eax ;
2012-02-20 05:39:18 +04:00
printf ( " Type %d - " , type ) ;
2011-03-27 06:36:49 +04:00
switch ( type ) {
case 0 :
2012-02-20 05:39:18 +04:00
printf ( " Original OEM " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 1 :
2012-02-20 05:39:18 +04:00
printf ( " Overdrive " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 2 :
2012-02-20 05:39:18 +04:00
printf ( " Dual-capable " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " Reserved " ) ;
2011-03-27 06:36:49 +04:00
break ;
}
2012-02-20 05:39:18 +04:00
printf ( " \n " ) ;
printf ( " Family %d - " , family ) ;
2011-03-27 06:36:49 +04:00
switch ( family ) {
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " i386 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 4 :
2012-02-20 05:39:18 +04:00
printf ( " i486 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 5 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 6 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium Pro " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 15 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium 4 " ) ;
2011-03-27 06:36:49 +04:00
}
2012-02-20 05:39:18 +04:00
printf ( " \n " ) ;
2011-03-27 06:36:49 +04:00
if ( family = = 15 ) {
extended_family = ( eax > > 20 ) & 0xff ;
2012-02-20 05:39:18 +04:00
printf ( " Extended family %d \n " , extended_family ) ;
2011-03-27 06:36:49 +04:00
}
2012-02-20 05:39:18 +04:00
printf ( " Model %d - " , model ) ;
2011-03-27 06:36:49 +04:00
switch ( family ) {
case 3 :
break ;
case 4 :
switch ( model ) {
case 0 :
case 1 :
2012-02-20 05:39:18 +04:00
printf ( " DX " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 2 :
2012-02-20 05:39:18 +04:00
printf ( " SX " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " 487/DX2 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 4 :
2012-02-20 05:39:18 +04:00
printf ( " SL " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 5 :
2012-02-20 05:39:18 +04:00
printf ( " SX2 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 7 :
2012-02-20 05:39:18 +04:00
printf ( " Write-back enhanced DX2 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 8 :
2012-02-20 05:39:18 +04:00
printf ( " DX4 " ) ;
2011-03-27 06:36:49 +04:00
break ;
}
break ;
case 5 :
switch ( model ) {
case 1 :
2012-02-20 05:39:18 +04:00
printf ( " 60/66 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 2 :
2012-02-20 05:39:18 +04:00
printf ( " 75-200 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " for 486 system " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 4 :
2012-02-20 05:39:18 +04:00
printf ( " MMX " ) ;
2011-03-27 06:36:49 +04:00
break ;
}
break ;
case 6 :
switch ( model ) {
case 1 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium Pro " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium II Model 3 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 5 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium II Model 5/Xeon/Celeron " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 6 :
2012-02-20 05:39:18 +04:00
printf ( " Celeron " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 7 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium III/Pentium III Xeon - external L2 cache " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 8 :
2012-02-20 05:39:18 +04:00
printf ( " Pentium III/Pentium III Xeon - internal L2 cache " ) ;
2011-03-27 06:36:49 +04:00
break ;
}
break ;
case 15 :
break ;
}
2012-02-20 05:39:18 +04:00
printf ( " \n " ) ;
2011-03-27 06:36:49 +04:00
cpuid ( 0x80000000 , max_eax , unused , unused , unused ) ;
/* Quok said: If the max extended eax value is high enough to support the processor brand string
( values 0x80000002 to 0x80000004 ) , then we ' ll use that information to return the brand information .
Otherwise , we ' ll refer back to the brand tables above for backwards compatibility with older processors .
According to the Sept . 2006 Intel Arch Software Developer ' s Guide , if extended eax values are supported ,
then all 3 values for the processor brand string are supported , but we ' ll test just to make sure and be safe . */
if ( max_eax > = 0x80000004 ) {
2012-02-20 05:39:18 +04:00
printf ( " Brand: " ) ;
2011-03-27 06:36:49 +04:00
if ( max_eax > = 0x80000002 ) {
cpuid ( 0x80000002 , eax , ebx , ecx , edx ) ;
printregs ( eax , ebx , ecx , edx ) ;
}
if ( max_eax > = 0x80000003 ) {
cpuid ( 0x80000003 , eax , ebx , ecx , edx ) ;
printregs ( eax , ebx , ecx , edx ) ;
}
if ( max_eax > = 0x80000004 ) {
cpuid ( 0x80000004 , eax , ebx , ecx , edx ) ;
printregs ( eax , ebx , ecx , edx ) ;
}
2012-02-20 05:39:18 +04:00
printf ( " \n " ) ;
2011-03-27 06:36:49 +04:00
} else if ( brand > 0 ) {
2012-02-20 05:39:18 +04:00
printf ( " Brand %d - " , brand ) ;
2011-03-27 06:36:49 +04:00
if ( brand < 0x18 ) {
if ( signature = = 0x000006B1 | | signature = = 0x00000F13 ) {
2012-02-20 05:39:18 +04:00
printf ( " %s \n " , Intel_Other [ brand ] ) ;
2011-03-27 06:36:49 +04:00
} else {
2012-02-20 05:39:18 +04:00
printf ( " %s \n " , Intel [ brand ] ) ;
2011-03-27 06:36:49 +04:00
}
} else {
2012-02-20 05:39:18 +04:00
printf ( " Reserved \n " ) ;
2011-03-27 06:36:49 +04:00
}
}
2012-02-20 05:39:18 +04:00
printf ( " Stepping: %d Reserved: %d \n " , stepping , reserved ) ;
2011-03-27 06:36:49 +04:00
return 0 ;
}
/* Print Registers */
void printregs ( int eax , int ebx , int ecx , int edx ) {
int j ;
char string [ 17 ] ;
string [ 16 ] = ' \0 ' ;
for ( j = 0 ; j < 4 ; j + + ) {
string [ j ] = eax > > ( 8 * j ) ;
string [ j + 4 ] = ebx > > ( 8 * j ) ;
string [ j + 8 ] = ecx > > ( 8 * j ) ;
string [ j + 12 ] = edx > > ( 8 * j ) ;
}
2012-02-20 05:39:18 +04:00
printf ( " %s " , string ) ;
2011-03-27 06:36:49 +04:00
}
/* AMD-specific information */
int do_amd ( void ) {
2012-02-20 05:39:18 +04:00
printf ( " AMD Specific Features: \n " ) ;
2011-03-27 06:36:49 +04:00
unsigned long extended , eax , ebx , ecx , edx , unused ;
int family , model , stepping , reserved ;
cpuid ( 1 , eax , unused , unused , unused ) ;
model = ( eax > > 4 ) & 0xf ;
family = ( eax > > 8 ) & 0xf ;
stepping = eax & 0xf ;
reserved = eax > > 12 ;
2012-02-20 05:39:18 +04:00
printf ( " Family: %d Model: %d [ " , family , model ) ;
2011-03-27 06:36:49 +04:00
switch ( family ) {
case 4 :
2012-02-20 05:39:18 +04:00
printf ( " 486 Model %d " , model ) ;
2011-03-27 06:36:49 +04:00
break ;
case 5 :
switch ( model ) {
case 0 :
case 1 :
case 2 :
case 3 :
case 6 :
case 7 :
2012-02-20 05:39:18 +04:00
printf ( " K6 Model %d " , model ) ;
2011-03-27 06:36:49 +04:00
break ;
case 8 :
2012-02-20 05:39:18 +04:00
printf ( " K6-2 Model 8 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 9 :
2012-02-20 05:39:18 +04:00
printf ( " K6-III Model 9 " ) ;
2011-03-27 06:36:49 +04:00
break ;
default :
2012-02-20 05:39:18 +04:00
printf ( " K5/K6 Model %d " , model ) ;
2011-03-27 06:36:49 +04:00
break ;
}
break ;
case 6 :
switch ( model ) {
case 1 :
case 2 :
case 4 :
2012-02-20 05:39:18 +04:00
printf ( " Athlon Model %d " , model ) ;
2011-03-27 06:36:49 +04:00
break ;
case 3 :
2012-02-20 05:39:18 +04:00
printf ( " Duron Model 3 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 6 :
2012-02-20 05:39:18 +04:00
printf ( " Athlon MP/Mobile Athlon Model 6 " ) ;
2011-03-27 06:36:49 +04:00
break ;
case 7 :
2012-02-20 05:39:18 +04:00
printf ( " Mobile Duron Model 7 " ) ;
2011-03-27 06:36:49 +04:00
break ;
default :
2012-02-20 05:39:18 +04:00
printf ( " Duron/Athlon Model %d " , model ) ;
2011-03-27 06:36:49 +04:00
break ;
}
break ;
}
2012-02-20 05:39:18 +04:00
printf ( " ] \n " ) ;
2011-03-27 06:36:49 +04:00
cpuid ( 0x80000000 , extended , unused , unused , unused ) ;
if ( extended = = 0 ) {
return 0 ;
}
if ( extended > = 0x80000002 ) {
unsigned int j ;
2012-02-20 05:39:18 +04:00
printf ( " Detected Processor Name: " ) ;
2011-03-27 06:36:49 +04:00
for ( j = 0x80000002 ; j < = 0x80000004 ; j + + ) {
cpuid ( j , eax , ebx , ecx , edx ) ;
printregs ( eax , ebx , ecx , edx ) ;
}
2012-02-20 05:39:18 +04:00
printf ( " \n " ) ;
2011-03-27 06:36:49 +04:00
}
if ( extended > = 0x80000007 ) {
cpuid ( 0x80000007 , unused , unused , unused , edx ) ;
if ( edx & 1 ) {
2012-02-20 05:39:18 +04:00
printf ( " Temperature Sensing Diode Detected! \n " ) ;
2011-03-27 06:36:49 +04:00
}
}
2012-02-20 05:39:18 +04:00
printf ( " Stepping: %d Reserved: %d \n " , stepping , reserved ) ;
2011-03-27 06:36:49 +04:00
return 0 ;
}