Browse Source

[cpuid] Provide cpuid_supported() to test for supported functions

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
d37e025b81

+ 61
- 29
src/arch/x86/core/cpuid.c View File

@@ -24,6 +24,7 @@
24 24
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 25
 
26 26
 #include <string.h>
27
+#include <errno.h>
27 28
 #include <ipxe/cpuid.h>
28 29
 
29 30
 /** @file
@@ -32,15 +33,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32 33
  *
33 34
  */
34 35
 
36
+/** Colour for debug messages */
37
+#define colour 0x861d
38
+
35 39
 /**
36 40
  * Check whether or not CPUID instruction is supported
37 41
  *
38
- * @ret is_supported	CPUID instruction is supported
42
+ * @ret rc		Return status code
39 43
  */
40
-int cpuid_is_supported ( void ) {
44
+static int cpuid_instruction_supported ( void ) {
41 45
 	unsigned long original;
42 46
 	unsigned long inverted;
43 47
 
48
+	/* Check for instruction existence via flag modifiability */
44 49
 	__asm__ ( "pushf\n\t"
45 50
 		  "pushf\n\t"
46 51
 		  "pop %0\n\t"
@@ -53,7 +58,54 @@ int cpuid_is_supported ( void ) {
53 58
 		  "popf\n\t"
54 59
 		  : "=&r" ( original ), "=&r" ( inverted )
55 60
 		  : "ir" ( CPUID_FLAG ) );
56
-	return ( ( original ^ inverted ) & CPUID_FLAG );
61
+	if ( ! ( ( original ^ inverted ) & CPUID_FLAG ) ) {
62
+		DBGC ( colour, "CPUID instruction is not supported\n" );
63
+		return -ENOTSUP;
64
+	}
65
+
66
+	return 0;
67
+}
68
+
69
+/**
70
+ * Check whether or not CPUID function is supported
71
+ *
72
+ * @v function		CPUID function
73
+ * @ret rc		Return status code
74
+ */
75
+int cpuid_supported ( uint32_t function ) {
76
+	uint32_t max_function;
77
+	uint32_t discard_b;
78
+	uint32_t discard_c;
79
+	uint32_t discard_d;
80
+	int rc;
81
+
82
+	/* Check that CPUID instruction is available */
83
+	if ( ( rc = cpuid_instruction_supported() ) != 0 )
84
+		return rc;
85
+
86
+	/* Find highest supported function number within this family */
87
+	cpuid ( ( function & CPUID_EXTENDED ), &max_function, &discard_b,
88
+		&discard_c, &discard_d );
89
+
90
+	/* Fail if maximum function number is meaningless (e.g. if we
91
+	 * are attempting to call an extended function on a CPU which
92
+	 * does not support them).
93
+	 */
94
+	if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
95
+	     ( function & CPUID_AMD_CHECK_MASK ) ) {
96
+		DBGC ( colour, "CPUID invalid maximum function %#08x\n",
97
+		       max_function );
98
+		return -EINVAL;
99
+	}
100
+
101
+	/* Fail if this function is not supported */
102
+	if ( function > max_function ) {
103
+		DBGC ( colour, "CPUID function %#08x not supported\n",
104
+		       function );
105
+		return -ENOTTY;
106
+	}
107
+
108
+	return 0;
57 109
 }
58 110
 
59 111
 /**
@@ -62,18 +114,13 @@ int cpuid_is_supported ( void ) {
62 114
  * @v features		x86 CPU features to fill in
63 115
  */
64 116
 static void x86_intel_features ( struct x86_features *features ) {
65
-	uint32_t max_level;
66 117
 	uint32_t discard_a;
67 118
 	uint32_t discard_b;
68
-	uint32_t discard_c;
69
-	uint32_t discard_d;
119
+	int rc;
70 120
 
71 121
 	/* Check that features are available via CPUID */
72
-	cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
73
-		&discard_d );
74
-	if ( max_level < CPUID_FEATURES ) {
75
-		DBGC ( features, "CPUID has no Intel-defined features (max "
76
-		       "level %08x)\n", max_level );
122
+	if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) {
123
+		DBGC ( features, "CPUID has no Intel-defined features\n" );
77 124
 		return;
78 125
 	}
79 126
 
@@ -91,22 +138,13 @@ static void x86_intel_features ( struct x86_features *features ) {
91 138
  * @v features		x86 CPU features to fill in
92 139
  */
93 140
 static void x86_amd_features ( struct x86_features *features ) {
94
-	uint32_t max_level;
95 141
 	uint32_t discard_a;
96 142
 	uint32_t discard_b;
97
-	uint32_t discard_c;
98
-	uint32_t discard_d;
143
+	int rc;
99 144
 
100 145
 	/* Check that features are available via CPUID */
101
-	cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
102
-		&discard_d );
103
-	if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
104
-		DBGC ( features, "CPUID has no extended functions\n" );
105
-		return;
106
-	}
107
-	if ( max_level < CPUID_AMD_FEATURES ) {
108
-		DBGC ( features, "CPUID has no AMD-defined features (max "
109
-		       "level %08x)\n", max_level );
146
+	if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) {
147
+		DBGC ( features, "CPUID has no AMD-defined features\n" );
110 148
 		return;
111 149
 	}
112 150
 
@@ -127,12 +165,6 @@ void x86_features ( struct x86_features *features ) {
127 165
 	/* Clear all features */
128 166
 	memset ( features, 0, sizeof ( *features ) );
129 167
 
130
-	/* Check that CPUID instruction is available */
131
-	if ( ! cpuid_is_supported() ) {
132
-		DBGC ( features, "CPUID instruction is not supported\n" );
133
-		return;
134
-	}
135
-
136 168
 	/* Get Intel-defined features */
137 169
 	x86_intel_features ( features );
138 170
 

+ 6
- 29
src/arch/x86/core/cpuid_settings.c View File

@@ -149,48 +149,25 @@ static int cpuid_settings_fetch ( struct settings *settings,
149 149
 				  struct setting *setting,
150 150
 				  void *data, size_t len ) {
151 151
 	uint32_t function;
152
-	uint32_t max_function;
153 152
 	uint32_t num_functions;
154 153
 	uint32_t registers;
155 154
 	uint32_t num_registers;
156 155
 	uint32_t buf[4];
157 156
 	uint32_t output;
158
-	uint32_t discard_b;
159
-	uint32_t discard_c;
160
-	uint32_t discard_d;
161 157
 	size_t frag_len;
162 158
 	size_t result_len = 0;
163
-
164
-	/* Fail unless CPUID is supported */
165
-	if ( ! cpuid_is_supported() ) {
166
-		DBGC ( settings, "CPUID not supported\n" );
167
-		return -ENOTSUP;
168
-	}
169
-
170
-	/* Find highest supported function number within this set */
171
-	function = CPUID_FUNCTION ( setting->tag );
172
-	cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b,
173
-		&discard_c, &discard_d );
174
-
175
-	/* Fail if maximum function number is meaningless (e.g. if we
176
-	 * are attempting to call an extended function on a CPU which
177
-	 * does not support them).
178
-	 */
179
-	if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
180
-	     ( function & CPUID_AMD_CHECK_MASK ) ) {
181
-		DBGC ( settings, "CPUID invalid maximum function\n" );
182
-		return -ENOTSUP;
183
-	}
159
+	int rc;
184 160
 
185 161
 	/* Call each function in turn */
162
+	function = CPUID_FUNCTION ( setting->tag );
186 163
 	num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
187 164
 	for ( ; num_functions-- ; function++ ) {
188 165
 
189 166
 		/* Fail if this function is not supported */
190
-		if ( function > max_function ) {
191
-			DBGC ( settings, "CPUID function %#08x not supported\n",
192
-			       function );
193
-			return -ENOTSUP;
167
+		if ( ( rc = cpuid_supported ( function ) ) != 0 ) {
168
+			DBGC ( settings, "CPUID function %#08x not supported: "
169
+			       "%s\n", function, strerror ( rc ) );
170
+			return rc;
194 171
 		}
195 172
 
196 173
 		/* Issue CPUID */

+ 1
- 0
src/arch/x86/include/bits/errfile.h View File

@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 25
 #define ERRFILE_gdbmach		( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
26 26
 #define ERRFILE_rtc_entropy	( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
27 27
 #define ERRFILE_acpipwr		( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
28
+#define ERRFILE_cpuid		( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
28 29
 
29 30
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
30 31
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

+ 4
- 4
src/arch/x86/include/ipxe/cpuid.h View File

@@ -60,22 +60,22 @@ struct x86_features {
60 60
 /**
61 61
  * Issue CPUID instruction
62 62
  *
63
- * @v operation		CPUID operation
63
+ * @v function		CPUID function
64 64
  * @v eax		Output via %eax
65 65
  * @v ebx		Output via %ebx
66 66
  * @v ecx		Output via %ecx
67 67
  * @v edx		Output via %edx
68 68
  */
69 69
 static inline __attribute__ (( always_inline )) void
70
-cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
70
+cpuid ( uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
71 71
 	uint32_t *edx ) {
72 72
 
73 73
 	__asm__ ( "cpuid"
74 74
 		  : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
75
-		  : "0" ( operation ) );
75
+		  : "0" ( function ) );
76 76
 }
77 77
 
78
-extern int cpuid_is_supported ( void );
78
+extern int cpuid_supported ( uint32_t function );
79 79
 extern void x86_features ( struct x86_features *features );
80 80
 
81 81
 #endif /* _IPXE_CPUID_H */

Loading…
Cancel
Save