URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [i386/] [cpuModel.S] - Rev 173
Compare with Previous | Blame | View Log
/* 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: cpuModel.S,v 1.2 2001-09-27 12:01:22 chris Exp $
*/
#include <asm.h>
#include <libcpu/registers.h>
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 EFLAGS AC bit determination method described in
* the book mentioned 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,al
movb $2,bl
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,al; \
outb al,$0x22; \
movb val,al; \
outb al,$0x23
#define getCx86(reg) \
movb reg,al; \
outb al,$0x22; \
inb $0x23,al
cli
getCx86($0xc3) /* get CCR3 */
movb al,cl /* Save old value */
movb al,bl
andb $0x0f,bl /* Enable access to all config registers */
orb $0x10,bl /* by setting bit 4 */
setCx86($0xc3,bl)
getCx86($0xe8) /* now we can get CCR4 */
orb $0x80,al /* and set bit 7 (CPUIDEN) */
movb al,bl /* to enable CPUID execution */
setCx86($0xe8,bl)
getCx86($0xfe) /* DIR0 : let's check this is a 6x86(L) */
andb $0xf0,al /* should be 3xh */
cmpb $0x30,al
jne n6x86
getCx86($0xe9) /* CCR5 : we reset the SLOP bit */
andb $0xfd,al /* so that udelay calculation */
movb al,bl /* is correct on 6x86(L) CPUs */
setCx86($0xe9,bl)
setCx86($0xc3,cl) /* Restore old CCR3 */
sti
jmp isnew /* We enabled CPUID now */
n6x86: setCx86($0xc3,cl) /* 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