}
}
+static void test_cpuid_get_leaf_failure(void)
+{
+ const static struct test {
+ struct cpuid_policy p;
+ const char *name;
+ uint32_t leaf, subleaf;
+ } tests[] = {
+ /* Bound checking logic. */
+ {
+ .name = "Basic max leaf >= array size",
+ .p = {
+ .basic.max_leaf = CPUID_GUEST_NR_BASIC,
+ },
+ },
+ {
+ .name = "Feature max leaf >= array size",
+ .p = {
+ .basic.max_leaf = CPUID_GUEST_NR_BASIC - 1,
+ .feat.max_subleaf = CPUID_GUEST_NR_FEAT,
+ },
+ .leaf = 0x00000007,
+ },
+ {
+ .name = "Extended max leaf >= array size",
+ .p = {
+ .extd.max_leaf = 0x80000000 + CPUID_GUEST_NR_EXTD,
+ },
+ .leaf = 0x80000000,
+ },
+
+ {
+ .name = "Basic leaf >= max leaf",
+ .p = {
+ .basic.max_leaf = CPUID_GUEST_NR_BASIC - 1,
+ },
+ .leaf = CPUID_GUEST_NR_BASIC,
+ },
+ {
+ .name = "Feature leaf >= max leaf",
+ .p = {
+ .basic.max_leaf = CPUID_GUEST_NR_BASIC - 1,
+ .feat.max_subleaf = CPUID_GUEST_NR_FEAT - 1,
+ },
+ .leaf = 0x00000007,
+ .subleaf = CPUID_GUEST_NR_FEAT,
+ },
+ {
+ .name = "Extended leaf >= max leaf",
+ .p = {
+ .extd.max_leaf = 0x80000000 + CPUID_GUEST_NR_EXTD - 1,
+ },
+ .leaf = 0x80000000 + CPUID_GUEST_NR_EXTD,
+ },
+ };
+ const struct cpuid_policy pc;
+ const struct cpuid_leaf *lc;
+ struct cpuid_policy p;
+ struct cpuid_leaf *l;
+
+ /* Constness build test. */
+ lc = x86_cpuid_get_leaf(&pc, 0, 0);
+ l = x86_cpuid_get_leaf(&p, 0, 0);
+
+ printf("Testing CPUID get leaf bound checking:\n");
+
+ for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i )
+ {
+ const struct test *t = &tests[i];
+
+ if ( x86_cpuid_get_leaf(&t->p, t->leaf, t->subleaf) )
+ fail(" Test %s get leaf fail\n", t->name);
+ }
+}
+
static void test_is_compatible_success(void)
{
static struct test {
test_cpuid_deserialise_failure();
test_cpuid_out_of_range_clearing();
test_cpuid_maximum_leaf_shrinking();
+ test_cpuid_get_leaf_failure();
test_msr_serialise_success();
test_msr_deserialise_failure();
switch ( leaf )
{
case 0 ... CPUID_GUEST_NR_BASIC - 1:
- ASSERT(p->basic.max_leaf < ARRAY_SIZE(p->basic.raw));
- if ( leaf > min_t(uint32_t, p->basic.max_leaf,
- ARRAY_SIZE(p->basic.raw) - 1) )
- return;
-
- switch ( leaf )
- {
- case 0x4:
- if ( subleaf >= ARRAY_SIZE(p->cache.raw) )
- return;
-
- *res = array_access_nospec(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,
- ARRAY_SIZE(p->feat.raw) - 1) )
- return;
-
- *res = array_access_nospec(p->feat.raw, subleaf);
- break;
-
- case 0xb:
- if ( subleaf >= ARRAY_SIZE(p->topo.raw) )
- return;
-
- *res = array_access_nospec(p->topo.raw, subleaf);
- break;
-
- case XSTATE_CPUID:
- if ( !p->basic.xsave || subleaf >= ARRAY_SIZE(p->xstate.raw) )
- return;
+ case 0x80000000 ... 0x80000000 + CPUID_GUEST_NR_EXTD - 1:
+ {
+ const struct cpuid_leaf *tmp = x86_cpuid_get_leaf(p, leaf, subleaf);
- *res = array_access_nospec(p->xstate.raw, subleaf);
- break;
+ if ( !tmp )
+ return;
- default:
- *res = array_access_nospec(p->basic.raw, leaf);
- break;
- }
+ *res = *tmp;
break;
+ }
case 0x40000000 ... 0x400000ff:
if ( is_viridian_domain(d) )
case 0x40000100 ... 0x400001ff:
return cpuid_hypervisor_leaves(v, leaf, subleaf, res);
- case 0x80000000 ... 0x80000000 + CPUID_GUEST_NR_EXTD - 1:
- ASSERT((p->extd.max_leaf & 0xffff) < ARRAY_SIZE(p->extd.raw));
- if ( (leaf & 0xffff) > min_t(uint32_t, p->extd.max_leaf & 0xffff,
- ARRAY_SIZE(p->extd.raw) - 1) )
- return;
-
- *res = array_access_nospec(p->extd.raw, leaf & 0xffff);
- break;
-
default:
return;
}
uint32_t nr_entries, uint32_t *err_leaf,
uint32_t *err_subleaf);
+/**
+ * Get a cpuid leaf from a policy object.
+ *
+ * @param policy The cpuid_policy object.
+ * @param leaf The leaf index.
+ * @param subleaf The subleaf index.
+ * @returns a pointer to the requested leaf or NULL in case of error.
+ *
+ * The function will perform out of bound checks. Do not call this function
+ * directly and instead use x86_cpuid_get_leaf that will deal with both const
+ * and non-const policies returning a pointer with constness matching that of
+ * the input.
+ */
+const struct cpuid_leaf *_x86_cpuid_get_leaf(const struct cpuid_policy *p,
+ uint32_t leaf, uint32_t subleaf);
+#define x86_cpuid_get_leaf(p, l, s) \
+ ((__typeof__(&(p)->basic.raw[0]))_x86_cpuid_get_leaf(p, l, s))
+
#endif /* !XEN_LIB_X86_CPUID_H */
/*
return -ERANGE;
}
+const struct cpuid_leaf *_x86_cpuid_get_leaf(const struct cpuid_policy *p,
+ uint32_t leaf, uint32_t subleaf)
+{
+ switch ( leaf )
+ {
+ case 0 ... CPUID_GUEST_NR_BASIC - 1:
+ if ( p->basic.max_leaf >= ARRAY_SIZE(p->basic.raw) ||
+ leaf > p->basic.max_leaf )
+ return NULL;
+
+ switch ( leaf )
+ {
+ case 0x4:
+ if ( subleaf >= ARRAY_SIZE(p->cache.raw) )
+ return NULL;
+
+ return &array_access_nospec(p->cache.raw, subleaf);
+
+ case 0x7:
+ if ( p->feat.max_subleaf >= ARRAY_SIZE(p->feat.raw) ||
+ subleaf > p->feat.max_subleaf )
+ return NULL;
+
+ return &array_access_nospec(p->feat.raw, subleaf);
+
+ case 0xb:
+ if ( subleaf >= ARRAY_SIZE(p->topo.raw) )
+ return NULL;
+
+ return &array_access_nospec(p->topo.raw, subleaf);
+
+ case 0xd:
+ if ( !p->basic.xsave || subleaf >= ARRAY_SIZE(p->xstate.raw) )
+ return NULL;
+
+ return &array_access_nospec(p->xstate.raw, subleaf);
+ }
+
+ return &array_access_nospec(p->basic.raw, leaf);
+
+ case 0x80000000 ... 0x80000000 + CPUID_GUEST_NR_EXTD - 1:
+ if ( (p->extd.max_leaf & 0xffff) >= ARRAY_SIZE(p->extd.raw) ||
+ leaf > p->extd.max_leaf )
+ return NULL;
+
+ return &array_access_nospec(p->extd.raw, leaf & 0xffff);
+ }
+
+ return NULL;
+}
+
/*
* Local variables:
* mode: C