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

4.104.115
Last change on this file since 359e537 was caf761f, checked in by Till Straumann <strauman@…>, on 10/28/09 at 21:40:14

2009-10-28 Till Straumann <strauman@…>

  • cpuModel.S, cpuModel.h, displayCpu.c: Save/cache CPUID:ECX (extended capabilities) in a new variable (x86_capability_x). Added more known flag description strings (printCpuInfo()) and let 'printCpuInfo()' dump the extended feature flags, too.
  • Property mode set to 100644
File size: 6.2 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.rtems.com/license/LICENSE.
23 *
24 *  $Id$
25 */
26
27#include <rtems/asm.h>
28#include <rtems/score/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 EFLAGS AC bit determination method described in
43         * the book mentioned 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        movl ecx,SYM(x86_capability_x) /* store ecx feature flags */
99
100        movb al, cl             /* save reg for future use */
101       
102        andb $0x0f,ah           /* mask processor family   */
103        movb ah,SYM (x86)       /* put result in x86 var   */
104       
105        andb $0xf0, al          /* get model               */
106        shrb $4, al
107        movb al,SYM (x86_model) /* store it in x86_model   */
108       
109        andb $0x0f, cl          /* get mask revision       */
110        movb cl,SYM (x86_mask)  /* store it in x86_mask    */
111       
112        movl edx,SYM(x86_capability)    /* store feature flags in x86_capability */
113       
114        /* get vendor info by using CPUID with EXA = 0 */
115        xorl eax, eax           
116        cpuid
117
118        /*
119         * store results contained in ebx, edx, ecx in
120         * x86_vendor_id variable.
121         */
122        movl ebx,SYM(x86_vendor_id)     
123        movl edx,SYM(x86_vendor_id)+4   
124        movl ecx,SYM(x86_vendor_id)+8   
125
126        movl cr0,eax            /* 486+ */
127        andl $(CR0_PAGING | CR0_PROTECTION_ENABLE | CR0_EXTENSION_TYPE), eax
128        orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax
129        jmp 2f
130
131/* Now we test if we have a Cyrix 6x86(L). We didn't test before to avoid
132 * clobbering the new BX chipset used with the Pentium II, which has a register
133 * at the same addresses as those used to access the Cyrix special configuration
134 * registers (CCRs).
135 */
136        /*
137         * A Cyrix/IBM 6x86(L) preserves flags after dividing 5 by 2
138         * (and it _must_ be 5 divided by 2) while other CPUs change
139         * them in undefined ways. We need to know this since we may
140         * need to enable the CPUID instruction at least.
141         * We couldn't use this test before since the PPro and PII behave
142         * like Cyrix chips in this respect.
143         */
144is486x: xor ax,ax
145        sahf
146        movb $5,al
147        movb $2,bl
148        div bl
149        lahf
150        cmpb $2,ah
151        jne ncyrix
152        /*
153         * N.B. The pattern of accesses to 0x22 and 0x23 is *essential*
154         *      so do not try to "optimize" it! For the same reason we
155         *      do all this with interrupts off.
156         */
157#define setCx86(reg, val) \
158        movb reg,al;    \
159        outb al,$0x22;  \
160        movb val,al;    \
161        outb al,$0x23
162
163#define getCx86(reg) \
164        movb reg,al;    \
165        outb al,$0x22;  \
166        inb $0x23,al
167
168        cli
169        getCx86($0xc3)          /*  get CCR3 */
170        movb al,cl              /* Save old value */
171        movb al,bl
172        andb $0x0f,bl           /* Enable access to all config registers */
173        orb $0x10,bl            /* by setting bit 4 */
174        setCx86($0xc3,bl)
175
176        getCx86($0xe8)          /* now we can get CCR4 */
177        orb $0x80,al            /* and set bit 7 (CPUIDEN) */
178        movb al,bl              /* to enable CPUID execution */
179        setCx86($0xe8,bl)
180
181        getCx86($0xfe)          /* DIR0 : let's check this is a 6x86(L) */
182        andb $0xf0,al           /* should be 3xh */
183        cmpb $0x30,al           
184        jne n6x86
185        getCx86($0xe9)          /* CCR5 : we reset the SLOP bit */
186        andb $0xfd,al           /* so that udelay calculation */
187        movb al,bl              /* is correct on 6x86(L) CPUs */
188        setCx86($0xe9,bl)
189        setCx86($0xc3,cl)       /* Restore old CCR3 */
190        sti
191        jmp isnew               /* We enabled CPUID now */
192
193n6x86:  setCx86($0xc3,cl)       /* Restore old CCR3 */
194        sti
195ncyrix:                         /* restore original EFLAGS */
196        popfl
197        movl cr0,eax            /* 486 */
198        andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax     /* Save PG,PE,ET */
199        orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax       /* set AM, WP, NE and MP */
200        jmp 2f
201is386:                          /* restore original EFLAGS */
202        popfl
203        movl cr0,eax            /* 386 */
204        andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax     /* Save PG,PE,ET */
205        orl $CR0_MONITOR_COPROC,eax             /* set MP */
2062:      movl eax,cr0
207        call check_x87
208        ret
209       
210
211/*
212 * We depend on ET to be correct. This checks for 287/387.
213 */
214check_x87:
215        movb $0,SYM(hard_math)
216        clts
217        fninit
218        fstsw ax
219        cmpb $0,al
220        je 1f
221        movl cr0,eax            /* no coprocessor: have to set bits */
222        xorl $4,eax             /* set EM */
223        movl eax,cr0
224        ret
225        .align 16
2261:      movb $1,SYM(hard_math)
227        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
228        ret
229
230END_CODE
231       
232BEGIN_DATA
233        PUBLIC(x86)
234        PUBLIC(have_cpuid)
235        PUBLIC(x86_model)
236        PUBLIC(x86_mask)
237        PUBLIC(x86_capability)
238        PUBLIC(x86_capability_x)
239        PUBLIC(x86_vendor_id)
240        PUBLIC(hard_math)
241
242SYM(x86):       
243        .byte 0
244SYM(have_cpuid):       
245        .long 0
246SYM(x86_model):
247        .byte 0
248SYM(x86_mask): 
249        .byte 0
250SYM(x86_capability):   
251        .long 0         
252SYM(x86_capability_x): 
253        .long 0         
254SYM(x86_vendor_id):     
255        .zero 13
256SYM(hard_math):
257        .byte 0
258END_DATA
Note: See TracBrowser for help on using the repository browser.