From 6416da3579fced127f57e9c5fba79a2f9739c1b7 Mon Sep 17 00:00:00 2001 From: Joao Martins Date: Fri, 21 Sep 2018 11:27:06 -0400 Subject: [PATCH] i386/xen: handle GNTTABOP_set_version 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 --- linux-headers/linux/kvm.h | 19 +++++++ target/i386/cpu.c | 4 ++ target/i386/cpu.h | 2 + target/i386/xen-proto.h | 13 +++++ target/i386/xen.c | 114 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 8409d197fb..f15aee0c0a 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -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 { diff --git a/target/i386/cpu.c b/target/i386/cpu.c index afe27d0ed3..c6bce8c5fe 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -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 diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 3e0644b239..1c0cb47e7b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -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) diff --git a/target/i386/xen-proto.h b/target/i386/xen-proto.h index cf73f12ae6..2c5acd443f 100644 --- a/target/i386/xen-proto.h +++ b/target/i386/xen-proto.h @@ -11,6 +11,18 @@ #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 { diff --git a/target/i386/xen.c b/target/i386/xen.c index 0acaf76cf9..b112c50e4b 100644 --- a/target/i386/xen.c +++ b/target/i386/xen.c @@ -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; } -- 2.50.1