]> www.infradead.org Git - users/dwmw2/qemu.git/commitdiff
i386/xen: handle GNTTABOP_set_version
authorJoao Martins <joao.m.martins@oracle.com>
Fri, 21 Sep 2018 15:27:06 +0000 (11:27 -0400)
committerJoao Martins <joao.m.martins@oracle.com>
Tue, 19 Feb 2019 14:00:57 +0000 (09:00 -0500)
We support only grant table layout version 1 (for now).

We seed the initial grant table frame which contains the
preallocated reserved grant entries such as xenstore and
console which are used by the backend to map the ring
and such.

For now we limit to the most widely supported i.e. version 1.
Initializing grant table means adding support for:
 * XENMAPSPACE_shared_info in XENMEM_add_to_physmap hypercall
 * GNTTABOP_set_version hypercall

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
linux-headers/linux/kvm.h
target/i386/cpu.c
target/i386/cpu.h
target/i386/xen-proto.h
target/i386/xen.c

index 8409d197fb10d364e7b73ccffcfbd8b818806652..f15aee0c0a2315978672ae7978d7238dacc8269e 100644 (file)
@@ -1508,6 +1508,24 @@ struct kvm_xen_hvm_attr {
                struct {
                        __s32 domid;
                } dom;
+               struct kvm_xen_gnttab {
+
+#define KVM_XEN_GNTTAB_F_INIT           0
+#define KVM_XEN_GNTTAB_F_GROW          (1 << 0)
+                       __u32 flags;
+                       union {
+                               struct {
+                                    __u32 max_frames;
+                                    __u32 max_maptrack_frames;
+                                    __u64 initial_frame;
+                               } init;
+                               struct {
+                                    __u32 idx;
+                                    __u64 gfn;
+                               } grow;
+                               __u32 padding[3];
+                       };
+               } gnttab;
        } u;
 };
 
@@ -1520,6 +1538,7 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_ATTR_TYPE_EVTCHN            0x4
 /* Available with KVM_CAP_XEN_HVM_DOM0 */
 #define KVM_XEN_ATTR_TYPE_DOMID             0x5
