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

Last change on this file since 328bd35 was c499856, checked in by Chris Johns <chrisj@…>, on Mar 20, 2014 at 9:10:47 PM

Change all references of rtems.com to rtems.org.

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