From ab0df696d09f6b53b33345d207f8aead63a6fcab Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 5 Aug 1998 15:15:46 +0000 Subject: Automatic CPU type detection code from Eric Valette . Enabled on the pc386. --- c/src/lib/libcpu/i386/Makefile.in | 6 +- c/src/lib/libcpu/i386/cpu.h | 9 +- c/src/lib/libcpu/i386/cpuModel.S | 255 +++++++++++++++++++++++++++++++++++++ c/src/lib/libcpu/i386/cpuModel.h | 32 +++++ c/src/lib/libcpu/i386/displayCpu.c | 209 ++++++++++++++++++++++++++++++ c/src/lib/libcpu/i386/registers.h | 159 +++++++++++++++++++++++ 6 files changed, 664 insertions(+), 6 deletions(-) create mode 100644 c/src/lib/libcpu/i386/cpuModel.S create mode 100644 c/src/lib/libcpu/i386/cpuModel.h create mode 100644 c/src/lib/libcpu/i386/displayCpu.c create mode 100644 c/src/lib/libcpu/i386/registers.h (limited to 'c/src/lib/libcpu') diff --git a/c/src/lib/libcpu/i386/Makefile.in b/c/src/lib/libcpu/i386/Makefile.in index 8a1c6f0951..b1282e2b55 100644 --- a/c/src/lib/libcpu/i386/Makefile.in +++ b/c/src/lib/libcpu/i386/Makefile.in @@ -11,14 +11,14 @@ PROJECT_ROOT = @PROJECT_ROOT@ PGM=${ARCH}/libcpu.rel # C source names, if any, go here -- minus the .c -C_PIECES=cpu +C_PIECES=cpu displayCpu C_FILES=$(C_PIECES:%=%.c) C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) -H_FILES=$(srcdir)/cpu.h +H_FILES=$(srcdir)/cpu.h $(srcdir)/registers.h $(srcdir)/cpuModel.h # Assembly source names, if any, go here -- minus the .s -S_PIECES=cpu_asm +S_PIECES=cpu_asm cpuModel S_FILES=$(S_PIECES:%=%.S) S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o) diff --git a/c/src/lib/libcpu/i386/cpu.h b/c/src/lib/libcpu/i386/cpu.h index cded552740..be25929a0e 100644 --- a/c/src/lib/libcpu/i386/cpu.h +++ b/c/src/lib/libcpu/i386/cpu.h @@ -18,8 +18,11 @@ * $Id$ */ -#ifndef _i386_CPU_H -#define _i386_CPU_H +#ifndef _LIBCPU_i386_CPU_H +#define _LIBCPU_i386_CPU_H + +#include + #ifndef ASM @@ -63,7 +66,7 @@ : "=r" ((_eflags)) : "0" ((_eflags)) \ ); \ \ - _level = (_eflags & 0x0200) ? 0 : 1; \ + _level = (_eflags & EFLAGS_INTR_ENABLE) ? 0 : 1; \ } while (0) #define _CPU_ISR_Disable( _level ) i386_disable_interrupts( _level ) diff --git a/c/src/lib/libcpu/i386/cpuModel.S b/c/src/lib/libcpu/i386/cpuModel.S new file mode 100644 index 0000000000..aaace8af9f --- /dev/null +++ b/c/src/lib/libcpu/i386/cpuModel.S @@ -0,0 +1,255 @@ +/* cpuModel.S + * + * This file contains all assembly code for the Intel Cpu identification. + * It is based on linux cpu detection code. + * + * Intel also provides public similar code in the book + * called : + * + * Pentium Processor Family + * Developer Family + * Volume 3 : Architecture and Programming Manual + * + * At the following place : + * + * Chapter 5 : Feature determination + * Chapter 25: CPUID instruction + * + * COPYRIGHT (c) 1998 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include +#include + +BEGIN_CODE + PUBLIC(checkCPUtypeSetCr0); +/* + * check Processor type: 386, 486, 6x86(L) or CPUID capable processor + */ + +SYM (checkCPUtypeSetCr0): + /* + * Assume 386 for now + */ + movl $3, SYM (x86) + /* + * Start using the EFAGS AC bit determination method described in + * the book mentionned above page 5.1. If this bit can be set we + * have a 486 or above. + */ + pushfl /* save EFLAGS */ + + pushfl /* Get EFLAGS in EAX */ + popl eax + + movl eax,ecx /* save original EFLAGS in ECX */ + xorl $EFLAGS_ALIGN_CHECK,eax /* flip AC bit in EAX */ + pushl eax /* set EAX as EFLAGS */ + popfl + pushfl /* Get new EFLAGS in EAX */ + popl eax + + xorl ecx,eax /* check if AC bit changed */ + andl $EFLAGS_ALIGN_CHECK,eax + je is386 /* If not : we have a 386 */ + /* + * Assume 486 for now + */ + movl $4,SYM (x86) + movl ecx,eax /* Restore orig EFLAGS in EAX */ + xorl $EFLAGS_ID,eax /* flip ID flag */ + pushl eax /* set EAX as EFLAGS */ + popfl + pushfl /* Get new EFLAGS in EAX */ + popl eax + + xorl ecx,eax /* check if ID bit changed */ + andl $EFLAGS_ID,eax + + /* + * if we are on a straight 486DX, + * SX, or 487SX we can't change it + * OTOH 6x86MXs and MIIs check OK + * Also if we are on a Cyrix 6x86(L) + */ + je is486x + +isnew: + /* + * restore original EFLAGS + */ + popfl + incl SYM(have_cpuid) /* we have CPUID instruction */ + + /* use it to get : + * processor type, + * processor model, + * processor mask, + * by using it with EAX = 1 + */ + movl $1, eax + cpuid + + movb al, cl /* save reg for future use */ + + andb $0x0f,ah /* mask processor family */ + movb ah,SYM (x86) /* put result in x86 var */ + + andb $0xf0, al /* get model */ + shrb $4, al + movb al,SYM (x86_model) /* store it in x86_model */ + + andb $0x0f, cl /* get mask revision */ + movb cl,SYM (x86_mask) /* store it in x86_mask */ + + movl edx,SYM(x86_capability) /* store feature flags in x86_capability */ + + /* get vendor info by using CPUID with EXA = 0 */ + xorl eax, eax + cpuid + + /* + * store results contained in ebx, edx, ecx in + * x86_vendor_id variable. + */ + movl ebx,SYM(x86_vendor_id) + movl edx,SYM(x86_vendor_id)+4 + movl ecx,SYM(x86_vendor_id)+8 + + movl cr0,eax /* 486+ */ + andl $(CR0_PAGING | CR0_PROTECTION_ENABLE | CR0_EXTENSION_TYPE), eax + orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax + jmp 2f + +/* Now we test if we have a Cyrix 6x86(L). We didn't test before to avoid + * clobbering the new BX chipset used with the Pentium II, which has a register + * at the same addresses as those used to access the Cyrix special configuration + * registers (CCRs). + */ + /* + * A Cyrix/IBM 6x86(L) preserves flags after dividing 5 by 2 + * (and it _must_ be 5 divided by 2) while other CPUs change + * them in undefined ways. We need to know this since we may + * need to enable the CPUID instruction at least. + * We couldn't use this test before since the PPro and PII behave + * like Cyrix chips in this respect. + */ +is486x: xor ax,ax + sahf + movb $5,ax + movb $2,bx + div bl + lahf + cmpb $2,ah + jne ncyrix + /* + * N.B. The pattern of accesses to 0x22 and 0x23 is *essential* + * so do not try to "optimize" it! For the same reason we + * do all this with interrupts off. + */ +#define setCx86(reg, val) \ + movb reg,ax; \ + outb ax,$0x22; \ + movb val,ax; \ + outb ax,$0x23 + +#define getCx86(reg) \ + movb reg,ax; \ + outb ax,$0x22; \ + inb $0x23,ax + + cli + getCx86($0xc3) /* get CCR3 */ + movb ax,cx /* Save old value */ + movb ax,bx + andb $0x0f,bx /* Enable access to all config registers */ + orb $0x10,bx /* by setting bit 4 */ + setCx86($0xc3,bx) + + getCx86($0xe8) /* now we can get CCR4 */ + orb $0x80,ax /* and set bit 7 (CPUIDEN) */ + movb ax,bx /* to enable CPUID execution */ + setCx86($0xe8,bx) + + getCx86($0xfe) /* DIR0 : let's check this is a 6x86(L) */ + andb $0xf0,ax /* should be 3xh */ + cmpb $0x30,ax + jne n6x86 + getCx86($0xe9) /* CCR5 : we reset the SLOP bit */ + andb $0xfd,ax /* so that udelay calculation */ + movb ax,bx /* is correct on 6x86(L) CPUs */ + setCx86($0xe9,bx) + setCx86($0xc3,cx) /* Restore old CCR3 */ + sti + jmp isnew /* We enabled CPUID now */ + +n6x86: setCx86($0xc3,cx) /* Restore old CCR3 */ + sti +ncyrix: /* restore original EFLAGS */ + popfl + movl cr0,eax /* 486 */ + andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax /* Save PG,PE,ET */ + orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax /* set AM, WP, NE and MP */ + jmp 2f +is386: /* restore original EFLAGS */ + popfl + movl cr0,eax /* 386 */ + andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax /* Save PG,PE,ET */ + orl $CR0_MONITOR_COPROC,eax /* set MP */ +2: movl eax,cr0 + call check_x87 + ret + + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + movb $0,SYM(hard_math) + clts + fninit + fstsw ax + cmpb $0,al + je 1f + movl cr0,eax /* no coprocessor: have to set bits */ + xorl $4,eax /* set EM */ + movl eax,cr0 + ret + .align 16 +1: movb $1,SYM(hard_math) + .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +END_CODE + +BEGIN_DATA + PUBLIC(x86) + PUBLIC(have_cpuid) + PUBLIC(x86_model) + PUBLIC(x86_mask) + PUBLIC(x86_capability) + PUBLIC(x86_vendor_id) + PUBLIC(hard_math) + +SYM(x86): + .byte 0 +SYM(have_cpuid): + .long 0 +SYM(x86_model): + .byte 0 +SYM(x86_mask): + .byte 0 +SYM(x86_capability): + .long 0 +SYM(x86_vendor_id): + .zero 13 +SYM(hard_math): + .byte 0 +END_DATA + diff --git a/c/src/lib/libcpu/i386/cpuModel.h b/c/src/lib/libcpu/i386/cpuModel.h new file mode 100644 index 0000000000..5d7301aab4 --- /dev/null +++ b/c/src/lib/libcpu/i386/cpuModel.h @@ -0,0 +1,32 @@ +/* cpuModel.h + * + * This file contains declaration for variables and code + * that may be used to get the Intel Cpu identification + * that has been performed by checkCPUtypeSetCr0 function. + * + * COPYRIGHT (c) 1998 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +/* + * Tell us the machine setup.. + */ +#include +#include +#include + +extern char hard_math; /* flotting point coprocessor present indicator */ +extern char x86; /* type of cpu (3 = 386, 4 =486, ...) */ +extern char x86_model; +extern char x86_mask; +extern int x86_capability; +extern char x86_vendor_id[13]; +extern int have_cpuid; +extern unsigned char Cx86_step; /* cyrix processor identification */ + +extern voidget_cpuinfo(); /* Display this information in ascii form */ diff --git a/c/src/lib/libcpu/i386/displayCpu.c b/c/src/lib/libcpu/i386/displayCpu.c new file mode 100644 index 0000000000..3220b1151f --- /dev/null +++ b/c/src/lib/libcpu/i386/displayCpu.c @@ -0,0 +1,209 @@ +/* displayCpu.c + * + * This file contains code for displaying the Intel Cpu identification + * that has been performed by checkCPUtypeSetCr0 function. + * + * COPYRIGHT (c) 1998 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +/* + * Tell us the machine setup.. + */ +#include +#include +#include +#include + +extern void printk(const char*, ...); + +unsigned char Cx86_step = 0; +static const char *Cx86_type[] = { + "unknown", "1.3", "1.4", "1.5", "1.6", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2" + }; + +static const char * i486model(unsigned int nr) +{ + static const char *model[] = { + "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB", + "10","11","12","13","Am5x86-WT","Am5x86-WB" + }; + if (nr < sizeof(model)/sizeof(char *)) + return model[nr]; + return NULL; +} + +static const char * i586model(unsigned int nr) +{ + static const char *model[] = { + "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83", + "Pentium MMX", NULL, NULL, "Mobile Pentium 75+", + "Mobile Pentium MMX" + }; + if (nr < sizeof(model)/sizeof(char *)) + return model[nr]; + return NULL; +} + +static const char * Cx86model(void) +{ + unsigned char nr6x86 = 0; + static const char *model[] = { + "unknown", "6x86", "6x86L", "6x86MX", "MII" + }; + switch (x86) { + case 5: + nr6x86 = ((x86_capability & (1 << 8)) ? 2 : 1); /* cx8 flag only on 6x86L */ + break; + case 6: + nr6x86 = 3; + break; + default: + nr6x86 = 0; + } + + /* We must get the stepping number by reading DIR1 */ + i386_outport_byte(0x22,0xff) ; i386_inport_byte(0x23, x86_mask); + switch (x86_mask) { + case 0x03: + Cx86_step = 1; /* 6x86MX Rev 1.3 */ + break; + case 0x04: + Cx86_step = 2; /* 6x86MX Rev 1.4 */ + break; + case 0x05: + Cx86_step = 3; /* 6x86MX Rev 1.5 */ + break; + case 0x06: + Cx86_step = 4; /* 6x86MX Rev 1.6 */ + break; + case 0x14: + Cx86_step = 5; /* 6x86 Rev 2.4 */ + break; + case 0x15: + Cx86_step = 6; /* 6x86 Rev 2.5 */ + break; + case 0x16: + Cx86_step = 7; /* 6x86 Rev 2.6 */ + break; + case 0x17: + Cx86_step = 8; /* 6x86 Rev 2.7 or 3.7 */ + break; + case 0x22: + Cx86_step = 9; /* 6x86L Rev 4.2 */ + break; + default: + Cx86_step = 0; + } + return model[nr6x86]; +} + +static const char * i686model(unsigned int nr) +{ + static const char *model[] = { + "PPro A-step", "Pentium Pro" + }; + if (nr < sizeof(model)/sizeof(char *)) + return model[nr]; + return NULL; +} + +struct cpu_model_info { + int x86; + char *model_names[16]; +}; + +static struct cpu_model_info amd_models[] = { + { 4, + { NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4", + "DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }}, + { 5, + { "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)", + "K5 (PR-166)", "K5 (PR-200)", NULL, NULL, + "K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)", + "K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }}, +}; + +static const char * AMDmodel(void) +{ + const char *p=NULL; + int i; + + if (x86_model < 16) + for (i=0; i7 + */ + unsigned int carry : 1; + unsigned int : 1; + unsigned int parity : 1; + unsigned int : 1; + + unsigned int auxiliary_carry : 1; + unsigned int : 1; + unsigned int zero : 1; /* result is zero */ + unsigned int sign : 1; /* result is less than zero */ + /* + * Second byte : bits 7->15 + */ + unsigned int trap : 1; + unsigned int intr_enable : 1; /* set => intr on */ + unsigned int direction : 1; /* set => autodecrement */ + unsigned int overflow : 1; + + unsigned int IO_privilege : 2; + unsigned int nested_task : 1; + unsigned int : 1; + /* + * Third byte : bits 15->23 + */ + unsigned int resume : 1; + unsigned int virtual_mode : 1; + unsigned int aligment_check : 1; + unsigned int virtual_intr : 1; + + unsigned int virtual_intr_pending : 1; + unsigned int id : 1; + unsigned int : 2; + + /* + * fourth byte : bits 24->31 : UNUSED + */ + unsigned int : 8; +}eflags_bits; + +typedef union { + eflags_bits eflags; + unsigned int i; +}eflags; +/* + * definition of eflags registers has a bit field structure + */ +typedef struct { + /* + * fist byte : bits 0->7 + */ + unsigned int protection_enable : 1; + unsigned int monitor_coproc : 1; + unsigned int coproc_soft_emul : 1; + unsigned int floating_instr_except : 1; + + unsigned int extension_type : 1; + unsigned int numeric_error : 1; + unsigned int : 2; + /* + * second byte 8->15 : UNUSED + */ + unsigned int : 8; + /* + * third byte 16->23 + */ + unsigned int write_protect : 1; + unsigned int : 1; + unsigned int aligment_mask : 1; + unsigned int : 1; + + unsigned int : 4; + /* + * fourth byte 24->31 + */ + unsigned int : 4; + + unsigned int : 1; + unsigned int no_write_through : 1; + unsigned int page_level_cache_disable : 1; + unsigned int paging : 1; +}cr0_bits; + +typedef union { + cr0_bits cr0; + unsigned int i; +}cr0; + +#endif + +#endif + -- cgit v1.2.3