+#define KVM_XEN_ATTR_TYPE_GNTTAB            0x6
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
index afe27d0ed352cafd8c202e89b9cca599df6e9015..c6bce8c5fedd1ef26922a635aa7205083a9e0c9a 100644 (file)
@@ -5813,6 +5813,10 @@ static Property x86_cpu_properties[] = {
     DEFINE_PROP_BOOL("xen-pvclock", X86CPU, xen_pvclock, true),
     DEFINE_PROP_UINT32("xen-major-version", X86CPU, xen_major_version, 3),
     DEFINE_PROP_UINT32("xen-minor-version", X86CPU, xen_minor_version, 2),
+    DEFINE_PROP_UINT32("xen-gnttab-max-frames", X86CPU,
+                       xen_gnttab_max_frames, GNTTAB_MAX_FRAMES),
+    DEFINE_PROP_UINT32("xen-gnttab-max-version", X86CPU,
+                       xen_gnttab_max_version, 1),
 
     /*
      * From "Requirements for Implementing the Microsoft
index 3e0644b239440292c8cc3d6b28d1033f27d84cc0..1c0cb47e7b7d3a1f9c3d33a55fcc1e1674710fd7 100644 (file)
@@ -1491,6 +1491,8 @@ struct X86CPU {
     bool xen_pvclock;
     uint32_t xen_major_version;
     uint32_t xen_minor_version;
+    uint32_t xen_gnttab_max_frames;
+    uint32_t xen_gnttab_max_version;
 };
 
 static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
index cf73f12ae6a638ddb21dec3fadc919e4decadd03..2c5acd443fc5cf8287bc95b42ed8c60340bc3bc2 100644 (file)
 #ifndef TARGET_I386_XEN_PROTO_H
 #define TARGET_I386_XEN_PROTO_H
 
+typedef struct XenGrantTable {
+    unsigned int version;
+    unsigned int nr_frames;
+
+#define GNTTAB_MAX_FRAMES 64
+    unsigned int max_nr_frames;
+    union {
+        void **frames;
+        struct grant_entry_v1 **frames_v1;
+    };
+} XenGrantTable;
+
 typedef struct XenCallbackVector {
     int via;
     int vector;
@@ -42,6 +54,7 @@ typedef struct XenState {
     int domid;
     int port;
     QemuMutex port_lock;
+    struct XenGrantTable gnttab;
 } XenState;
 
 typedef struct XenCPUState {
index 0acaf76cf98bbf5ab0a6217d7bebb5068ca9a348..b112c50e4be98e0959ee30c8b28c5d834a680ca6 100644 (file)
@@ -34,6 +34,7 @@
 #include "standard-headers/xen/vcpu.h"
 #include "standard-headers/xen/sched.h"
 #include "standard-headers/xen/event_channel.h"
+#include "standard-headers/xen/grant_table.h"
 
 #define PAGE_OFFSET    0xffffffff80000000UL
 #define PAGE_SHIFT     12
@@ -256,6 +257,33 @@ static int xen_set_shared_info(CPUState *cs, struct shared_info *shi,
     return err;
 }
 
+static int xen_set_gnttab_frame(CPUState *cs, void *frame,
+                                uint32_t idx, uint64_t gfn)
+{
+    struct kvm_xen_hvm_attr xhgt;
+    XenState *xen = cs->xen_state;
+    int err;
+
+    if (idx < xen->gnttab.nr_frames &&
+        idx >= xen->gnttab.max_nr_frames) {
+        return -EINVAL;
+    }
+
+    xhgt.type = KVM_XEN_ATTR_TYPE_GNTTAB;
+    xhgt.u.gnttab.flags = KVM_XEN_GNTTAB_F_GROW;
+    xhgt.u.gnttab.grow.idx = idx;
+    xhgt.u.gnttab.grow.gfn = gfn;
+    err = kvm_vm_ioctl(cs->kvm_state, KVM_XEN_HVM_SET_ATTR, &xhgt);
+    if (!err) {
+        if (!idx) {
+            g_free(xen->gnttab.frames[idx]);
+        }
+        xen->gnttab.frames[idx] = frame;
+        xen->gnttab.nr_frames++;
+    }
+    return err;
+}
+
 static int kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit,
                                    int cmd, uint64_t arg, X86CPU *cpu)
 {
@@ -284,6 +312,10 @@ static int kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit,
                 err = xen_set_shared_info(cs, hva, xatp->gpfn);
                 break;
             }
+            case XENMAPSPACE_grant_table: {
+                err = xen_set_gnttab_frame(cs, hva, xatp->idx, xatp->gpfn);
+                break;
+            }
             default:
                 break;
             }
@@ -847,6 +879,83 @@ error:
     return err ? HCALL_ERR : 0;
 }
 
+static int kvm_xen_set_gnttab(CPUState *cs)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    XenState *xen = cs->xen_state;
+    unsigned int max = cpu->xen_gnttab_max_frames;
+    XenGrantTable *gnttab = &xen->gnttab;
+    struct kvm_xen_hvm_attr xhsi;
+    struct kvm_xen_gnttab *xhgt = &xhsi.u.gnttab;
+    void *addr, *initial;
+    int err;
+
+    if (gnttab->max_nr_frames > 0) {
+        return 0;
+    }
+
+    addr = g_malloc(sizeof(addr) * max);
+    if (!addr) {
+        return -ENOMEM;
+    }
+
+    initial = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
+    if (!initial) {
+        g_free(addr);
+        return -ENOMEM;
+    }
+
+    xhsi.type = KVM_XEN_ATTR_TYPE_GNTTAB;
+    xhgt->flags = KVM_XEN_GNTTAB_F_INIT;
+    xhgt->init.max_frames = max;
+    xhgt->init.max_maptrack_frames = max;
+    xhgt->init.initial_frame = (__u64) initial;
+
+    err = kvm_vm_ioctl(cs->kvm_state, KVM_XEN_HVM_SET_ATTR, &xhsi);
+    if (err) {
+        g_free(addr);
+        qemu_vfree(initial);
+        return -EFAULT;
+    }
+
+    gnttab->nr_frames = 0;
+    gnttab->max_nr_frames = cpu->xen_gnttab_max_frames;
+    gnttab->frames = addr;
+    gnttab->frames[0] = initial;
+    return 0;
+}
+
+static int kvm_xen_hcall_gnttab_op(struct kvm_xen_exit *exit, X86CPU *cpu,
+                                   int cmd, uint64_t arg, int count)
+{
+    CPUState *cs = CPU(cpu);
+    int err = -ENOSYS;
+
+    switch (cmd) {
+    case GNTTABOP_set_version: {
+        struct gnttab_set_version *gsv;
+
+        gsv = gva_to_hva(cs, arg);
+        if (!gsv) {
+            err = -EFAULT;
+            break;
+        }
+
+        if (!gsv->version ||
+            gsv->version > cpu->xen_gnttab_max_version) {
+            err = -ENOTSUP;
+            break;
+        }
+
+        err = 0;
+        break;
+    }
+    }
+
+    exit->u.hcall.result = err;
+    return err ? HCALL_ERR : 0;
+}
+
 static int __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
 {
     uint16_t code = exit->u.hcall.input;
@@ -858,6 +967,10 @@ static int __kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
     case HVMOP_set_evtchn_upcall_vector:
         return kvm_xen_hcall_evtchn_upcall_vector(exit, cpu,
                                                   exit->u.hcall.params[0]);
+    case __HYPERVISOR_grant_table_op:
+        return kvm_xen_hcall_gnttab_op(exit, cpu, exit->u.hcall.params[0],
+                                       exit->u.hcall.params[1],
+                                       exit->u.hcall.params[2]);
     case __HYPERVISOR_sched_op_compat:
     case __HYPERVISOR_sched_op:
         return kvm_xen_hcall_sched_op(exit, cpu, exit->u.hcall.params[0],
@@ -912,6 +1025,7 @@ int kvm_xen_vcpu_init(CPUState *cs)
         return -ENOTSUP;
 
     kvm_xen_set_hypercall_page(cs);
+    kvm_xen_set_gnttab(cs);
     return 0;
 }