# 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 \
--- /dev/null
+/**
+ * @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:
+ */
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
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
--- /dev/null
+/**
+ * @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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
#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>
#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__))
--- /dev/null
+/**
+ * @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:
+ */
#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>
#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);
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)