1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
/* Helper file for i386 platform. Runtime check for MMX/SSE/SSE2 support.
Used by 20020523-2.c and i386-sse-6.c, and possibly others. */
/* Plagarized from 20020523-2.c. */
/* %ecx */
#define bit_SSE3 (1 << 0)
#define bit_SSSE3 (1 << 9)
/* %edx */
#define bit_CMOV (1 << 15)
#define bit_MMX (1 << 23)
#define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26)
/* Extended Features */
/* %ecx */
#define bit_SSE4a (1 << 6)
#ifndef NOINLINE
#define NOINLINE __attribute__ ((noinline))
#endif
static inline unsigned int
i386_get_cpuid (unsigned int *ecx, unsigned int *edx)
{
int fl1;
#ifndef __x86_64__
int fl2;
/* See if we can use cpuid. On AMD64 we always can. */
__asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
"pushl %0; popfl; pushfl; popl %0; popfl"
: "=&r" (fl1), "=&r" (fl2)
: "i" (0x00200000));
if (((fl1 ^ fl2) & 0x00200000) == 0)
return (0);
#endif
/* Host supports cpuid. See if cpuid gives capabilities, try
CPUID(0). Preserve %ebx and %ecx; cpuid insn clobbers these, we
don't need their CPUID values here, and %ebx may be the PIC
register. */
#ifdef __x86_64__
__asm__ ("pushq %%rcx; pushq %%rbx; cpuid; popq %%rbx; popq %%rcx"
: "=a" (fl1) : "0" (0) : "rdx", "cc");
#else
__asm__ ("pushl %%ecx; pushl %%ebx; cpuid; popl %%ebx; popl %%ecx"
: "=a" (fl1) : "0" (0) : "edx", "cc");
#endif
if (fl1 == 0)
return (0);
/* Invoke CPUID(1), return %ecx and %edx; caller can examine bits to
determine what's supported. */
#ifdef __x86_64__
__asm__ ("pushq %%rbx; cpuid; popq %%rbx"
: "=c" (*ecx), "=d" (*edx), "=a" (fl1) : "2" (1) : "cc");
#else
__asm__ ("pushl %%ebx; cpuid; popl %%ebx"
: "=c" (*ecx), "=d" (*edx), "=a" (fl1) : "2" (1) : "cc");
#endif
return 1;
}
static inline unsigned int
i386_get_extended_cpuid (unsigned int *ecx, unsigned int *edx)
{
int fl1;
if (!(i386_get_cpuid (ecx, edx)))
return 0;
/* Invoke CPUID(0x80000000) to get the highest supported extended function
number */
#ifdef __x86_64__
__asm__ ("cpuid"
: "=a" (fl1) : "0" (0x80000000) : "edx", "ecx", "ebx");
#else
__asm__ ("pushl %%ebx; cpuid; popl %%ebx"
: "=a" (fl1) : "0" (0x80000000) : "edx", "ecx");
#endif
/* Check if highest supported extended function used below are supported */
if (fl1 < 0x80000001)
return 0;
/* Invoke CPUID(0x80000001), return %ecx and %edx; caller can examine bits to
determine what's supported. */
#ifdef __x86_64__
__asm__ ("cpuid"
: "=c" (*ecx), "=d" (*edx), "=a" (fl1) : "2" (0x80000001) : "ebx");
#else
__asm__ ("pushl %%ebx; cpuid; popl %%ebx"
: "=c" (*ecx), "=d" (*edx), "=a" (fl1) : "2" (0x80000001));
#endif
return 1;
}
unsigned int i386_cpuid_ecx (void) NOINLINE;
unsigned int i386_cpuid_edx (void) NOINLINE;
unsigned int i386_extended_cpuid_ecx (void) NOINLINE;
unsigned int i386_extended_cpuid_edx (void) NOINLINE;
unsigned int NOINLINE
i386_cpuid_ecx (void)
{
unsigned int ecx, edx;
if (i386_get_cpuid (&ecx, &edx))
return ecx;
else
return 0;
}
unsigned int NOINLINE
i386_cpuid_edx (void)
{
unsigned int ecx, edx;
if (i386_get_cpuid (&ecx, &edx))
return edx;
else
return 0;
}
unsigned int NOINLINE
i386_extended_cpuid_ecx (void)
{
unsigned int ecx, edx;
if (i386_get_extended_cpuid (&ecx, &edx))
return ecx;
else
return 0;
}
unsigned int NOINLINE
i386_extended_cpuid_edx (void)
{
unsigned int ecx, edx;
if (i386_get_extended_cpuid (&ecx, &edx))
return edx;
else
return 0;
}
static inline unsigned int
i386_cpuid (void)
{
return i386_cpuid_edx ();
}
|