OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [i386/] [cpuModel.S] - Rev 180

Go to most recent revision | 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
        

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.