91 lines
2.0 KiB
C
91 lines
2.0 KiB
C
#ifdef CONFIG_X86_64
|
|
#include "stdint.h"
|
|
#include "string.h"
|
|
#include "bits/cpu.h"
|
|
#include "init.h"
|
|
|
|
|
|
/* Standard macro to see if a specific flag is changeable */
|
|
static inline int flag_is_changeable_p(uint32_t flag)
|
|
{
|
|
uint32_t f1, f2;
|
|
|
|
asm("pushfl\n\t"
|
|
"pushfl\n\t"
|
|
"popl %0\n\t"
|
|
"movl %0,%1\n\t"
|
|
"xorl %2,%0\n\t"
|
|
"pushl %0\n\t"
|
|
"popfl\n\t"
|
|
"pushfl\n\t"
|
|
"popl %0\n\t"
|
|
"popfl\n\t"
|
|
: "=&r" (f1), "=&r" (f2)
|
|
: "ir" (flag));
|
|
|
|
return ((f1^f2) & flag) != 0;
|
|
}
|
|
|
|
|
|
/* Probe for the CPUID instruction */
|
|
static inline int have_cpuid_p(void)
|
|
{
|
|
return flag_is_changeable_p(X86_EFLAGS_ID);
|
|
}
|
|
|
|
static void identify_cpu(struct cpuinfo_x86 *c)
|
|
{
|
|
unsigned xlvl;
|
|
|
|
c->cpuid_level = -1; /* CPUID not detected */
|
|
c->x86_model = c->x86_mask = 0; /* So far unknown... */
|
|
c->x86_vendor_id[0] = '\0'; /* Unset */
|
|
memset(&c->x86_capability, 0, sizeof c->x86_capability);
|
|
|
|
if (!have_cpuid_p()) {
|
|
/* CPU doesn'thave CPUID */
|
|
|
|
/* If there are any capabilities, they'r vendor-specific */
|
|
/* enable_cpuid() would have set c->x86 for us. */
|
|
}
|
|
else {
|
|
/* CPU does have CPUID */
|
|
|
|
/* Get vendor name */
|
|
cpuid(0x00000000, &c->cpuid_level,
|
|
(int *)&c->x86_vendor_id[0],
|
|
(int *)&c->x86_vendor_id[8],
|
|
(int *)&c->x86_vendor_id[4]);
|
|
|
|
/* Initialize the standard set of capabilities */
|
|
/* Note that the vendor-specific code below might override */
|
|
|
|
/* Intel-defined flags: level 0x00000001 */
|
|
if ( c->cpuid_level >= 0x00000001 ) {
|
|
unsigned tfms, junk;
|
|
cpuid(0x00000001, &tfms, &junk, &junk,
|
|
&c->x86_capability[0]);
|
|
c->x86 = (tfms >> 8) & 15;
|
|
c->x86_model = (tfms >> 4) & 15;
|
|
c->x86_mask = tfms & 15;
|
|
}
|
|
|
|
/* AMD-defined flags: level 0x80000001 */
|
|
xlvl = cpuid_eax(0x80000000);
|
|
if ( (xlvl & 0xffff0000) == 0x80000000 ) {
|
|
if ( xlvl >= 0x80000001 )
|
|
c->x86_capability[1] = cpuid_edx(0x80000001);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct cpuinfo_x86 cpu_info;
|
|
void cpu_setup(void)
|
|
{
|
|
identify_cpu(&cpu_info);
|
|
}
|
|
|
|
INIT_FN ( INIT_CPU, cpu_setup, NULL, NULL );
|
|
|
|
#endif /* CONFIG_X86_64 */
|