]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
Basic grant table infrastructure
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 19 Jun 2017 13:55:21 +0000 (14:55 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 9 Aug 2017 15:37:25 +0000 (16:37 +0100)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Doxyfile
arch/x86/grant_table.c [new file with mode: 0644]
build/files.mk
common/grant_table.c [new file with mode: 0644]
include/xen/grant_table.h [new file with mode: 0644]
include/xtf.h
include/xtf/compiler.h
include/xtf/grant_table.h [new file with mode: 0644]
include/xtf/hypercall.h
tests/selftest/main.c

index 70f08d4f36022d72606f90ae7650cc37511089a9..afb55e98fbe1eec0e90a36b42aaf616b8f5bd3b0 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -2024,7 +2024,8 @@ INCLUDE_FILE_PATTERNS  =
 # recursively expanded use the := operator instead of the = operator.
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
-PREDEFINED             = __aligned(x)= \
+PREDEFINED             = __alias(x)= \
+                         __aligned(x)= \
                          __always_inline \
                          __attribute__(x)= \
                          __packed \
diff --git a/arch/x86/grant_table.c b/arch/x86/grant_table.c
new file mode 100644 (file)
index 0000000..e8b4561
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file arch/x86/grant_table.c
+ *
+ * %x86 specific bits of Grant Table handling
+ */
+#include <xtf/grant_table.h>
+#include <xtf/hypercall.h>
+#include <xtf/lib.h>
+
+#include <arch/pagetable.h>
+#include <arch/symbolic-const.h>
+
+int arch_map_gnttab(void)
+{
+    unsigned int i, nr_frames = sizeof(gnttab_raw) / PAGE_SIZE;
+    int rc = 0;
+
+    /* Ensure gnttab_raw[] is a whole number of pages. */
+    BUILD_BUG_ON(sizeof(gnttab_raw) % PAGE_SIZE);
+
+    if ( IS_DEFINED(CONFIG_PV) )
+    {
+        unsigned long gnttab_gfns[nr_frames];
+        struct gnttab_setup_table setup = {
+            .dom = DOMID_SELF,
+            .nr_frames = ARRAY_SIZE(gnttab_gfns),
+            .frame_list = gnttab_gfns,
+        };
+
+        rc = hypercall_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+        if ( rc || setup.status )
+        {
+            printk("%s() GNTTABOP_setup_table failed: rc %d, status %d: %s\n",
+                   __func__, rc, setup.status, gntst_strerror(setup.status));
+            return -EIO;
+        }
+
+        for ( i = 0; !rc && i < nr_frames; ++i )
+            rc = hypercall_update_va_mapping(
+                _u(&gnttab_raw[i * PAGE_SIZE]),
+                pte_from_gfn(gnttab_gfns[i], PF_SYM(AD, RW, P)), UVMF_INVLPG);
+    }
+    else /* HVM */
+    {
+        struct xen_add_to_physmap xatp = {
+            .domid = DOMID_SELF,
+            .space = XENMAPSPACE_grant_table,
+            .idx = 0,
+            .gfn = virt_to_gfn(gnttab_raw),
+        };
+
+        for ( i = 0; !rc && i < nr_frames; ++i, ++xatp.idx, ++xatp.gfn )
+            rc = hypercall_memory_op(XENMEM_add_to_physmap, &xatp);
+    }
+
+    if ( rc )
+    {
+        printk("%s() Failed to map gnttab[%u]: %d\n", __func__, i, rc);
+        return -EIO;
+    }
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 6001a9254b1e5fe001428f43d8f678688bbb67f4..f9bb3b4028a3f03d35773ec0792c4fb37e9eda1e 100644 (file)
@@ -7,6 +7,7 @@
 obj-perarch += $(ROOT)/common/console.o
 obj-perarch += $(ROOT)/common/exlog.o
 obj-perarch += $(ROOT)/common/extable.o
+obj-perarch += $(ROOT)/common/grant_table.o
 obj-perarch += $(ROOT)/common/heapsort.o
 obj-perarch += $(ROOT)/common/lib.o
 obj-perarch += $(ROOT)/common/libc/stdio.o
@@ -19,6 +20,7 @@ obj-perarch += $(ROOT)/common/xenbus.o
 obj-perenv += $(ROOT)/arch/x86/decode.o
 obj-perenv += $(ROOT)/arch/x86/desc.o
 obj-perenv += $(ROOT)/arch/x86/extable.o
+obj-perenv += $(ROOT)/arch/x86/grant_table.o
 obj-perenv += $(ROOT)/arch/x86/hypercall_page.o
 obj-perenv += $(ROOT)/arch/x86/setup.o
 obj-perenv += $(ROOT)/arch/x86/traps.o
diff --git a/common/grant_table.c b/common/grant_table.c
new file mode 100644 (file)
index 0000000..15cd966
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file common/grant_table.c
+ *
+ * A driver for the Xen Grant Table interface.
+ */
+#include <xtf/grant_table.h>
+#include <xtf/lib.h>
+
+uint8_t gnttab_raw[] __page_aligned_bss;
+extern grant_entry_v1_t gnttab_v1[] __alias("gnttab_raw");
+extern grant_entry_v2_t gnttab_v2[] __alias("gnttab_raw");
+
+const char *gntst_strerror(int err)
+{
+    static const char *const errstr[] = GNTTABOP_error_msgs;
+    unsigned int idx = -err;
+
+    return idx < ARRAY_SIZE(errstr) ? errstr[idx] : "unknown";
+}
+
+int xtf_init_grant_table(unsigned int version)
+{
+    struct gnttab_set_version ver = { version };
+
+    int rc = hypercall_grant_table_op(GNTTABOP_set_version, &ver, 1);
+
+    if ( rc == -ENOSYS )
+        /* Sufficiently old Xen which doesn't support gnttab v2. */
+        return -ENODEV;
+
+    if ( rc )
+    {
+        printk("%s() GNTTABOP_set_version failed: rc %d\n", __func__, rc);
+        return -EIO;
+    }
+
+    static bool gnttab_mapped;
+    if ( !gnttab_mapped )
+    {
+        rc = arch_map_gnttab();
+
+        if ( !rc )
+            gnttab_mapped = true;
+    }
+
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
new file mode 100644 (file)
index 0000000..8c40903
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Xen public Grant Table hypercall interface
+ */
+
+#ifndef XEN_PUBLIC_GRANT_TABLE_H
+#define XEN_PUBLIC_GRANT_TABLE_H
+
+#include "xen.h"
+
+#define GNTST_okay              (0)  /* Normal return.                        */
+#define GNTST_general_error     (-1) /* General undefined error.              */
+#define GNTST_bad_domain        (-2) /* Unrecognsed domain id.                */
+#define GNTST_bad_gntref        (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle        (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr     (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr      (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space   (-7) /* Out of space in I/O MMU.              */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation.   */
+#define GNTST_bad_page          (-9) /* Specified page was invalid for op.    */
+#define GNTST_bad_copy_arg     (-10) /* copy arguments cross page boundary.   */
+#define GNTST_address_too_big  (-11) /* transfer page address too large.      */
+#define GNTST_eagain           (-12) /* Operation not done; try again.        */
+
+#define GNTTABOP_error_msgs {                       \
+        "okay",                                     \
+        "undefined error",                          \
+        "unrecognised domain id",                   \
+        "invalid grant reference",                  \
+        "invalid mapping handle",                   \
+        "invalid virtual address",                  \
+        "invalid device address",                   \
+        "no spare translation slot in the I/O MMU", \
+        "permission denied",                        \
+        "bad page",                                 \
+        "copy arguments cross page boundary",       \
+        "page address size too large",              \
+        "operation not done; try again",            \
+    }
+
+/*
+ * Type of grant entry.
+ *  GTF_invalid: This grant entry grants no privileges.
+ *  GTF_permit_access: Allow @domid to map/access @frame.
+ *  GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ *                       to this guest. Xen writes the page number to @frame.
+ *  GTF_transitive: Allow @domid to transitively access a subrange of
+ *                  @trans_grant in @trans_domid.  No mappings are allowed.
+ */
+#define GTF_invalid         (0 << 0)
+#define GTF_permit_access   (1 << 0)
+#define GTF_accept_transfer (2 << 0)
+#define GTF_transitive      (3 << 0)
+#define GTF_type_mask       (3 << 0)
+
+/*
+ * Subflags for GTF_permit_access.
+ *  GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ *  GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ *  GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ *  GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags for the grant [GST]
+ *  GTF_sub_page: Grant access to only a subrange of the page.  @domid
+ *                will only be allowed to copy from the grant, and not
+ *                map it. [GST]
+ */
+#define _GTF_readonly       2
+#define GTF_readonly        (1 << _GTF_readonly)
+
+#define _GTF_reading        3
+#define GTF_reading         (1 << _GTF_reading)
+
+#define _GTF_writing        4
+#define GTF_writing         (1 << _GTF_writing)
+
+#define _GTF_PWT            5
+#define GTF_PWT             (1 << _GTF_PWT)
+
+#define _GTF_PCD            6
+#define GTF_PCD             (1 << _GTF_PCD)
+
+#define _GTF_PAT            7
+#define GTF_PAT             (1 << _GTF_PAT)
+
+#define _GTF_sub_page       8
+#define GTF_sub_page        (1 << _GTF_sub_page)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ *  GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ *      to transferring ownership of a page frame. When a guest sees this flag
+ *      it must /not/ modify the grant entry until GTF_transfer_completed is
+ *      set by Xen.
+ *  GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ *      after reading GTF_transfer_committed. Xen will always write the frame
+ *      address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed 2
+#define GTF_transfer_committed  (1 << _GTF_transfer_committed)
+
+#define _GTF_transfer_completed 3
+#define GTF_transfer_completed  (1 << _GTF_transfer_completed)
+
+typedef uint32_t grant_ref_t;
+typedef uint32_t grant_handle_t;
+
+typedef struct
+{
+    /* GTF_xxx: various type and flag information.  [XEN,GST] */
+    uint16_t flags;
+    /* The domain being granted foreign privileges. [GST] */
+    domid_t  domid;
+    /*
+     * GTF_permit_access: GFN that @domid is allowed to map and access. [GST]
+     * GTF_accept_transfer: GFN that @domid is allowed to transfer into. [GST]
+     * GTF_transfer_completed: MFN whose ownership transferred by @domid
+     *                         (non-translated guests only). [XEN]
+     */
+    uint32_t frame;
+} grant_entry_v1_t;
+
+typedef struct {
+    uint16_t flags;
+    domid_t  domid;
+} grant_entry_header_t;
+
+typedef union {
+    grant_entry_header_t hdr;
+
+    /*
+     * This member is used for V1-style full page grants, where either:
+     *
+     * -- hdr.type is GTF_accept_transfer, or
+     * -- hdr.type is GTF_permit_access and GTF_sub_page is not set.
+     *
+     * In that case, the frame field has the same semantics as the
+     * field of the same name in the V1 entry structure.
+     */
+    struct {
+        grant_entry_header_t hdr;
+        uint32_t pad0;
+        uint64_t frame;
+    } full_page;
+
+    /*
+     * If the grant type is GTF_grant_access and GTF_sub_page is set,
+     * @domid is allowed to access bytes [@page_off,@page_off+@length)
+     * in frame @frame.
+     */
+    struct {
+        grant_entry_header_t hdr;
+        uint16_t page_off;
+        uint16_t length;
+        uint64_t frame;
+    } sub_page;
+
+    /*
+     * If the grant is GTF_transitive, @domid is allowed to use the
+     * grant @gref in domain @trans_domid, as if it was the local
+     * domain.  Obviously, the transitive access must be compatible
+     * with the original grant.
+     *
+     * The current version of Xen does not allow transitive grants
+     * to be mapped.
+     */
+    struct {
+        grant_entry_header_t hdr;
+        domid_t trans_domid;
+        uint16_t pad0;
+        grant_ref_t gref;
+    } transitive;
+
+    uint32_t __spacer[4]; /* Pad to a power of two */
+} grant_entry_v2_t;
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ *  3. Xen may not support more than a single grant-table page per domain.
+ */
+#define GNTTABOP_setup_table          2
+struct gnttab_setup_table
+{
+    /* IN parameters. */
+    domid_t  dom;
+    uint32_t nr_frames;
+    /* OUT parameters. */
+    int16_t  status;
+    unsigned long *frame_list;
+};
+
+/*
+ * GNTTABOP_set_version: Request a particular version of the grant
+ * table shared table structure.  This operation may be used to toggle
+ * between different versions, but must be performed while no grants
+ * are active.  The only defined versions are 1 and 2.
+ */
+#define GNTTABOP_set_version          8
+struct gnttab_set_version {
+    /* IN/OUT parameters */
+    uint32_t version;
+};
+
+#endif /* XEN_PUBLIC_GRANT_TABLE_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 7d1e90a4ac6b617e463f73b5951b99543264ad1c..288a861ca11037905a0e61311ae366b20acf564a 100644 (file)
 #include <xtf/test.h>
 
 /* Optional functionality */
+#include <xtf/atomic.h>
 #include <xtf/bitops.h>
 #include <xtf/exlog.h>
+#include <xtf/grant_table.h>
 #include <xtf/hypercall.h>
 #include <xtf/traps.h>
 #include <xtf/xenbus.h>
index 11a516c4921f65c52a158ddcd1e039ad128626dd..9dd6734dcd133b16cf8bf7b19617d52a1ac250f6 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef XTF_COMPILER_H
 #define XTF_COMPILER_H
 
+#define __alias(x)            __attribute__((__alias__(x)))
 #define __aligned(x)          __attribute__((__aligned__(x)))
 #define __noreturn            __attribute__((__noreturn__))
 #define __packed              __attribute__((__packed__))
diff --git a/include/xtf/grant_table.h b/include/xtf/grant_table.h
new file mode 100644 (file)
index 0000000..e13d9b8
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file include/xtf/grant_table.h
+ *
+ * A driver for the Xen Grant Table interface.
+ */
+#ifndef XTF_GRANT_TABLE_H
+#define XTF_GRANT_TABLE_H
+
+#include <xtf/hypercall.h>
+
+/**
+ * Raw grant table mapping from Xen.
+ * Valid once arch_map_gnttab() has returned successfully.
+ */
+extern uint8_t gnttab_raw[PAGE_SIZE];
+
+/** Grant table in v1 format (aliases #gnttab_raw). */
+extern grant_entry_v1_t gnttab_v1[
+    sizeof(gnttab_raw) / sizeof(grant_entry_v1_t)];
+
+/** Grant table in v2 format (aliases #gnttab_raw). */
+extern grant_entry_v2_t gnttab_v2[
+    sizeof(gnttab_raw) / sizeof(grant_entry_v2_t)];
+
+/**
+ * Map the domains grant table under #gnttab_raw[].
+ */
+int arch_map_gnttab(void);
+
+
+/**
+ * Convert a grant status error value to a string.
+ * @param err GNTST_*
+ * @returns error string, or "unknown"
+ */
+const char *gntst_strerror(int err);
+
+/**
+ * Initialise XTF's grant infrastructure.
+ *
+ * Sets a grant table version, and maps the grant table itself.  Safe to be
+ * called multiple times to switch grant table version, as long as there are
+ * no active grants.
+ */
+int xtf_init_grant_table(unsigned int version);
+
+#endif /* XTF_GRANT_TABLE_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 17e9636560771e12768797e0b59d59ebb976eba8..be4a01ec1119ceded7344d8212c8a96ec6be9052 100644 (file)
@@ -33,6 +33,7 @@ extern uint8_t hypercall_page[PAGE_SIZE];
 #include <xen/callback.h>
 #include <xen/errno.h>
 #include <xen/event_channel.h>
+#include <xen/grant_table.h>
 #include <xen/physdev.h>
 #include <xen/memory.h>
 #include <xen/version.h>
@@ -87,6 +88,12 @@ static inline long hypercall_update_va_mapping(
 #endif
 }
 
+static inline long hypercall_grant_table_op(unsigned int cmd, void *args,
+                                            unsigned int count)
+{
+    return HYPERCALL3(long, __HYPERVISOR_grant_table_op, cmd, args, count);
+}
+
 static inline long hypercall_vm_assist(unsigned int cmd, unsigned int type)
 {
     return HYPERCALL2(long, __HYPERVISOR_vm_assist, cmd, type);
index fa74f6098d290329c571213b4499f36527a81156..1f57cb2bd7e5e9b7e2604c21373c64f2bc5f1a11 100644 (file)
@@ -316,6 +316,14 @@ static void test_driver_init(void)
         if ( rc && rc != -ENODEV )
             xtf_failure("Fail: apic_init() returned %d\n", rc);
     }
+
+    rc = xtf_init_grant_table(1);
+    if ( rc )
+        xtf_failure("Fail: xtf_init_grant_table(1) returned %d\n", rc);
+
+    rc = xtf_init_grant_table(2);
+    if ( rc && rc != -ENODEV )
+        xtf_failure("Fail: xtf_init_grant_table(2) returned %d\n", rc);
 }
 
 void test_main(void)