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

Commit 22dba85

Browse files
authored
Merge pull request #315 from intel/cpuid-opt
cpuid: Optimize CPUID storage structure
2 parents d906fde + 49e9db2 commit 22dba85

File tree

3 files changed

+192
-145
lines changed

3 files changed

+192
-145
lines changed

core/cpuid.c

Lines changed: 179 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,32 @@ typedef union cpuid_feature_t {
5555
uint32_t value;
5656
} cpuid_feature_t;
5757

58+
typedef void (*set_feature_t)(hax_cpuid_entry *, hax_cpuid *, uint32_t);
59+
60+
typedef struct cpuid_set_t {
61+
uint32_t function;
62+
set_feature_t set_feature;
63+
} cpuid_set_t;
64+
5865
static cpuid_cache_t cache = {0};
5966

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(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info);
63-
static void cpuid_set_8000_0001(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info);
64-
static void cpuid_set_fixed_features(hax_cpuid_t *cpuid);
67+
static hax_cpuid_entry * find_cpuid_entry(hax_cpuid_entry *features,
68+
uint32_t size, uint32_t function,
69+
uint32_t index);
70+
static void set_feature(hax_cpuid_entry *features, hax_cpuid *cpuid_info,
71+
uint32_t function);
72+
static void set_feature_0000_0001(hax_cpuid_entry *features,
73+
hax_cpuid *cpuid_info, uint32_t function);
74+
static void cpuid_set_fixed_features(hax_cpuid_entry *features,
75+
uint32_t function);
76+
static void dump_features(hax_cpuid_entry *features, uint32_t size);
77+
static uint32_t get_feature_key_leaf(uint32_t function, uint32_t reg,
78+
uint32_t bit);
79+
80+
static const cpuid_set_t kCpuidSet[CPUID_FEATURE_SET_SIZE] = {
81+
{0x00000001, set_feature_0000_0001},
82+
{0x80000001, set_feature}
83+
};
6584

6685
void cpuid_query_leaf(cpuid_args_t *args, uint32_t leaf)
6786
{
@@ -134,42 +153,41 @@ bool cpuid_host_has_feature_uncached(uint32_t feature_key)
134153

135154
void cpuid_init_supported_features(void)
136155
{
137-
uint32_t bit, flag, function, x86_feature;
156+
uint32_t i, bit, flag, function, x86_feature;
157+
hax_cpuid_entry *host_supported, *hax_supported;
138158

139159
// 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;
160+
host_supported = cache.host_supported.features;
161+
162+
for (i = 0; i < CPUID_FEATURE_SET_SIZE; ++i) {
163+
function = kCpuidSet[i].function;
164+
host_supported[i].function = function;
165+
166+
for (bit = 0; bit < sizeof(uint32_t) * 8; ++bit) {
167+
flag = 1 << bit;
168+
169+
#define SET_FEATURE_FLAG(r, n) \
170+
x86_feature = get_feature_key_leaf(function, (n), bit); \
171+
if (cpuid_host_has_feature(x86_feature)) { \
172+
host_supported[i].r |= flag; \
173+
}
174+
175+
SET_FEATURE_FLAG(eax, CPUID_REG_EAX);
176+
SET_FEATURE_FLAG(ebx, CPUID_REG_EBX);
177+
SET_FEATURE_FLAG(ecx, CPUID_REG_ECX);
178+
SET_FEATURE_FLAG(edx, CPUID_REG_EDX);
179+
#undef SET_FEATURE_FLAG
158180
}
159181
}
160182

161183
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);
184+
dump_features(host_supported, CPUID_FEATURE_SET_SIZE);
169185

170186
// Initialize HAXM supported features
171-
cache.hax_supported = (hax_cpuid_t){
172-
.feature_1_ecx =
187+
hax_supported = cache.hax_supported.features;
188+
hax_supported[0] = (hax_cpuid_entry){
189+
.function = 0x01,
190+
.ecx =
173191
FEATURE(SSE3) |
174192
FEATURE(SSSE3) |
175193
FEATURE(SSE41) |
@@ -179,7 +197,7 @@ void cpuid_init_supported_features(void)
179197
FEATURE(AESNI) |
180198
FEATURE(PCLMULQDQ) |
181199
FEATURE(POPCNT),
182-
.feature_1_edx =
200+
.edx =
183201
FEATURE(PAT) |
184202
FEATURE(FPU) |
185203
FEATURE(VME) |
@@ -202,23 +220,19 @@ void cpuid_init_supported_features(void)
202220
FEATURE(SSE2) |
203221
FEATURE(SS) |
204222
FEATURE(PSE) |
205-
FEATURE(HTT),
206-
.feature_8000_0001_ecx = 0,
207-
.feature_8000_0001_edx =
223+
FEATURE(HTT)
224+
};
225+
hax_supported[1] = (hax_cpuid_entry){
226+
.function = 0x80000001,
227+
.edx =
208228
FEATURE(NX) |
209229
FEATURE(SYSCALL) |
210230
FEATURE(RDTSCP) |
211231
FEATURE(EM64T)
212232
};
213233

214234
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);
235+
dump_features(hax_supported, CPUID_FEATURE_SET_SIZE);
222236
}
223237

