source: rtems/c/src/lib/libcpu/i386/cpuModel.S @ ab0df696

4.104.114.84.9
Last change on this file since ab0df696 was ab0df696, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 5, 1998 at 3:15:46 PM

Automatic CPU type detection code from Eric Valette <valette@…>.
Enabled on the pc386.

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/*  cpuModel.S
2 *
3 *  This file contains all assembly code for the Intel Cpu identification.
4 *  It is based on linux cpu detection code.
5 *
6 *  Intel also provides public similar code in the book
7 *  called :
8 *     
9 *      Pentium Processor Family
10 *              Developer Family
11 *      Volume  3 :     Architecture and Programming Manual
12 *
13 * At the following place :
14 *     
15 *      Chapter 5 :     Feature determination
16 *      Chapter 25:     CPUID instruction       
17 *
18 *  COPYRIGHT (c) 1998 valette@crf.canon.fr
19 *
20 *  The license and distribution terms for this file may be
21 *  found in the file LICENSE in this distribution or at
22 *  http://www.OARcorp.com/rtems/license.html.
23 *
24 *  $Id$
25 */
26
27#include <asm.h>
28#include <libcpu/registers.h>
29
30BEGIN_CODE
31        PUBLIC(checkCPUtypeSetCr0);
32/*
33 * check Processor type: 386, 486, 6x86(L) or CPUID capable processor
34 */
35
36SYM (checkCPUtypeSetCr0):
37        /*
38         *  Assume 386 for now
39         */
40        movl $3, SYM (x86)
41        /*
42         * Start using the EFAGS AC bit determination method described in
43         * the book mentionned above page 5.1. If this bit can be set we
44         * have a 486 or above.
45         */
46        pushfl                          /* save EFLAGS                  */
47       
48        pushfl                          /* Get EFLAGS in EAX            */
49        popl eax
50       
51        movl eax,ecx                    /* save original EFLAGS in ECX  */
52        xorl $EFLAGS_ALIGN_CHECK,eax    /* flip AC bit in EAX           */
53        pushl eax                       /* set EAX as EFLAGS            */
54        popfl                   
55        pushfl                          /* Get new EFLAGS in EAX        */
56        popl eax
57       
58        xorl ecx,eax                    /* check if AC bit changed      */
59        andl $EFLAGS_ALIGN_CHECK,eax   
60        je is386                        /* If not : we have a 386       */
61        /*
62         *  Assume 486 for now
63         */
64        movl $4,SYM (x86)
65        movl ecx,eax                    /* Restore orig EFLAGS in EAX   */
66        xorl $EFLAGS_ID,eax             /* flip  ID flag                */
67        pushl eax                       /* set EAX as EFLAGS            */
68        popfl                           
69        pushfl                          /* Get new EFLAGS in EAX        */
70        popl eax       
71                       
72        xorl ecx,eax                    /* check if ID bit changed      */
73        andl $EFLAGS_ID,eax
74
75        /*
76         * if we are on a straight 486DX,
77         * SX, or 487SX we can't change it
78         * OTOH 6x86MXs and MIIs check OK
79         * Also if we are on a Cyrix 6x86(L)
80         */
81        je is486x
82
83isnew: 
84        /*
85         * restore original EFLAGS
86         */
87        popfl
88        incl SYM(have_cpuid)    /* we have CPUID instruction */
89
90        /* use it to get :     
91         *      processor type,
92         *      processor model,
93         *      processor mask,
94         * by using it with EAX = 1
95         */
96        movl $1, eax           
97        cpuid                   
98
99        movb al, cl             /* save reg for future use */
100       
101        andb $0x0f,ah           /* mask processor family   */
102        movb ah,SYM (x86)       /* put result in x86 var   */
103       
104        andb $0xf0, al          /* get model               */
105        shrb $4, al
106        movb al,SYM (x86_model) /* store it in x86_model   */
107       
108        andb $0x0f, cl          /* get mask revision       */
109        movb cl,SYM (x86_mask)  /* store it in x86_mask    */
110       
111        movl edx,SYM(x86_capability)    /* store feature flags in x86_capability */
112       
113        /* get vendor info by using CPUID with EXA = 0 */
114        xorl eax, eax           
115        cpuid
116
117        /*
118         * store results contained in ebx, edx, ecx in
119         * x86_vendor_id variable.
120         */
121        movl ebx,SYM(x86_vendor_id)     
122        movl edx,SYM(x86_vendor_id)+4   
123        movl ecx,SYM(x86_vendor_id)+8   
124
125        movl cr0,eax            /* 486+ */
126        andl $(CR0_PAGING | CR0_PROTECTION_ENABLE | CR0_EXTENSION_TYPE), eax
127        orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax
128        jmp 2f
129
130/* Now we test if we have a Cyrix 6x86(L). We didn't test before to avoid
131 * clobbering the new BX chipset used with the Pentium II, which has a register
132 * at the same addresses as those used to access the Cyrix special configuration
133 * registers (CCRs).
134 */
135        /*
136         * A Cyrix/IBM 6x86(L) preserves flags after dividing 5 by 2
137         * (and it _must_ be 5 divided by 2) while other CPUs change
138         * them in undefined ways. We need to know this since we may
139         * need to enable the CPUID instruction at least.
140         * We couldn't use this test before since the PPro and PII behave
141         * like Cyrix chips in this respect.
142         */
143is486x: xor ax,ax
144        sahf
145        movb $5,ax
146        movb $2,bx
147        div bl
148        lahf
149        cmpb $2,ah
150        jne ncyrix
151        /*
152         * N.B. The pattern of accesses to 0x22 and 0x23 is *essential*
153         *      so do not try to "optimize" it! For the same reason we
154         *      do all this with interrupts off.
155         */
156#define setCx86(reg, val) \
157        movb reg,ax;    \
158        outb ax,$0x22;  \
159        movb val,ax;    \
160        outb ax,$0x23
161
162#define getCx86(reg) \
163        movb reg,ax;    \
164        outb ax,$0x22;  \
165        inb $0x23,ax
166
167        cli
168        getCx86($0xc3)          /*  get CCR3 */
169        movb ax,cx              /* Save old value */
170        movb ax,bx
171        andb $0x0f,bx           /* Enable access to all config registers */
172        orb $0x10,bx            /* by setting bit 4 */
173        setCx86($0xc3,bx)
174
175        getCx86($0xe8)          /* now we can get CCR4 */
176        orb $0x80,ax            /* and set bit 7 (CPUIDEN) */
177        movb ax,bx              /* to enable CPUID execution */
178        setCx86($0xe8,bx)
179
180        getCx86($0xfe)          /* DIR0 : let's check this is a 6x86(L) */
181        andb $0xf0,ax           /* should be 3xh */
182        cmpb $0x30,ax           
183        jne n6x86
184        getCx86($0xe9)          /* CCR5 : we reset the SLOP bit */
185        andb $0xfd,ax           /* so that udelay calculation */
186        movb ax,bx              /* is correct on 6x86(L) CPUs */
187        setCx86($0xe9,bx)
188        setCx86($0xc3,cx)       /* Restore old CCR3 */
189        sti
190        jmp isnew               /* We enabled CPUID now */
191
192n6x86:  setCx86($0xc3,cx)       /* Restore old CCR3 */
193        sti
194ncyrix:                         /* restore original EFLAGS */
195        popfl
196        movl cr0,eax            /* 486 */
197        andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax     /* Save PG,PE,ET */
198        orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax       /* set AM, WP, NE and MP */
199        jmp 2f
200is386:                          /* restore original EFLAGS */
201        popfl
202        movl cr0,eax            /* 386 */
203        andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax     /* Save PG,PE,ET */
204        orl $CR0_MONITOR_COPROC,eax             /* set MP */
2052:      movl eax,cr0
206        call check_x87
207        ret
208       
209
210/*
211 * We depend on ET to be correct. This checks for 287/387.
212 */
213check_x87:
214        movb $0,SYM(hard_math)
215        clts
216        fninit
217        fstsw ax
218        cmpb $0,al
219        je 1f
220        movl cr0,eax            /* no coprocessor: have to set bits */
221        xorl $4,eax             /* set EM */
222        movl eax,cr0
223        ret
224        .align 16
2251:      movb $1,SYM(hard_math)
226        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
227        ret
228
229END_CODE
230       
231BEGIN_DATA
232        PUBLIC(x86)
233        PUBLIC(have_cpuid)
234        PUBLIC(x86_model)
235        PUBLIC(x86_mask)
236        PUBLIC(x86_capability)
237        PUBLIC(x86_vendor_id)
238        PUBLIC(hard_math)
239
240SYM(x86):       
241        .byte 0
242SYM(have_cpuid):       
243        .long 0
244SYM(x86_model):
245        .byte 0
246SYM(x86_mask): 
247        .byte 0
248SYM(x86_capability):   
249        .long 0         
250SYM(x86_vendor_id):     
251        .zero 13
252SYM(hard_math):
253        .byte 0
254END_DATA
255       
Note: See TracBrowser for help on using the repository browser.