|
@@ -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
|
|