224238
void cpuid_guest_init(hax_cpuid_t *cpuid)
@@ -237,130 +251,170 @@ void cpuid_set_features_mask(hax_cpuid_t *cpuid, uint64_t features_mask)
237251
cpuid->features_mask = features_mask;
238252
}
239253

240-
void cpuid_get_guest_features(hax_cpuid_t *cpuid,
241-
uint32_t *cpuid_1_features_ecx,
242-
uint32_t *cpuid_1_features_edx,
243-
uint32_t *cpuid_8000_0001_features_ecx,
244-
uint32_t *cpuid_8000_0001_features_edx)
254+
void cpuid_get_guest_features(hax_cpuid_t *cpuid, hax_cpuid_entry *features)
245255
{
246-
*cpuid_1_features_ecx = cpuid->feature_1_ecx;
247-
*cpuid_1_features_edx = cpuid->feature_1_edx;
248-
*cpuid_8000_0001_features_ecx = cpuid->feature_8000_0001_ecx;
249-
*cpuid_8000_0001_features_edx = cpuid->feature_8000_0001_edx;
256+
hax_cpuid_entry *entry;
257+
258+
if (cpuid == NULL || features == NULL)
259+
return;
260+
261+
entry = find_cpuid_entry(cpuid->features, CPUID_FEATURE_SET_SIZE,
262+
features->function, 0);
263+
if (entry == NULL)
264+
return;
265+
266+
*features = *entry;
250267
}
251268

