These will be extended with further libx86 work. Fix the sorting of the CPUID_GUEST_NR_* constants, noticed while writing the unit tests.
Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> --- CC: Jan Beulich <jbeul...@suse.com> CC: Wei Liu <wei.l...@citrix.com> CC: Roger Pau Monné <roger....@citrix.com> CC: Sergey Dyasli <sergey.dya...@citrix.com> v2: * Pospone the AFL fuzzer for now. It needs a bit more work. * Exit early for malloc() failures, which won't occur in practice. --- tools/tests/Makefile | 1 + tools/tests/cpu-policy/.gitignore | 1 + tools/tests/cpu-policy/Makefile | 28 ++++ tools/tests/cpu-policy/test-cpu-policy.c | 258 +++++++++++++++++++++++++++++++ xen/include/xen/lib/x86/cpuid.h | 2 +- 5 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 tools/tests/cpu-policy/.gitignore create mode 100644 tools/tests/cpu-policy/Makefile create mode 100644 tools/tests/cpu-policy/test-cpu-policy.c diff --git a/tools/tests/Makefile b/tools/tests/Makefile index a9fc50d..067a380 100644 --- a/tools/tests/Makefile +++ b/tools/tests/Makefile @@ -5,6 +5,7 @@ CFLAGS += $(CFLAGS_libxenctrl) LDLIBS += $(LDLIBS_libxenctrl) SUBDIRS-y := +SUBDIRS-$(CONFIG_X86) += cpu-policy SUBDIRS-$(CONFIG_X86) += mce-test SUBDIRS-y += mem-sharing ifeq ($(XEN_TARGET_ARCH),__fixme__) diff --git a/tools/tests/cpu-policy/.gitignore b/tools/tests/cpu-policy/.gitignore new file mode 100644 index 0000000..83bdb6b --- /dev/null +++ b/tools/tests/cpu-policy/.gitignore @@ -0,0 +1 @@ +test-cpu-policy diff --git a/tools/tests/cpu-policy/Makefile b/tools/tests/cpu-policy/Makefile new file mode 100644 index 0000000..eeed7f3 --- /dev/null +++ b/tools/tests/cpu-policy/Makefile @@ -0,0 +1,28 @@ +XEN_ROOT = $(CURDIR)/../../.. +include $(XEN_ROOT)/tools/Rules.mk + +.PHONY: all +all: test-cpu-policy + +.PHONY: clean +clean: + $(RM) -f -- *.o .*.d .*.d2 test-cpu-policy + +.PHONY: distclean +distclean: clean + $(RM) -f -- *~ + +.PHONY: install +install: all + +.PHONY: uninstall + +CFLAGS += -Werror $(CFLAGS_xeninclude) -D__XEN_TOOLS__ -O3 +CFLAGS += $(APPEND_CFLAGS) + +vpath %.c ../../../xen/lib/x86 + +test-cpu-policy: test-cpu-policy.o msr.o cpuid.o + $(CC) $(CFLAGS) $^ -o $@ + +-include $(DEPS_INCLUDE) diff --git a/tools/tests/cpu-policy/test-cpu-policy.c b/tools/tests/cpu-policy/test-cpu-policy.c new file mode 100644 index 0000000..d13963e --- /dev/null +++ b/tools/tests/cpu-policy/test-cpu-policy.c @@ -0,0 +1,258 @@ +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> + +#include <xen-tools/libs.h> +#include <xen/lib/x86/cpuid.h> +#include <xen/lib/x86/msr.h> +#include <xen/domctl.h> + +static unsigned int nr_failures; +#define fail(fmt, ...) \ +({ \ + nr_failures++; \ + printf(fmt, ##__VA_ARGS__); \ +}) + +static void test_cpuid_serialise_success(void) +{ + static const struct test { + struct cpuid_policy p; + const char *name; + unsigned int nr_leaves; + } tests[] = { + { + .name = "empty policy", + .nr_leaves = 4, + }, + }; + + printf("Testing CPUID serialise success:\n"); + + for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t = &tests[i]; + unsigned int nr = t->nr_leaves; + xen_cpuid_leaf_t *leaves = malloc(nr * sizeof(*leaves)); + int rc; + + if ( !leaves ) + err(1, "%s() malloc failure", __func__); + + rc = x86_cpuid_copy_to_buffer(&t->p, leaves, &nr); + + if ( rc != 0 ) + { + fail(" Test %s, expected rc 0, got %d\n", + t->name, rc); + goto test_done; + } + + if ( nr != t->nr_leaves ) + { + fail(" Test %s, expected %u leaves, got %u\n", + t->name, t->nr_leaves, nr); + goto test_done; + } + + test_done: + free(leaves); + } +} + +static void test_msr_serialise_success(void) +{ + static const struct test { + struct msr_policy p; + const char *name; + unsigned int nr_msrs; + } tests[] = { + { + .name = "empty policy", + .nr_msrs = MSR_MAX_SERIALISED_ENTRIES, + }, + }; + + printf("Testing MSR serialise success:\n"); + + for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t = &tests[i]; + unsigned int nr = t->nr_msrs; + xen_msr_entry_t *msrs = malloc(nr * sizeof(*msrs)); + int rc; + + if ( !msrs ) + err(1, "%s() malloc failure", __func__); + + rc = x86_msr_copy_to_buffer(&t->p, msrs, &nr); + + if ( rc != 0 ) + { + fail(" Test %s, expected rc 0, got %d\n", + t->name, rc); + goto test_done; + } + + if ( nr != t->nr_msrs ) + { + fail(" Test %s, expected %u msrs, got %u\n", + t->name, t->nr_msrs, nr); + goto test_done; + } + + test_done: + free(msrs); + } +} + +static void test_cpuid_deserialise_failure(void) +{ + static const struct test { + const char *name; + xen_cpuid_leaf_t leaf; + } tests[] = { + { + .name = "incorrect basic subleaf", + .leaf = { .leaf = 0, .subleaf = 0 }, + }, + { + .name = "incorrect hv1 subleaf", + .leaf = { .leaf = 0x40000000, .subleaf = 0 }, + }, + { + .name = "incorrect hv2 subleaf", + .leaf = { .leaf = 0x40000100, .subleaf = 0 }, + }, + { + .name = "incorrect extd subleaf", + .leaf = { .leaf = 0x80000000, .subleaf = 0 }, + }, + { + .name = "OoB basic leaf", + .leaf = { .leaf = CPUID_GUEST_NR_BASIC }, + }, + { + .name = "OoB cache leaf", + .leaf = { .leaf = 0x4, .subleaf = CPUID_GUEST_NR_CACHE }, + }, + { + .name = "OoB feat leaf", + .leaf = { .leaf = 0x7, .subleaf = CPUID_GUEST_NR_FEAT }, + }, + { + .name = "OoB topo leaf", + .leaf = { .leaf = 0xb, .subleaf = CPUID_GUEST_NR_TOPO }, + }, + { + .name = "OoB xstate leaf", + .leaf = { .leaf = 0xd, .subleaf = CPUID_GUEST_NR_XSTATE }, + }, + { + .name = "OoB extd leaf", + .leaf = { .leaf = 0x80000000 | CPUID_GUEST_NR_EXTD }, + }, + }; + + printf("Testing CPUID deserialise failure:\n"); + + for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t = &tests[i]; + uint32_t err_leaf = ~0u, err_subleaf = ~0u; + int rc; + + /* No writes should occur. Use NULL to catch errors. */ + rc = x86_cpuid_copy_from_buffer(NULL, &t->leaf, 1, + &err_leaf, &err_subleaf); + + if ( rc != -ERANGE ) + { + fail(" Test %s, expected rc %d, got %d\n", + t->name, -ERANGE, rc); + continue; + } + + if ( err_leaf != t->leaf.leaf || err_subleaf != t->leaf.subleaf ) + { + fail(" Test %s, expected err %08x:%08x, got %08x:%08x\n", + t->name, t->leaf.leaf, t->leaf.subleaf, + err_leaf, err_subleaf); + continue; + } + } +} + +static void test_msr_deserialise_failure(void) +{ + static const struct test { + const char *name; + xen_msr_entry_t msr; + int rc; + } tests[] = { + { + .name = "bad msr index", + .msr = { .idx = 0xdeadc0de }, + .rc = -ERANGE, + }, + { + .name = "nonzero flags", + .msr = { .idx = 0xce, .flags = 1 }, + .rc = -EINVAL, + }, + { + .name = "truncated val", + .msr = { .idx = 0xce, .val = ~0ull }, + .rc = -EOVERFLOW, + }, + }; + + printf("Testing MSR deserialise failure:\n"); + + for ( size_t i = 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t = &tests[i]; + uint32_t err_msr = ~0u; + int rc; + + /* No writes should occur. Use NULL to catch errors. */ + rc = x86_msr_copy_from_buffer(NULL, &t->msr, 1, &err_msr); + + if ( rc != t->rc ) + { + fail(" Test %s, expected rc %d, got %d\n", + t->name, t->rc, rc); + continue; + } + + if ( err_msr != t->msr.idx ) + { + fail(" Test %s, expected err_msr %#x, got %#x\n", + t->name, t->msr.idx, err_msr); + continue; + } + } +} + +int main(int argc, char **argv) +{ + printf("CPU Policy unit tests\n"); + + test_cpuid_serialise_success(); + test_msr_serialise_success(); + + test_cpuid_deserialise_failure(); + test_msr_deserialise_failure(); + + if ( nr_failures ) + printf("Done: %u failures\n", nr_failures); + else + printf("Done: all ok\n"); + + return !!nr_failures; +} diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpuid.h index 767a33b..95b37b6 100644 --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -66,8 +66,8 @@ static inline void cpuid_count_leaf( #undef XCHG #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_FEAT (0u + 1) #define CPUID_GUEST_NR_TOPO (1u + 1) #define CPUID_GUEST_NR_XSTATE (62u + 1) #define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1) -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel