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

4.115
Last change on this file since a3579d3b was 9e95e54, checked in by Joel Sherrill <joel.sherrill@…>, on 04/15/10 at 14:09:57

2010-04-15 Joel Sherrill <joel.sherrill@…>

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