mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
x86/cpuid: Handle leaf 0x4 in guest_cpuid()
Leaf 0x4 is reserved by AMD. For Intel, it is a multi-invocation leaf with ecx enumerating different cache details. Add a new union for it in struct cpuid_policy, collect it from hardware in calculate_raw_policy(), audit it in recalculate_cpuid_policy() and update guest_cpuid() and update_domain_cpuid_info() to properly insert/extract data. A lot of the data here will need further auditing/refinement when better topology support is introduced, but for now, this matches the existing toolstack behaviour. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
9dc1e0cd81
commit
0b4249e96b
3 files changed
+82
-5
No files matched your search
+53
-2
@@ -199,6 +199,7 @@ static void recalculate_misc(struct cpuid_policy *p)
|
||||
|
||||
case X86_VENDOR_AMD:
|
||||
zero_leaves(p->basic.raw, 0x2, 0x3);
|
||||
memset(p->cache.raw, 0, sizeof(p->cache.raw));
|
||||
p->basic.raw[0x9] = EMPTY_LEAF;
|
||||
|
||||
p->extd.vendor_ebx = p->basic.vendor_ebx;
|
||||
@@ -242,6 +243,32 @@ static void __init calculate_raw_policy(void)
|
||||
cpuid_leaf(i, &p->basic.raw[i]);
|
||||
}
|
||||
|
||||
if ( p->basic.max_leaf >= 4 )
|
||||
{
|
||||
for ( i = 0; i < ARRAY_SIZE(p->cache.raw); ++i )
|
||||
{
|
||||
union {
|
||||
struct cpuid_leaf l;
|
||||
struct cpuid_cache_leaf c;
|
||||
} u;
|
||||
|
||||
cpuid_count_leaf(4, i, &u.l);
|
||||
|
||||
if ( u.c.type == 0 )
|
||||
break;
|
||||
|
||||
p->cache.subleaf[i] = u.c;
|
||||
}
|
||||
|
||||
/*
|
||||
* The choice of CPUID_GUEST_NR_CACHE is arbitrary. It is expected
|
||||
* that it will eventually need increasing for future hardware.
|
||||
*/
|
||||
if ( i == ARRAY_SIZE(p->cache.raw) )
|
||||
printk(XENLOG_WARNING
|
||||
"CPUID: Insufficient Leaf 4 space for this hardware\n");
|
||||
}
|
||||
|
||||
if ( p->basic.max_leaf >= 7 )
|
||||
{
|
||||
cpuid_count_leaf(7, 0, &p->feat.raw[0]);
|
||||
@@ -520,6 +547,23 @@ void recalculate_cpuid_policy(struct domain *d)
|
||||
recalculate_xstate(p);
|
||||
recalculate_misc(p);
|
||||
|
||||
for ( i = 0; i < ARRAY_SIZE(p->cache.raw); ++i )
|
||||
{
|
||||
if ( p->cache.subleaf[i].type >= 1 &&
|
||||
p->cache.subleaf[i].type <= 3 )
|
||||
{
|
||||
/* Subleaf has a valid cache type. Zero reserved fields. */
|
||||
p->cache.raw[i].a &= 0xffffc3ffu;
|
||||
p->cache.raw[i].d &= 0x00000007u;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Subleaf is not valid. Zero the rest of the union. */
|
||||
zero_leaves(p->cache.raw, i, ARRAY_SIZE(p->cache.raw) - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !p->extd.svm )
|
||||
p->extd.raw[0xa] = EMPTY_LEAF;
|
||||
|
||||
@@ -605,7 +649,7 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
|
||||
*res = EMPTY_LEAF;
|
||||
break;
|
||||
|
||||
case 0x0 ... 0x3:
|
||||
case 0x0 ... 0x4:
|
||||
case 0x7 ... 0x9:
|
||||
case 0xc ... XSTATE_CPUID:
|
||||
case 0x80000000 ... 0xffffffff:
|
||||
@@ -640,7 +684,7 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
|
||||
res->a = (res->a & ~0xff) | 3;
|
||||
break;
|
||||
|
||||
case 0x0 ... 0x3:
|
||||
case 0x0 ... 0x4:
|
||||
case 0x7 ... 0x9:
|
||||
case 0xc ... XSTATE_CPUID:
|
||||
case 0x80000000 ... 0xffffffff:
|
||||
@@ -674,6 +718,13 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
|
||||
|
||||
switch ( leaf )
|
||||
{
|
||||
case 0x4:
|
||||
if ( subleaf >= ARRAY_SIZE(p->cache.raw) )
|
||||
return;
|
||||
|
||||
*res = p->cache.raw[subleaf];
|
||||
break;
|
||||
|
||||
case 0x7:
|
||||
ASSERT(p->feat.max_subleaf < ARRAY_SIZE(p->feat.raw));
|
||||
if ( subleaf > min_t(uint32_t, p->feat.max_subleaf,
|
||||
|
||||
+19
-3
@@ -101,6 +101,10 @@ static int update_domain_cpuid_info(struct domain *d,
|
||||
switch ( ctl->input[0] )
|
||||
{
|
||||
case 0x00000000 ... ARRAY_SIZE(p->basic.raw) - 1:
|
||||
if ( ctl->input[0] == 4 &&
|
||||
ctl->input[1] >= ARRAY_SIZE(p->cache.raw) )
|
||||
return 0;
|
||||
|
||||
if ( ctl->input[0] == 7 &&
|
||||
ctl->input[1] >= ARRAY_SIZE(p->feat.raw) )
|
||||
return 0;
|
||||
@@ -129,12 +133,24 @@ static int update_domain_cpuid_info(struct domain *d,
|
||||
switch ( ctl->input[0] )
|
||||
{
|
||||
case 0x00000000 ... ARRAY_SIZE(p->basic.raw) - 1:
|
||||
if ( ctl->input[0] == 7 )
|
||||
switch ( ctl->input[0] )
|
||||
{
|
||||
case 4:
|
||||
p->cache.raw[ctl->input[1]] = leaf;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
p->feat.raw[ctl->input[1]] = leaf;
|
||||
else if ( ctl->input[0] == XSTATE_CPUID )
|
||||
break;
|
||||
|
||||
case XSTATE_CPUID:
|
||||
p->xstate.raw[ctl->input[1]] = leaf;
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
p->basic.raw[ctl->input[0]] = leaf;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40000000:
|
||||
|
||||
@@ -63,6 +63,7 @@ DECLARE_PER_CPU(bool, cpuid_faulting_enabled);
|
||||
|
||||
#define CPUID_GUEST_NR_BASIC (0xdu + 1)
|
||||
#define CPUID_GUEST_NR_FEAT (0u + 1)
|
||||
#define CPUID_GUEST_NR_CACHE (5u + 1)
|
||||
#define CPUID_GUEST_NR_XSTATE (62u + 1)
|
||||
#define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
|
||||
#define CPUID_GUEST_NR_EXTD_AMD (0x1cu + 1)
|
||||
@@ -137,6 +138,15 @@ struct cpuid_policy
|
||||
};
|
||||
} basic;
|
||||
|
||||
/* Structured cache leaf: 0x00000004[xx] */
|
||||
union {
|
||||
struct cpuid_leaf raw[CPUID_GUEST_NR_CACHE];
|
||||
struct cpuid_cache_leaf {
|
||||
uint32_t type:5,
|
||||
:27, :32, :32, :32;
|
||||
} subleaf[CPUID_GUEST_NR_CACHE];
|
||||
} cache;
|
||||
|
||||
/* Structured feature leaf: 0x00000007[xx] */
|
||||
union {
|
||||
struct cpuid_leaf raw[CPUID_GUEST_NR_FEAT];
|
||||
|
||||