3232
3333#include "include/ia32.h"
3434
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+
3544typedef union cpuid_feature_t {
3645 struct {
3746 uint32_t index : 5 ;
@@ -46,6 +55,14 @@ typedef union cpuid_feature_t {
4655 uint32_t value ;
4756} cpuid_feature_t ;
4857
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+
4966void cpuid_query_leaf (cpuid_args_t * args , uint32_t leaf )
5067{
5168 args -> eax = leaf ;
@@ -59,10 +76,10 @@ void cpuid_query_subleaf(cpuid_args_t *args, uint32_t leaf, uint32_t subleaf)
5976 asm_cpuid (args );
6077}
6178
62- void cpuid_host_init (cpuid_cache_t * cache )
79+ void cpuid_host_init (void )
6380{
6481 cpuid_args_t res ;
65- uint32_t * data = cache -> data ;
82+ uint32_t * data = cache . data ;
6683
6784 cpuid_query_leaf (& res , 0x00000001 );
6885 data [0 ] = res .ecx ;
@@ -76,19 +93,19 @@ void cpuid_host_init(cpuid_cache_t *cache)
7693 data [4 ] = res .ecx ;
7794 data [5 ] = res .edx ;
7895
79- cache -> initialized = 1 ;
96+ cache . initialized = true ;
8097}
8198
82- bool cpuid_host_has_feature (cpuid_cache_t * cache , uint32_t feature_key )
99+ bool cpuid_host_has_feature (uint32_t feature_key )
83100{
84101 cpuid_feature_t feature ;
85102 uint32_t value ;
86103
87104 feature .value = feature_key ;
88- if (!cache -> initialized || feature .index >= CPUID_CACHE_SIZE ) {
105+ if (!cache . initialized || feature .index >= CPUID_CACHE_SIZE ) {
89106 return cpuid_host_has_feature_uncached (feature_key );
90107 }
91- value = cache -> data [feature .index ];
108+ value = cache . data [feature .index ];
92109 if (value & (1 << feature .bit )) {
93110 return true;
94111 }
@@ -114,3 +131,235 @@ bool cpuid_host_has_feature_uncached(uint32_t feature_key)
114131 }
115132 return false;
116133}
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