7 // This file determines x86/AMD64 features a processor supports.
10 // - 0 if the machine has the asked-for feature.
11 // - 1 if the machine doesn't have the asked-for feature.
12 // - 2 if the asked-for feature isn't recognised (this will be the case for
13 // any feature if run on a non-x86/AMD64 machine).
14 // - 3 if there was a usage error (it also prints an error message).
16 #define FEATURE_PRESENT 0
17 #define FEATURE_NOT_PRESENT 1
18 #define UNRECOGNISED_FEATURE 2
27 #if defined(VGA_x86) || defined(VGA_amd64)
28 static void cpuid ( unsigned int n
, unsigned int m
,
29 unsigned int* a
, unsigned int* b
,
30 unsigned int* c
, unsigned int* d
)
32 __asm__
__volatile__ (
34 : "=a" (*a
), "=b" (*b
), "=c" (*c
), "=d" (*d
) /* output */
35 : "0" (n
), "2" (m
) /* input */
39 static Bool
vendorStringEquals ( char* str
)
42 unsigned int a
, b
, c
, d
;
43 cpuid(0, 0, &a
, &b
, &c
, &d
);
44 memcpy(&vstr
[0], &b
, 4);
45 memcpy(&vstr
[4], &d
, 4);
46 memcpy(&vstr
[8], &c
, 4);
48 return 0 == strcmp(vstr
, str
);
51 static Bool
have_xgetbv ( void )
53 #if defined(VGA_amd64)
54 unsigned long long int w
;
55 __asm__
__volatile__("movq $0,%%rcx ; "
56 ".byte 0x0F,0x01,0xD0 ; " /* xgetbv */
58 :/*OUT*/"=r"(w
) :/*IN*/
59 :/*TRASH*/"rdx","rcx");
61 /* OS has enabled both XMM and YMM state support */
71 static Bool
go(char* cpu
)
73 unsigned int level
= 0, sublevel
= 0;
74 unsigned int amask
= 0, bmask
= 0, cmask
= 0, dmask
= 0;
75 unsigned int a
, b
, c
, d
;
76 Bool require_amd
= False
;
77 Bool require_xgetbv
= False
;
78 if ( strcmp( cpu
, "x86-fpu" ) == 0 ) {
81 } else if ( strcmp( cpu
, "x86-cmov" ) == 0 ) {
84 } else if ( strcmp( cpu
, "x86-mmx" ) == 0 ) {
87 } else if ( strcmp( cpu
, "x86-mmxext" ) == 0 ) {
90 } else if ( strcmp( cpu
, "x86-sse" ) == 0 ) {
93 } else if ( strcmp( cpu
, "x86-sse2" ) == 0 ) {
96 } else if ( strcmp( cpu
, "x86-sse3" ) == 0 ) {
99 } else if ( strcmp( cpu
, "x86-ssse3" ) == 0 ) {
102 } else if ( strcmp( cpu
, "x86-lzcnt" ) == 0 ) {
106 #if defined(VGA_amd64)
107 } else if ( strcmp( cpu
, "amd64-sse3" ) == 0 ) {
110 } else if ( strcmp( cpu
, "amd64-pclmulqdq" ) == 0 ) {
113 } else if ( strcmp( cpu
, "amd64-ssse3" ) == 0 ) {
116 } else if ( strcmp( cpu
, "amd64-cx16" ) == 0 ) {
119 } else if ( strcmp( cpu
, "amd64-lzcnt" ) == 0 ) {
123 } else if ( strcmp( cpu
, "amd64-sse42" ) == 0 ) {
126 } else if ( strcmp( cpu
, "amd64-avx" ) == 0 ) {
128 cmask
= (1 << 27) | (1 << 28);
129 require_xgetbv
= True
;
130 } else if (strcmp (cpu
, "amd64-fma4" ) == 0) {
134 } else if (strcmp (cpu
, "amd64-f16c" ) == 0) {
137 } else if (strcmp (cpu
, "amd64-rdrand" ) == 0) {
140 } else if (strcmp (cpu
, "amd64-rdseed" ) == 0) {
145 return UNRECOGNISED_FEATURE
;
148 assert( !(cmask
!= 0 && dmask
!= 0 && bmask
!= 0) );
149 assert( !(cmask
== 0 && dmask
== 0 && bmask
== 0) );
151 if (require_amd
&& !vendorStringEquals("AuthenticAMD"))
152 return FEATURE_NOT_PRESENT
;
153 // regardless of what that feature actually is
155 cpuid( level
& 0x80000000, 0, &a
, &b
, &c
, &d
);
158 cpuid( level
, sublevel
, &a
, &b
, &c
, &d
);
160 if (amask
> 0 && (a
& amask
) == amask
)
161 return FEATURE_PRESENT
;
163 if (bmask
> 0 && (b
& bmask
) == bmask
)
164 return FEATURE_PRESENT
;
166 if (dmask
> 0 && (d
& dmask
) == dmask
) {
167 if (require_xgetbv
&& !have_xgetbv())
168 return FEATURE_NOT_PRESENT
;
170 return FEATURE_PRESENT
;
172 if (cmask
> 0 && (c
& cmask
) == cmask
) {
173 if (require_xgetbv
&& !have_xgetbv())
174 return FEATURE_NOT_PRESENT
;
176 return FEATURE_PRESENT
;
179 return FEATURE_NOT_PRESENT
;
184 static Bool
go(char* cpu
)
186 // Feature not recognised (non-x86/AMD64 machine!)
187 return UNRECOGNISED_FEATURE
;
190 #endif // defined(VGA_x86) || defined(VGA_amd64)
193 //---------------------------------------------------------------------------
195 //---------------------------------------------------------------------------
196 int main(int argc
, char **argv
)
199 fprintf( stderr
, "usage: x86_amd64_features <feature>\n" );