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;
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]);
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;
*res = EMPTY_LEAF;
break;
- case 0x0 ... 0x3:
+ case 0x0 ... 0x4:
case 0x7 ... 0x9:
case 0xc ... XSTATE_CPUID:
case 0x80000000 ... 0xffffffff:
res->a = (res->a & ~0xff) | 3;
break;
- case 0x0 ... 0x3:
+ case 0x0 ... 0x4:
case 0x7 ... 0x9:
case 0xc ... XSTATE_CPUID:
case 0x80000000 ... 0xffffffff:
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,
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;
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:
#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)
};
} 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];