Skip to content
This repository was archived by the owner on Jan 28, 2023. It is now read-only.

Commit 93998a7

Browse files
authored
Merge pull request #277 from intel/cpuid-support
Enable setting CPUID feature for guest VCPUs
2 parents 896c860 + 8f042b0 commit 93998a7

File tree

15 files changed

+597
-77
lines changed

15 files changed

+597
-77
lines changed

core/cpu.c

+1-13
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@
4040
#include "include/intr.h"
4141
#include "include/ept.h"
4242

43-
static cpuid_cache_t cache = {
44-
.initialized = 0
45-
};
46-
4743
static void cpu_vmentry_failed(struct vcpu_t *vcpu, vmx_result_t result);
4844
static int cpu_vmexit_handler(struct vcpu_t *vcpu, exit_reason_t exit_reason,
4945
struct hax_tunnel *htun);
@@ -66,15 +62,7 @@ static int cpu_nx_enable(void)
6662

6763
bool cpu_has_feature(uint32_t feature)
6864
{
69-
if (!cache.initialized) {
70-
cpuid_host_init(&cache);
71-
}
72-
return cpuid_host_has_feature(&cache, feature);
73-
}
74-
75-
void cpu_init_feature_cache(void)
76-
{
77-
cpuid_host_init(&cache);
65+
return cpuid_host_has_feature(feature);
7866
}
7967

8068
void cpu_init_vmx(void *arg)

core/cpuid.c

+255-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
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+
3544
typedef 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+
4966
void 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+
}

core/hax.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ int hax_get_capability(void *buf, int bufLeng, int *outLength)
373373
cap->winfo |= HAX_CAP_TUNNEL_PAGE;
374374
cap->winfo |= HAX_CAP_RAM_PROTECTION;
375375
cap->winfo |= HAX_CAP_DEBUG;
376+
cap->winfo |= HAX_CAP_CPUID;
376377
if (cpu_data->vmx_info._ept_cap) {
377378
cap->winfo |= HAX_CAP_EPT;
378379
}
@@ -565,7 +566,10 @@ int hax_module_init(void)
565566
hax_clear_page(hax_cpu_data[cpu_id]->hstate.hfxpage);
566567
hax_cpu_data[cpu_id]->cpu_id = cpu_id;
567568
}
568-
cpu_init_feature_cache();
569+
570+
cpuid_host_init();
571+
cpuid_init_supported_features();
572+
569573
if (hax_vmx_init() < 0)
570574
goto out_2;
571575

0 commit comments

Comments
 (0)