32
32
33
33
#include "include/ia32.h"
34
34
35
+ #define CPUID_CACHE_SIZE 6
36
+
37
+ typedef struct cpuid_cache_t {
38
+ uint32_t data [CPUID_CACHE_SIZE ]; // Host cached features
39
+ cpuid_t host_supported ; // Physical CPU supported features
40
+ cpuid_t hax_supported ; // Hypervisor supported features
41
+ bool initialized ;
42
+ } cpuid_cache_t ;
43
+
35
44
typedef union cpuid_feature_t {
36
45
struct {
37
46
uint32_t index : 5 ;
@@ -46,6 +55,14 @@ typedef union cpuid_feature_t {
46
55
uint32_t value ;
47
56
} cpuid_feature_t ;
48
57
58
+ static cpuid_cache_t cache = {0 };
59
+
60
+ static hax_cpuid_entry * find_cpuid_entry (hax_cpuid * cpuid_info ,
61
+ uint32_t function , uint32_t index );
62
+ static void cpuid_set_0000_0001 (cpuid_t * cpuid , hax_cpuid * cpuid_info );
63
+ static void cpuid_set_8000_0001 (cpuid_t * cpuid , hax_cpuid * cpuid_info );
64
+ static void cpuid_set_fixed_features (cpuid_t * cpuid );
65
+
49
66
void cpuid_query_leaf (cpuid_args_t * args , uint32_t leaf )
50
67
{
51
68
args -> eax = leaf ;
@@ -59,10 +76,10 @@ void cpuid_query_subleaf(cpuid_args_t *args, uint32_t leaf, uint32_t subleaf)
59
76
asm_cpuid (args );
60
77
}
61
78
62
- void cpuid_host_init (cpuid_cache_t * cache )
79
+ void cpuid_host_init (void )
63
80
{
64
81
cpuid_args_t res ;
65
- uint32_t * data = cache -> data ;
82
+ uint32_t * data = cache . data ;
66
83
67
84
cpuid_query_leaf (& res , 0x00000001 );
68
85
data [0 ] = res .ecx ;
@@ -76,19 +93,19 @@ void cpuid_host_init(cpuid_cache_t *cache)
76
93
data [4 ] = res .ecx ;
77
94
data [5 ] = res .edx ;
78
95
79
- cache -> initialized = 1 ;
96
+ cache . initialized = true ;
80
97
}
81
98
82
- bool cpuid_host_has_feature (cpuid_cache_t * cache , uint32_t feature_key )
99
+ bool cpuid_host_has_feature (uint32_t feature_key )
83
100
{
84
101
cpuid_feature_t feature ;
85
102
uint32_t value ;
86
103
87
104
feature .value = feature_key ;
88
- if (!cache -> initialized || feature .index >= CPUID_CACHE_SIZE ) {
105
+ if (!cache . initialized || feature .index >= CPUID_CACHE_SIZE ) {
89
106
return cpuid_host_has_feature_uncached (feature_key );
90
107
}
91
- value = cache -> data [feature .index ];
108
+ value = cache . data [feature .index ];
92
109
if (value & (1 << feature .bit )) {
93
110
return true;
94
111
}
@@ -114,3 +131,235 @@ bool cpuid_host_has_feature_uncached(uint32_t feature_key)
114
131
}
115
132
return false;
116
133
}
134
+
135
+ void cpuid_init_supported_features (void )
136
+ {
137
+ uint32_t bit , flag , function , x86_feature ;
138
+
139
+ // Initialize host supported features
140
+ for (bit = 0 ; bit < sizeof (uint32_t ) * 8 ; ++ bit ) {
141
+ flag = 1 << bit ;
142
+
143
+ function = 0x01 ;
144
+ x86_feature = FEATURE_KEY_LEAF (0 , function , CPUID_REG_ECX , bit );
145
+ if (cpuid_host_has_feature (x86_feature )) {
146
+ cache .host_supported .feature_1_ecx |= flag ;
147
+ }
148
+
149
+ x86_feature = FEATURE_KEY_LEAF (1 , function , CPUID_REG_EDX , bit );
150
+ if (cpuid_host_has_feature (x86_feature )) {
151
+ cache .host_supported .feature_1_edx |= flag ;
152
+ }
153
+
154
+ function = 0x80000001 ;
155
+ x86_feature = FEATURE_KEY_LEAF (5 , function , CPUID_REG_EDX , bit );
156
+ if (cpuid_host_has_feature (x86_feature )) {
157
+ cache .host_supported .feature_8000_0001_edx |= flag ;
158
+ }
159
+ }
160
+
161
+ hax_log (HAX_LOGI , "%s: host supported features:\n" , __func__ );
162
+ hax_log (HAX_LOGI , "feature_1_ecx: %08lx, feature_1_edx: %08lx\n" ,
163
+ cache .host_supported .feature_1_ecx ,
164
+ cache .host_supported .feature_1_edx );
165
+ hax_log (HAX_LOGI , "feature_8000_0001_ecx: %08lx, "
166
+ "feature_8000_0001_edx: %08lx\n" ,
167
+ cache .host_supported .feature_8000_0001_ecx ,
168
+ cache .host_supported .feature_8000_0001_edx );
169
+
170
+ // Initialize HAXM supported features
171
+ cache .hax_supported = (cpuid_t ){
172
+ .feature_1_ecx =
173
+ FEATURE (SSE3 ) |
174
+ FEATURE (SSSE3 ) |
175
+ FEATURE (SSE41 ) |
176
+ FEATURE (SSE42 ) |
177
+ FEATURE (CMPXCHG16B ) |
178
+ FEATURE (MOVBE ) |
179
+ FEATURE (AESNI ) |
180
+ FEATURE (PCLMULQDQ ) |
181
+ FEATURE (POPCNT ),
182
+ .feature_1_edx =
183
+ FEATURE (PAT ) |
184
+ FEATURE (FPU ) |
185
+ FEATURE (VME ) |
186
+ FEATURE (DE ) |
187
+ FEATURE (TSC ) |
188
+ FEATURE (MSR ) |
189
+ FEATURE (PAE ) |
190
+ FEATURE (MCE ) |
191
+ FEATURE (CX8 ) |
192
+ FEATURE (APIC ) |
193
+ FEATURE (SEP ) |
194
+ FEATURE (MTRR ) |
195
+ FEATURE (PGE ) |
196
+ FEATURE (MCA ) |
197
+ FEATURE (CMOV ) |
198
+ FEATURE (CLFSH ) |
199
+ FEATURE (MMX ) |
200
+ FEATURE (FXSR ) |
201
+ FEATURE (SSE ) |
202
+ FEATURE (SSE2 ) |
203
+ FEATURE (SS ) |
204
+ FEATURE (PSE ) |
205
+ FEATURE (HTT ),
206
+ .feature_8000_0001_ecx = 0 ,
207
+ .feature_8000_0001_edx =
208
+ FEATURE (NX ) |
209
+ FEATURE (SYSCALL ) |
210
+ FEATURE (RDTSCP ) |
211
+ FEATURE (EM64T )
212
+ };
213
+
214
+ hax_log (HAX_LOGI , "%s: HAXM supported features:\n" , __func__ );
215
+ hax_log (HAX_LOGI , "feature_1_ecx: %08lx, feature_1_edx: %08lx\n" ,
216
+ cache .hax_supported .feature_1_ecx ,
217
+ cache .hax_supported .feature_1_edx );
218
+ hax_log (HAX_LOGI , "feature_8000_0001_ecx: %08lx, "
219
+ "feature_8000_0001_edx: %08lx\n" ,
220
+ cache .hax_supported .feature_8000_0001_ecx ,
221
+ cache .hax_supported .feature_8000_0001_edx );
222
+ }
223
+
224
+ void cpuid_guest_init (cpuid_t * cpuid )
225
+ {
226
+ * cpuid = cache .hax_supported ;
227
+ cpuid -> features_mask = ~0ULL ;
228
+ }
229
+
230
+ void cpuid_get_features_mask (cpuid_t * cpuid , uint64_t * features_mask )
231
+ {
232
+ * features_mask = cpuid -> features_mask ;
233
+ }
234
+
235
+ void cpuid_set_features_mask (cpuid_t * cpuid , uint64_t features_mask )
236
+ {
237
+ cpuid -> features_mask = features_mask ;
238
+ }
239
+
240
+ void cpuid_get_guest_features (cpuid_t * cpuid , uint32_t * cpuid_1_features_ecx ,
241
+ uint32_t * cpuid_1_features_edx ,
242
+ uint32_t * cpuid_8000_0001_features_ecx ,
243
+ uint32_t * cpuid_8000_0001_features_edx )
244
+ {
245
+ * cpuid_1_features_ecx = cpuid -> feature_1_ecx ;
246
+ * cpuid_1_features_edx = cpuid -> feature_1_edx ;
247
+ * cpuid_8000_0001_features_ecx = cpuid -> feature_8000_0001_ecx ;
248
+ * cpuid_8000_0001_features_edx = cpuid -> feature_8000_0001_edx ;
249
+ }
250
+
251
+ void cpuid_set_guest_features (cpuid_t * cpuid , hax_cpuid * cpuid_info )
252
+ {
253
+ static void (* cpuid_set_guest_feature [])(cpuid_t * , hax_cpuid * ) = {
254
+ cpuid_set_0000_0001 ,
255
+ cpuid_set_8000_0001
256
+ };
257
+ static size_t count = sizeof (cpuid_set_guest_feature ) /
258
+ sizeof (cpuid_set_guest_feature [0 ]);
259
+ int i ;
260
+
261
+ hax_log (HAX_LOGI , "%s: before:\n" , __func__ );
262
+ hax_log (HAX_LOGI , "feature_1_ecx: %08lx, feature_1_edx: %08lx\n" ,
263
+ cpuid -> feature_1_ecx , cpuid -> feature_1_edx );
264
+ hax_log (HAX_LOGI , "feature_8000_0001_ecx: %08lx, feature_8000_0001_edx: %08lx"
265
+ "\n" , cpuid -> feature_8000_0001_ecx , cpuid -> feature_8000_0001_edx );
266
+
267
+ for (i = 0 ; i < count ; ++ i ) {
268
+ cpuid_set_guest_feature [i ](cpuid , cpuid_info );
269
+ }
270
+
271
+ hax_log (HAX_LOGI , "%s: after:\n" , __func__ );
272
+ hax_log (HAX_LOGI , "feature_1_ecx: %08lx, feature_1_edx: %08lx\n" ,
273
+ cpuid -> feature_1_ecx , cpuid -> feature_1_edx );
274
+ hax_log (HAX_LOGI , "feature_8000_0001_ecx: %08lx, feature_8000_0001_edx: %08lx"
275
+ "\n" , cpuid -> feature_8000_0001_ecx , cpuid -> feature_8000_0001_edx );
276
+ }
277
+
278
+ static hax_cpuid_entry * find_cpuid_entry (hax_cpuid * cpuid_info ,
279
+ uint32_t function , uint32_t index )
280
+ {
281
+ int i ;
282
+ hax_cpuid_entry * entry , * found = NULL ;
283
+
284
+ for (i = 0 ; i < cpuid_info -> total ; ++ i ) {
285
+ entry = & cpuid_info -> entries [i ];
286
+ if (entry -> function == function && entry -> index == index ) {
287
+ found = entry ;
288
+ break ;
289
+ }
290
+ }
291
+
292
+ return found ;
293
+ }
294
+
295
+ static void cpuid_set_0000_0001 (cpuid_t * cpuid , hax_cpuid * cpuid_info )
296
+ {
297
+ const uint32_t kFunction = 0x01 ;
298
+ hax_cpuid_entry * entry ;
299
+
300
+ entry = find_cpuid_entry (cpuid_info , kFunction , 0 );
301
+ if (entry == NULL )
302
+ return ;
303
+
304
+ hax_log (HAX_LOGI , "%s: function: %08lx, index: %lu, flags: %08lx\n" ,
305
+ __func__ , entry -> function , entry -> index , entry -> flags );
306
+ hax_log (HAX_LOGI , "%s: eax: %08lx, ebx: %08lx, ecx: %08lx, edx: %08lx\n" ,
307
+ __func__ , entry -> eax , entry -> ebx , entry -> ecx , entry -> edx );
308
+
309
+ cpuid -> feature_1_ecx = entry -> ecx ;
310
+ cpuid -> feature_1_edx = entry -> edx ;
311
+
312
+ // Filter the unsupported features
313
+ cpuid -> feature_1_ecx &= cache .host_supported .feature_1_ecx &
314
+ cache .hax_supported .feature_1_ecx ;
315
+ cpuid -> feature_1_edx &= cache .host_supported .feature_1_edx &
316
+ cache .hax_supported .feature_1_edx ;
317
+
318
+ // Set fixed supported features
319
+ cpuid_set_fixed_features (cpuid );
320
+
321
+ if (entry -> ecx != cpuid -> feature_1_ecx ||
322
+ entry -> edx != cpuid -> feature_1_edx ) {
323
+ hax_log (HAX_LOGW , "%s: filtered or unchanged flags: ecx: %08lx, "
324
+ "edx: %08lx\n" , __func__ , entry -> ecx ^ cpuid -> feature_1_ecx ,
325
+ entry -> edx ^ cpuid -> feature_1_edx );
326
+ }
327
+ }
328
+
329
+ static void cpuid_set_8000_0001 (cpuid_t * cpuid , hax_cpuid * cpuid_info )
330
+ {
331
+ const uint32_t kFunction = 0x80000001 ;
332
+ hax_cpuid_entry * entry ;
333
+
334
+ entry = find_cpuid_entry (cpuid_info , kFunction , 0 );
335
+ if (entry == NULL )
336
+ return ;
337
+
338
+ hax_log (HAX_LOGI , "%s: function: %08lx, index: %lu, flags: %08lx\n" ,
339
+ __func__ , entry -> function , entry -> index , entry -> flags );
340
+ hax_log (HAX_LOGI , "%s: eax: %08lx, ebx: %08lx, ecx: %08lx, edx: %08lx\n" ,
341
+ __func__ , entry -> eax , entry -> ebx , entry -> ecx , entry -> edx );
342
+
343
+ cpuid -> feature_8000_0001_edx = entry -> edx ;
344
+
345
+ // Filter the unsupported features
346
+ cpuid -> feature_8000_0001_edx &=
347
+ cache .host_supported .feature_8000_0001_edx &
348
+ cache .hax_supported .feature_8000_0001_edx ;
349
+
350
+ if (entry -> edx != cpuid -> feature_8000_0001_edx ) {
351
+ hax_log (HAX_LOGW , "%s: filtered or unchanged flags: edx: %08lx\n" ,
352
+ __func__ , entry -> edx ^ cpuid -> feature_8000_0001_edx );
353
+ }
354
+ }
355
+
356
+ static void cpuid_set_fixed_features (cpuid_t * cpuid )
357
+ {
358
+ const uint32_t kFixedFeatures =
359
+ FEATURE (MCE ) |
360
+ FEATURE (APIC ) |
361
+ FEATURE (MTRR ) |
362
+ FEATURE (PAT );
363
+
364
+ cpuid -> feature_1_edx |= kFixedFeatures ;
365
+ }
0 commit comments