252269
void cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
253270
{
254-
static void (*cpuid_set_guest_feature[])(hax_cpuid_t *, hax_cpuid *) = {
255-
cpuid_set_0000_0001,
256-
cpuid_set_8000_0001
257-
};
258-
static size_t count = sizeof(cpuid_set_guest_feature) /
259-
sizeof(cpuid_set_guest_feature[0]);
260271
int i;
272+
const cpuid_set_t *kItem;
273+
274+
if (cpuid == NULL || cpuid_info == NULL)
275+
return;
276+
277+
hax_log(HAX_LOGI, "%s: user setting:\n", __func__);
278+
dump_features(cpuid_info->entries, cpuid_info->total);
261279

262280
hax_log(HAX_LOGI, "%s: before:\n", __func__);
263-
hax_log(HAX_LOGI, "feature_1_ecx: %08lx, feature_1_edx: %08lx\n",
264-
cpuid->feature_1_ecx, cpuid->feature_1_edx);
265-
hax_log(HAX_LOGI, "feature_8000_0001_ecx: %08lx, feature_8000_0001_edx: %08lx"
266-
"\n", cpuid->feature_8000_0001_ecx, cpuid->feature_8000_0001_edx);
281+
dump_features(cpuid->features, CPUID_FEATURE_SET_SIZE);
267282

268-
for (i = 0; i < count; ++i) {
269-
cpuid_set_guest_feature[i](cpuid, cpuid_info);
283+
for (i = 0; i < CPUID_FEATURE_SET_SIZE; ++i) {
284+
kItem = &kCpuidSet[i];
285+
kItem->set_feature(cpuid->features, cpuid_info, kItem->function);
270286
}
271287

272288
hax_log(HAX_LOGI, "%s: after:\n", __func__);
273-
hax_log(HAX_LOGI, "feature_1_ecx: %08lx, feature_1_edx: %08lx\n",
274-
cpuid->feature_1_ecx, cpuid->feature_1_edx);
275-
hax_log(HAX_LOGI, "feature_8000_0001_ecx: %08lx, feature_8000_0001_edx: %08lx"
276-
"\n", cpuid->feature_8000_0001_ecx, cpuid->feature_8000_0001_edx);
289+
dump_features(cpuid->features, CPUID_FEATURE_SET_SIZE);
277290
}
278291

279-
static hax_cpuid_entry * find_cpuid_entry(hax_cpuid *cpuid_info,
280-
uint32_t function, uint32_t index)
292+
static hax_cpuid_entry * find_cpuid_entry(hax_cpuid_entry *features,
293+
uint32_t size, uint32_t function,
294+
uint32_t index)
281295
{
282296
int i;
283-
hax_cpuid_entry *entry, *found = NULL;
297+
hax_cpuid_entry *entry;
284298

285-
for (i = 0; i < cpuid_info->total; ++i) {
286-
entry = &cpuid_info->entries[i];
287-
if (entry->function == function && entry->index == index) {
288-
found = entry;
289-
break;
290-
}
299+
if (features == NULL)
300+
return NULL;
301+
302+
for (i = 0; i < size; ++i) {
303+
entry = &features[i];
304+
if (entry->function == function && entry->index == index)
305+
return entry;
291306
}
292307

293-
return found;
308+
return NULL;
294309
}
295310

296-
static void cpuid_set_0000_0001(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
311+
static void set_feature(hax_cpuid_entry *features, hax_cpuid *cpuid_info,
312+
uint32_t function)
297313
{
298-
const uint32_t kFunction = 0x01;
299-
hax_cpuid_entry *entry;
314+
hax_cpuid_entry *dest, *src, *host_supported, *hax_supported;
300315

301-
entry = find_cpuid_entry(cpuid_info, kFunction, 0);
302-
if (entry == NULL)
316+
if (features == NULL || cpuid_info == NULL)
303317
return;
304318

305-
hax_log(HAX_LOGI, "%s: function: %08lx, index: %lu, flags: %08lx\n",
306-
__func__, entry->function, entry->index, entry->flags);
307-
hax_log(HAX_LOGI, "%s: eax: %08lx, ebx: %08lx, ecx: %08lx, edx: %08lx\n",
308-
__func__, entry->eax, entry->ebx, entry->ecx, entry->edx);
319+
dest = find_cpuid_entry(features, CPUID_FEATURE_SET_SIZE, function, 0);
320+
if (dest == NULL)
321+
return;
309322

310-
cpuid->feature_1_ecx = entry->ecx;
311-
cpuid->feature_1_edx = entry->edx;
323+
src = find_cpuid_entry(cpuid_info->entries, cpuid_info->total, function, 0);
324+
if (src == NULL)
325+
return;
312326

313-
// Filter the unsupported features
314-
cpuid->feature_1_ecx &= cache.host_supported.feature_1_ecx &
315-
cache.hax_supported.feature_1_ecx;
316-
cpuid->feature_1_edx &= cache.host_supported.feature_1_edx &
317-
cache.hax_supported.feature_1_edx;
327+
host_supported = find_cpuid_entry(cache.host_supported.features,
328+
CPUID_FEATURE_SET_SIZE, function, 0);
329+
hax_supported = find_cpuid_entry(cache.hax_supported.features,
330+
CPUID_FEATURE_SET_SIZE, function, 0);
318331

319-
// Set fixed supported features
320-
cpuid_set_fixed_features(cpuid);
332+
if (host_supported == NULL || hax_supported == NULL)
333+
return;
321334

322-
if (entry->ecx != cpuid->feature_1_ecx ||
323-
entry->edx != cpuid->feature_1_edx) {
324-
hax_log(HAX_LOGW, "%s: filtered or unchanged flags: ecx: %08lx, "
325-
"edx: %08lx\n", __func__, entry->ecx ^ cpuid->feature_1_ecx,
326-
entry->edx ^ cpuid->feature_1_edx);
327-
}
335+
*dest = *src;
336+
dest->eax &= host_supported->eax & hax_supported->eax;
337+
dest->ebx &= host_supported->ebx & hax_supported->ebx;
338+
dest->ecx &= host_supported->ecx & hax_supported->ecx;
339+
dest->edx &= host_supported->edx & hax_supported->edx;
340+
341+
if (src->eax == dest->eax && src->ebx == dest->ebx &&
342+
src->ecx == dest->ecx && src->edx == dest->edx)
343+
return;
344+
345+
hax_log(HAX_LOGW, "%s: filtered or unchanged flags:\n", __func__);
346+
hax_log(HAX_LOGW, "function: %08lx, eax: %08lx, ebx: %08lx, ecx: %08lx, "
347+
"edx: %08lx\n", function, src->eax ^ dest->eax,
348+
src->ebx ^ dest->ebx, src->ecx ^ dest->ecx, src->edx ^ dest->edx);
349+
}
350+
351+
static void set_feature_0000_0001(hax_cpuid_entry *features,
352+
hax_cpuid *cpuid_info, uint32_t function)
353+
{
354+
if (features == NULL || cpuid_info == NULL)
355+
return;
356+
357+
set_feature(features, cpuid_info, function);
358+
// Set fixed supported features
359+
cpuid_set_fixed_features(features, function);
328360
}
329361

330-
static void cpuid_set_8000_0001(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
362+
static void cpuid_set_fixed_features(hax_cpuid_entry *features,
363+
uint32_t function)
331364
{
332-
const uint32_t kFunction = 0x80000001;
365+
const uint32_t kFixedFeatures =
366+
FEATURE(MCE) |
367+
FEATURE(APIC) |
368+
FEATURE(MTRR) |
369+
FEATURE(PAT);
333370
hax_cpuid_entry *entry;
334371

335-
entry = find_cpuid_entry(cpuid_info, kFunction, 0);
372+
if (features == NULL)
373+
return;
374+
375+
entry = find_cpuid_entry(features, CPUID_FEATURE_SET_SIZE, function, 0);
336376
if (entry == NULL)
337377
return;
338378

339-
hax_log(HAX_LOGI, "%s: function: %08lx, index: %lu, flags: %08lx\n",
340-
__func__, entry->function, entry->index, entry->flags);
341-
hax_log(HAX_LOGI, "%s: eax: %08lx, ebx: %08lx, ecx: %08lx, edx: %08lx\n",
342-
__func__, entry->eax, entry->ebx, entry->ecx, entry->edx);
379+
entry->edx |= kFixedFeatures;
380+
}
343381

344-
cpuid->feature_8000_0001_edx = entry->edx;
382+
static void dump_features(hax_cpuid_entry *features, uint32_t size)
383+
{
384+
int i;
385+
hax_cpuid_entry *entry;
345386

346-
// Filter the unsupported features
347-
cpuid->feature_8000_0001_edx &=
348-
cache.host_supported.feature_8000_0001_edx &
349-
cache.hax_supported.feature_8000_0001_edx;
387+
if (features == NULL)
388+
return;
350389

351-
if (entry->edx != cpuid->feature_8000_0001_edx) {
352-
hax_log(HAX_LOGW, "%s: filtered or unchanged flags: edx: %08lx\n",
353-
__func__, entry->edx ^ cpuid->feature_8000_0001_edx);
390+
for (i = 0; i < size; ++i) {
391+
entry = &features[i];
392+
hax_log(HAX_LOGI, "function: %08lx, index: %lu, flags: %08lx\n",
393+
entry->function, entry->index, entry->flags);
394+
hax_log(HAX_LOGI, "eax: %08lx, ebx: %08lx, ecx: %08lx, edx: %08lx\n",
395+
entry->eax, entry->ebx, entry->ecx, entry->edx);
354396
}
355397
}
356398

357-
static void cpuid_set_fixed_features(hax_cpuid_t *cpuid)
399+
static uint32_t get_feature_key_leaf(uint32_t function, uint32_t reg,
400+
uint32_t bit)
358401
{
359-
const uint32_t kFixedFeatures =
360-
FEATURE(MCE) |
361-
FEATURE(APIC) |
362-
FEATURE(MTRR) |
363-
FEATURE(PAT);
402+
if (function == 0x01) {
403+
if (reg == CPUID_REG_ECX)
404+
return FEATURE_KEY_LEAF(0, function, reg, bit);
405+
406+
if (reg == CPUID_REG_EDX)
407+
return FEATURE_KEY_LEAF(1, function, reg, bit);
408+
409+
return -1;
410+
}
411+
412+
if (function == 0x80000001) {
413+
if (reg == CPUID_REG_EDX)
414+
return FEATURE_KEY_LEAF(5, function, reg, bit);
415+
416+
return -1;
417+
}
364418

365-
cpuid->feature_1_edx |= kFixedFeatures;
419+
return -1;
366420
}

0 commit comments

Comments
 (0)