libx86: Introduce x86_cpu_policies_are_compatible()

This helper will eventually be the core "can a guest configured like this run
on the CPU?" logic.  For now, it is just enough of a stub to allow us to
replace the hypercall interface while retaining the previous behaviour.

It will be expanded as various other bits of CPUID handling get cleaned up.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
Andrew Cooper committed 2019-09-26 13:40:18 +01:00
1 parent f001579288
commit 588a966a57
5 files changed
+188 -3

No files matched your search

+1 -1
View File
@@ -39,7 +39,7 @@ CFLAGS += $(APPEND_CFLAGS)
vpath %.c ../../../xen/lib/x86
test-cpu-policy: test-cpu-policy.o msr.o cpuid.o
test-cpu-policy: test-cpu-policy.o msr.o cpuid.o policy.o
$(CC) $(CFLAGS) $^ -o $@
-include $(DEPS_INCLUDE)
+109 -2
View File
@@ -9,8 +9,7 @@
#include <xen-tools/libs.h>
#include <xen/asm/x86-vendors.h>
#include <xen/lib/x86/cpuid.h>
#include <xen/lib/x86/msr.h>
#include <xen/lib/x86/cpu-policy.h>
#include <xen/domctl.h>
static unsigned int nr_failures;
@@ -503,6 +502,111 @@ static void test_cpuid_out_of_range_clearing(void)
}
}
static void test_is_compatible_success(void)
{
static struct test {
const char *name;
struct cpuid_policy host_cpuid;
struct cpuid_policy guest_cpuid;
struct msr_policy host_msr;
struct msr_policy guest_msr;
} tests[] = {
{
.name = "Host CPUID faulting, Guest not",
.host_msr = {
.platform_info.cpuid_faulting = true,
},
},
{
.name = "Host CPUID faulting, Guest wanted",
.host_msr = {
.platform_info.cpuid_faulting = true,
},
.guest_msr = {
.platform_info.cpuid_faulting = true,
},
},
};
struct cpu_policy_errors no_errors = INIT_CPU_POLICY_ERRORS;
printf("Testing policy compatibility success:\n");
for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i )
{
struct test *t = &tests[i];
struct cpu_policy sys = {
&t->host_cpuid,
&t->host_msr,
}, new = {
&t->guest_cpuid,
&t->guest_msr,
};
struct cpu_policy_errors e;
int res = x86_cpu_policies_are_compatible(&sys, &new, &e);
/* Check the expected error output. */
if ( res != 0 || memcmp(&no_errors, &e, sizeof(no_errors)) )
fail(" Test '%s' expected no errors\n"
" got res %d { leaf %08x, subleaf %08x, msr %08x }\n",
t->name, res, e.leaf, e.subleaf, e.msr);
}
}
static void test_is_compatible_failure(void)
{
static struct test {
const char *name;
struct cpuid_policy host_cpuid;
struct cpuid_policy guest_cpuid;
struct msr_policy host_msr;
struct msr_policy guest_msr;
struct cpu_policy_errors e;
} tests[] = {
{
.name = "Host basic.max_leaf out of range",
.guest_cpuid.basic.max_leaf = 1,
.e = { 0, -1, -1 },
},
{
.name = "Host extd.max_leaf out of range",
.guest_cpuid.extd.max_leaf = 1,
.e = { 0x80000008, -1, -1 },
},
{
.name = "Host no CPUID faulting, Guest wanted",
.guest_msr = {
.platform_info.cpuid_faulting = true,
},
.e = { -1, -1, 0xce },
},
};
printf("Testing policy compatibility failure:\n");
for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i )
{
struct test *t = &tests[i];
struct cpu_policy sys = {
&t->host_cpuid,
&t->host_msr,
}, new = {
&t->guest_cpuid,
&t->guest_msr,
};
struct cpu_policy_errors e;
int res = x86_cpu_policies_are_compatible(&sys, &new, &e);
/* Check the expected error output. */
if ( res == 0 || memcmp(&t->e, &e, sizeof(t->e)) )
fail(" Test '%s' res %d\n"
" expected { leaf %08x, subleaf %08x, msr %08x }\n"
" got { leaf %08x, subleaf %08x, msr %08x }\n",
t->name, res,
t->e.leaf, t->e.subleaf, t->e.msr,
e.leaf, e.subleaf, e.msr);
}
}
int main(int argc, char **argv)
{
printf("CPU Policy unit tests\n");
@@ -516,6 +620,9 @@ int main(int argc, char **argv)
test_msr_serialise_success();
test_msr_deserialise_failure();
test_is_compatible_success();
test_is_compatible_failure();
if ( nr_failures )
printf("Done: %u failures\n", nr_failures);
else
+26
View File
@@ -11,6 +11,32 @@ struct cpu_policy
struct msr_policy *msr;
};
struct cpu_policy_errors
{
uint32_t leaf, subleaf;
uint32_t msr;
};
#define INIT_CPU_POLICY_ERRORS { -1, -1, -1 }
/*
* Calculate whether two policies are compatible.
*
* i.e. Can a VM configured with @guest run on a CPU supporting @host.
*
* @param host A cpu_policy describing the hardware capabilities.
* @param guest A cpu_policy describing the intended VM configuration.
* @param err Optional hint for error diagnostics.
* @returns -errno
*
* For typical usage, @host should be a system policy. In the case that an
* incompatibility is detected, the optional err pointer may identify the
* problematic leaf/subleaf and/or MSR.
*/
int x86_cpu_policies_are_compatible(const struct cpu_policy *host,
const struct cpu_policy *guest,
struct cpu_policy_errors *err);
#endif /* !XEN_LIB_X86_POLICIES_H */
/*
+1
View File
@@ -1,2 +1,3 @@
obj-y += cpuid.o
obj-y += msr.o
obj-y += policy.o
+51
View File
@@ -0,0 +1,51 @@
#include "private.h"
#include <xen/lib/x86/cpu-policy.h>
int x86_cpu_policies_are_compatible(const struct cpu_policy *host,
const struct cpu_policy *guest,
struct cpu_policy_errors *err)
{
struct cpu_policy_errors e = INIT_CPU_POLICY_ERRORS;
int ret = -EINVAL;
#define NA XEN_CPUID_NO_SUBLEAF
#define FAIL_CPUID(l, s) \
do { e.leaf = (l); e.subleaf = (s); goto out; } while ( 0 )
#define FAIL_MSR(m) \
do { e.msr = (m); goto out; } while ( 0 )
if ( guest->cpuid->basic.max_leaf > host->cpuid->basic.max_leaf )
FAIL_CPUID(0, NA);
if ( guest->cpuid->extd.max_leaf > host->cpuid->extd.max_leaf )
FAIL_CPUID(0x80000008, NA);
/* TODO: Audit more CPUID data. */
if ( ~host->msr->platform_info.raw & guest->msr->platform_info.raw )
FAIL_MSR(MSR_INTEL_PLATFORM_INFO);
#undef FAIL_MSR
#undef FAIL_CPUID
#undef NA
/* Success. */
ret = 0;
out:
if ( err )
*err = e;
return ret;
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.