1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006 Erwan Velu - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * -----------------------------------------------------------------------
33 struct cpu_dev
* cpu_devs
[X86_VENDOR_NUM
] = {};
36 * CPUID functions returning a single datum
38 static inline unsigned int cpuid_eax(unsigned int op
)
49 static inline unsigned int cpuid_ecx(unsigned int op
)
51 unsigned int eax
, ecx
;
54 : "=a" (eax
), "=c" (ecx
)
59 static inline unsigned int cpuid_edx(unsigned int op
)
61 unsigned int eax
, edx
;
64 : "=a" (eax
), "=d" (edx
)
70 /* Standard macro to see if a specific flag is changeable */
71 static inline int flag_is_changeable_p(u32 flag
)
85 : "=&r" (f1
), "=&r" (f2
)
88 return ((f1
^f2
) & flag
) != 0;
91 /* Probe for the CPUID instruction */
92 static int have_cpuid_p(void)
94 return flag_is_changeable_p(X86_EFLAGS_ID
);
97 static struct cpu_dev amd_cpu_dev
= {
99 .c_ident
= { "AuthenticAMD" }
102 static struct cpu_dev intel_cpu_dev
= {
104 .c_ident
= { "GenuineIntel" }
107 static struct cpu_dev cyrix_cpu_dev
= {
109 .c_ident
= { "CyrixInstead" }
112 static struct cpu_dev umc_cpu_dev
= {
114 .c_ident
= { "UMC UMC UMC" }
118 static struct cpu_dev nexgen_cpu_dev
= {
119 .c_vendor
= "Nexgen",
120 .c_ident
= { "NexGenDriven" }
123 static struct cpu_dev centaur_cpu_dev
= {
124 .c_vendor
= "Centaur",
125 .c_ident
= { "CentaurHauls" }
128 static struct cpu_dev rise_cpu_dev
= {
130 .c_ident
= { "RiseRiseRise" }
133 static struct cpu_dev transmeta_cpu_dev
= {
134 .c_vendor
= "Transmeta",
135 .c_ident
= { "GenuineTMx86", "TransmetaCPU" }
138 void init_cpu_devs(void)
140 cpu_devs
[X86_VENDOR_INTEL
] = &intel_cpu_dev
;
141 cpu_devs
[X86_VENDOR_CYRIX
] = &cyrix_cpu_dev
;
142 cpu_devs
[X86_VENDOR_AMD
] = &amd_cpu_dev
;
143 cpu_devs
[X86_VENDOR_UMC
] = &umc_cpu_dev
;
144 cpu_devs
[X86_VENDOR_NEXGEN
] = &nexgen_cpu_dev
;
145 cpu_devs
[X86_VENDOR_CENTAUR
] = ¢aur_cpu_dev
;
146 cpu_devs
[X86_VENDOR_RISE
] = &rise_cpu_dev
;
147 cpu_devs
[X86_VENDOR_TRANSMETA
] = &transmeta_cpu_dev
;
150 void get_cpu_vendor(struct cpuinfo_x86
*c
)
152 char *v
= c
->x86_vendor_id
;
155 for (i
= 0; i
< X86_VENDOR_NUM
; i
++) {
157 if (!strcmp(v
,cpu_devs
[i
]->c_ident
[0]) ||
158 (cpu_devs
[i
]->c_ident
[1] &&
159 !strcmp(v
,cpu_devs
[i
]->c_ident
[1]))) {
166 c
->x86_vendor
= X86_VENDOR_UNKNOWN
;
169 int get_model_name(struct cpuinfo_x86
*c
)
174 if (cpuid_eax(0x80000000) < 0x80000004)
177 v
= (unsigned int *) c
->x86_model_id
;
178 cpuid(0x80000002, &v
[0], &v
[1], &v
[2], &v
[3]);
179 cpuid(0x80000003, &v
[4], &v
[5], &v
[6], &v
[7]);
180 cpuid(0x80000004, &v
[8], &v
[9], &v
[10], &v
[11]);
181 c
->x86_model_id
[48] = 0;
183 /* Intel chips right-justify this string for some dumb reason;
184 undo that brain damage */
185 p
= q
= &c
->x86_model_id
[0];
191 while ( q
<= &c
->x86_model_id
[48] )
192 *q
++ = '\0'; /* Zero-pad the rest */
198 void generic_identify(struct cpuinfo_x86
*c
)
202 /* Get vendor name */
203 cpuid(0x00000000, &c
->cpuid_level
,
204 (int *)&c
->x86_vendor_id
[0],
205 (int *)&c
->x86_vendor_id
[8],
206 (int *)&c
->x86_vendor_id
[4]);
209 /* Intel-defined flags: level 0x00000001 */
210 if ( c
->cpuid_level
>= 0x00000001 ) {
211 u32 capability
, excap
;
212 cpuid(0x00000001, &tfms
, &junk
, &excap
, &capability
);
213 c
->x86_capability
[0] = capability
;
214 c
->x86_capability
[4] = excap
;
215 c
->x86
= (tfms
>> 8) & 15;
216 c
->x86_model
= (tfms
>> 4) & 15;
218 c
->x86
+= (tfms
>> 20) & 0xff;
219 c
->x86_model
+= ((tfms
>> 16) & 0xF) << 4;
221 c
->x86_mask
= tfms
& 15;
222 if (capability
& (1<<19))
223 c
->x86_cache_alignment
= ((junk
>> 8) & 0xff) * 8;
225 /* Have CPUID level 0 only - unheard of */
229 /* AMD-defined flags: level 0x80000001 */
230 xlvl
= cpuid_eax(0x80000000);
231 if ( (xlvl
& 0xffff0000) == 0x80000000 ) {
232 if ( xlvl
>= 0x80000001 ) {
233 c
->x86_capability
[1] = cpuid_edx(0x80000001);
234 c
->x86_capability
[6] = cpuid_ecx(0x80000001);
236 if ( xlvl
>= 0x80000004 )
237 get_model_name(c
); /* Default name */
242 * Checksum an MP configuration block.
245 static int mpf_checksum(unsigned char *mp
, int len
)
255 static int smp_scan_config (unsigned long base
, unsigned long length
)
257 unsigned long *bp
= base
;
258 struct intel_mp_floating
*mpf
;
260 // printf("Scan SMP from %p for %ld bytes.\n", bp,length);
261 if (sizeof(*mpf
) != 16) {
262 printf("Error: MPF size\n");
267 mpf
= (struct intel_mp_floating
*)bp
;
268 if ((*bp
== SMP_MAGIC_IDENT
) &&
269 (mpf
->mpf_length
== 1) &&
270 !mpf_checksum((unsigned char *)bp
, 16) &&
271 ((mpf
->mpf_specification
== 1)
272 || (mpf
->mpf_specification
== 4)) ) {
281 int find_smp_config (void)
283 // unsigned int address;
286 * FIXME: Linux assumes you have 640K of base ram..
287 * this continues the error...
289 * 1) Scan the bottom 1K for a signature
290 * 2) Scan the top 1K of base RAM
291 * 3) Scan the 64K of bios
293 if (smp_scan_config(0x0,0x400) ||
294 smp_scan_config(639*0x400,0x400) ||
295 smp_scan_config(0xF0000,0x10000))
298 * If it is an SMP machine we should know now, unless the
299 * configuration is in an EISA/MCA bus machine with an
300 * extended bios data area.
302 * there is a real-mode segmented pointer pointing to the
303 * 4K EBDA area at 0x40E, calculate and scan it here.
305 * NOTE! There are Linux loaders that will corrupt the EBDA
306 * area, and as such this kind of SMP config may be less
307 * trustworthy, simply because the SMP table may have been
308 * stomped on during early boot. These loaders are buggy and
311 * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
314 // address = get_bios_ebda();
316 // smp_scan_config(address, 0x400);
321 void set_cpu_flags(struct cpuinfo_x86
*c
, s_cpu
*cpu
) {
322 cpu
->flags
.fpu
=cpu_has(c
, X86_FEATURE_FPU
);
323 cpu
->flags
.vme
=cpu_has(c
, X86_FEATURE_VME
);
324 cpu
->flags
.de
=cpu_has(c
, X86_FEATURE_DE
);
325 cpu
->flags
.pse
=cpu_has(c
, X86_FEATURE_PSE
);
326 cpu
->flags
.tsc
=cpu_has(c
, X86_FEATURE_TSC
);
327 cpu
->flags
.msr
=cpu_has(c
, X86_FEATURE_MSR
);
328 cpu
->flags
.pae
=cpu_has(c
, X86_FEATURE_PAE
);
329 cpu
->flags
.mce
=cpu_has(c
, X86_FEATURE_MCE
);
330 cpu
->flags
.cx8
=cpu_has(c
, X86_FEATURE_CX8
);
331 cpu
->flags
.apic
=cpu_has(c
, X86_FEATURE_APIC
);
332 cpu
->flags
.sep
=cpu_has(c
, X86_FEATURE_SEP
);
333 cpu
->flags
.mtrr
=cpu_has(c
, X86_FEATURE_MTRR
);
334 cpu
->flags
.pge
=cpu_has(c
, X86_FEATURE_PGE
);
335 cpu
->flags
.mca
=cpu_has(c
, X86_FEATURE_MCA
);
336 cpu
->flags
.cmov
=cpu_has(c
, X86_FEATURE_CMOV
);
337 cpu
->flags
.pat
=cpu_has(c
, X86_FEATURE_PAT
);
338 cpu
->flags
.pse_36
=cpu_has(c
, X86_FEATURE_PSE36
);
339 cpu
->flags
.psn
=cpu_has(c
, X86_FEATURE_PN
);
340 cpu
->flags
.clflsh
=cpu_has(c
, X86_FEATURE_CLFLSH
);
341 cpu
->flags
.dts
=cpu_has(c
, X86_FEATURE_DTES
);
342 cpu
->flags
.acpi
=cpu_has(c
, X86_FEATURE_ACPI
);
343 cpu
->flags
.mmx
=cpu_has(c
, X86_FEATURE_MMX
);
344 cpu
->flags
.fxsr
=cpu_has(c
, X86_FEATURE_FXSR
);
345 cpu
->flags
.sse
=cpu_has(c
, X86_FEATURE_XMM
);
346 cpu
->flags
.sse2
=cpu_has(c
, X86_FEATURE_XMM2
);
347 cpu
->flags
.ss
=cpu_has(c
, X86_FEATURE_SELFSNOOP
);
348 cpu
->flags
.htt
=cpu_has(c
, X86_FEATURE_HT
);
349 cpu
->flags
.acc
=cpu_has(c
, X86_FEATURE_ACC
);
350 cpu
->flags
.syscall
=cpu_has(c
, X86_FEATURE_SYSCALL
);
351 cpu
->flags
.mp
=cpu_has(c
, X86_FEATURE_MP
);
352 cpu
->flags
.nx
=cpu_has(c
, X86_FEATURE_NX
);
353 cpu
->flags
.mmxext
=cpu_has(c
, X86_FEATURE_MMXEXT
);
354 cpu
->flags
.lm
=cpu_has(c
, X86_FEATURE_LM
);
355 cpu
->flags
.nowext
=cpu_has(c
, X86_FEATURE_3DNOWEXT
);
356 cpu
->flags
.now
=cpu_has(c
, X86_FEATURE_3DNOW
);
357 cpu
->flags
.smp
= find_smp_config();
360 void set_generic_info(struct cpuinfo_x86
*c
,s_cpu
*cpu
) {
362 cpu
->vendor_id
=c
->x86_vendor
;
363 cpu
->model_id
=c
->x86_model
;
364 cpu
->stepping
=c
->x86_mask
;
365 strncpy(cpu
->vendor
,cpu_devs
[c
->x86_vendor
]->c_vendor
,CPU_VENDOR_SIZE
);
366 strncpy(cpu
->model
,c
->x86_model_id
,CPU_MODEL_SIZE
);
369 void detect_cpu(s_cpu
*cpu
)
371 struct cpuinfo_x86 c
;
372 c
.x86_cache_alignment
= 32;
373 c
.x86_cache_size
= -1;
374 c
.x86_vendor
= X86_VENDOR_UNKNOWN
;
375 c
.cpuid_level
= -1; /* CPUID not detected */
376 c
.x86_model
= c
.x86_mask
= 0; /* So far unknown... */
377 c
.x86_vendor_id
[0] = '\0'; /* Unset */
378 c
.x86_model_id
[0] = '\0'; /* Unset */
379 memset(&c
.x86_vendor_id
,'\0',CPU_VENDOR_SIZE
);
384 generic_identify(&c
);
385 set_generic_info(&c
,cpu
);
386 set_cpu_flags(&c
,cpu
);