[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 3/3] tools/cpu-policy: Add unit tests



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.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Wei Liu <wei.liu2@xxxxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
CC: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx>

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@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.