Note that we can't adjust HVM_IOREQSRV_BUFIOREQ_* to properly obey name space rules, as these constants as in use by callers of the libxc interface. Signed-off-by: Jan Beulich Reviewed-by: Wei Liu Reviewed-by: Paul Durrant Reviewed-by: Andrew Cooper --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -1416,23 +1416,14 @@ int xc_hvm_create_ioreq_server(xc_interf int handle_bufioreq, ioservid_t *id) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_create_ioreq_server_t, arg); + DECLARE_HVMCTL(create_ioreq_server, domid, + .handle_bufioreq = handle_bufioreq); int rc; - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; - - arg->domid = domid; - arg->handle_bufioreq = handle_bufioreq; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_create_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); + rc = do_hvmctl(xch, &hvmctl); - *id = arg->id; + *id = hvmctl.u.create_ioreq_server.id; - xc_hypercall_buffer_free(xch, arg); return rc; } @@ -1443,84 +1434,52 @@ int xc_hvm_get_ioreq_server_info(xc_inte xen_pfn_t *bufioreq_pfn, evtchn_port_t *bufioreq_port) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_get_ioreq_server_info_t, arg); + DECLARE_HVMCTL(get_ioreq_server_info, domid, + .id = id); int rc; - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; - - arg->domid = domid; - arg->id = id; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_get_ioreq_server_info, - HYPERCALL_BUFFER_AS_ARG(arg)); + rc = do_hvmctl(xch, &hvmctl); if ( rc != 0 ) - goto done; + return rc; if ( ioreq_pfn ) - *ioreq_pfn = arg->ioreq_pfn; + *ioreq_pfn = hvmctl.u.get_ioreq_server_info.ioreq_pfn; if ( bufioreq_pfn ) - *bufioreq_pfn = arg->bufioreq_pfn; + *bufioreq_pfn = hvmctl.u.get_ioreq_server_info.bufioreq_pfn; if ( bufioreq_port ) - *bufioreq_port = arg->bufioreq_port; + *bufioreq_port = hvmctl.u.get_ioreq_server_info.bufioreq_port; -done: - xc_hypercall_buffer_free(xch, arg); - return rc; + return 0; } int xc_hvm_map_io_range_to_ioreq_server(xc_interface *xch, domid_t domid, ioservid_t id, int is_mmio, uint64_t start, uint64_t end) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_io_range_t, arg); - int rc; - - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; - - arg->domid = domid; - arg->id = id; - arg->type = is_mmio ? HVMOP_IO_RANGE_MEMORY : HVMOP_IO_RANGE_PORT; - arg->start = start; - arg->end = end; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_map_io_range_to_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); + DECLARE_HVMCTL(map_io_range_to_ioreq_server, domid, + .id = id, + .type = is_mmio ? XEN_HVMCTL_IO_RANGE_MEMORY + : XEN_HVMCTL_IO_RANGE_PORT, + .start = start, + .end = end); - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_hvm_unmap_io_range_from_ioreq_server(xc_interface *xch, domid_t domid, ioservid_t id, int is_mmio, uint64_t start, uint64_t end) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_io_range_t, arg); - int rc; - - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; + DECLARE_HVMCTL(unmap_io_range_from_ioreq_server, domid, + .id = id, + .type = is_mmio ? XEN_HVMCTL_IO_RANGE_MEMORY + : XEN_HVMCTL_IO_RANGE_PORT, + .start = start, + .end = end); - arg->domid = domid; - arg->id = id; - arg->type = is_mmio ? HVMOP_IO_RANGE_MEMORY : HVMOP_IO_RANGE_PORT; - arg->start = start; - arg->end = end; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_unmap_io_range_from_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); - - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_hvm_map_pcidev_to_ioreq_server(xc_interface *xch, domid_t domid, @@ -1528,37 +1487,23 @@ int xc_hvm_map_pcidev_to_ioreq_server(xc uint8_t bus, uint8_t device, uint8_t function) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_io_range_t, arg); - int rc; + /* + * The underlying hypercall will deal with ranges of PCI SBDF + * but, for simplicity, the API only uses singletons. + */ + uint32_t sbdf = XEN_HVMCTL_PCI_SBDF(segment, bus, device, function); + DECLARE_HVMCTL(map_io_range_to_ioreq_server, domid, + .id = id, + .type = XEN_HVMCTL_IO_RANGE_PCI, + .start = sbdf, + .end = sbdf); if (device > 0x1f || function > 0x7) { errno = EINVAL; return -1; } - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; - - arg->domid = domid; - arg->id = id; - arg->type = HVMOP_IO_RANGE_PCI; - - /* - * The underlying hypercall will deal with ranges of PCI SBDF - * but, for simplicity, the API only uses singletons. - */ - arg->start = arg->end = HVMOP_PCI_SBDF((uint64_t)segment, - (uint64_t)bus, - (uint64_t)device, - (uint64_t)function); - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_map_io_range_to_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); - - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_hvm_unmap_pcidev_from_ioreq_server(xc_interface *xch, domid_t domid, @@ -1566,54 +1511,29 @@ int xc_hvm_unmap_pcidev_from_ioreq_serve uint8_t bus, uint8_t device, uint8_t function) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_io_range_t, arg); - int rc; + uint32_t sbdf = XEN_HVMCTL_PCI_SBDF(segment, bus, device, function); + DECLARE_HVMCTL(unmap_io_range_from_ioreq_server, domid, + .id = id, + .type = XEN_HVMCTL_IO_RANGE_PCI, + .start = sbdf, + .end = sbdf); if (device > 0x1f || function > 0x7) { errno = EINVAL; return -1; } - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; - - arg->domid = domid; - arg->id = id; - arg->type = HVMOP_IO_RANGE_PCI; - arg->start = arg->end = HVMOP_PCI_SBDF((uint64_t)segment, - (uint64_t)bus, - (uint64_t)device, - (uint64_t)function); - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_unmap_io_range_from_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); - - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_hvm_destroy_ioreq_server(xc_interface *xch, domid_t domid, ioservid_t id) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_destroy_ioreq_server_t, arg); - int rc; - - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; + DECLARE_HVMCTL(destroy_ioreq_server, domid, + .id = id); - arg->domid = domid; - arg->id = id; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_destroy_ioreq_server, - HYPERCALL_BUFFER_AS_ARG(arg)); - - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_hvm_set_ioreq_server_state(xc_interface *xch, @@ -1621,23 +1541,11 @@ int xc_hvm_set_ioreq_server_state(xc_int ioservid_t id, int enabled) { - DECLARE_HYPERCALL_BUFFER(xen_hvm_set_ioreq_server_state_t, arg); - int rc; - - arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); - if ( arg == NULL ) - return -1; + DECLARE_HVMCTL(set_ioreq_server_state, domid, + .id = id, + .enabled = !!enabled); - arg->domid = domid; - arg->id = id; - arg->enabled = !!enabled; - - rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, - HVMOP_set_ioreq_server_state, - HYPERCALL_BUFFER_AS_ARG(arg)); - - xc_hypercall_buffer_free(xch, arg); - return rc; + return do_hvmctl(xch, &hvmctl); } int xc_domain_setdebugging(xc_interface *xch, --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -34,8 +34,6 @@ #define XC_INTERNAL_COMPAT_MAP_FOREIGN_API #include "xenctrl.h" -#include - #include #include --- a/xen/arch/x86/hvm/control.c +++ b/xen/arch/x86/hvm/control.c @@ -20,6 +20,7 @@ #include #include #include +#include #include static int set_pci_intx_level(struct domain *d, @@ -292,6 +293,50 @@ long do_hvmctl(XEN_GUEST_HANDLE_PARAM(xe rc = hvm_inject_msi(d, op.u.inject_msi.addr, op.u.inject_msi.data); break; + case XEN_HVMCTL_create_ioreq_server: + rc = -EINVAL; + if ( op.u.create_ioreq_server.rsvd ) + break; + rc = hvm_create_ioreq_server(d, current->domain->domain_id, 0, + op.u.create_ioreq_server.handle_bufioreq, + &op.u.create_ioreq_server.id); + if ( rc == 0 && copy_field_to_guest(u_hvmctl, &op, + u.create_ioreq_server.id) ) + rc = -EFAULT; + break; + + case XEN_HVMCTL_get_ioreq_server_info: + rc = -EINVAL; + if ( op.u.get_ioreq_server_info.rsvd ) + break; + rc = hvm_get_ioreq_server_info(d, &op.u.get_ioreq_server_info); + if ( rc == 0 && copy_field_to_guest(u_hvmctl, &op, + u.get_ioreq_server_info) ) + rc = -EFAULT; + break; + + case XEN_HVMCTL_map_io_range_to_ioreq_server: + rc = hvm_map_io_range_to_ioreq_server( + d, &op.u.map_io_range_to_ioreq_server); + break; + + case XEN_HVMCTL_unmap_io_range_from_ioreq_server: + rc = hvm_unmap_io_range_from_ioreq_server( + d, &op.u.unmap_io_range_from_ioreq_server); + break; + + case XEN_HVMCTL_destroy_ioreq_server: + rc = hvm_destroy_ioreq_server(d, op.u.destroy_ioreq_server.id); + break; + + case XEN_HVMCTL_set_ioreq_server_state: + rc = -EINVAL; + if ( op.u.set_ioreq_server_state.rsvd ) + break; + rc = hvm_set_ioreq_server_state(d, op.u.set_ioreq_server_state.id, + !!op.u.set_ioreq_server_state.enabled); + break; + default: rc = -EOPNOTSUPP; break; --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -4487,195 +4487,6 @@ static int hvmop_flush_tlb_all(void) return 0; } -static int hvmop_create_ioreq_server( - XEN_GUEST_HANDLE_PARAM(xen_hvm_create_ioreq_server_t) uop) -{ - struct domain *curr_d = current->domain; - xen_hvm_create_ioreq_server_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_create_ioreq_server); - if ( rc != 0 ) - goto out; - - rc = hvm_create_ioreq_server(d, curr_d->domain_id, 0, - op.handle_bufioreq, &op.id); - if ( rc != 0 ) - goto out; - - rc = copy_to_guest(uop, &op, 1) ? -EFAULT : 0; - - out: - rcu_unlock_domain(d); - return rc; -} - -static int hvmop_get_ioreq_server_info( - XEN_GUEST_HANDLE_PARAM(xen_hvm_get_ioreq_server_info_t) uop) -{ - xen_hvm_get_ioreq_server_info_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_get_ioreq_server_info); - if ( rc != 0 ) - goto out; - - rc = hvm_get_ioreq_server_info(d, op.id, - &op.ioreq_pfn, - &op.bufioreq_pfn, - &op.bufioreq_port); - if ( rc != 0 ) - goto out; - - rc = copy_to_guest(uop, &op, 1) ? -EFAULT : 0; - - out: - rcu_unlock_domain(d); - return rc; -} - -static int hvmop_map_io_range_to_ioreq_server( - XEN_GUEST_HANDLE_PARAM(xen_hvm_io_range_t) uop) -{ - xen_hvm_io_range_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_map_io_range_to_ioreq_server); - if ( rc != 0 ) - goto out; - - rc = hvm_map_io_range_to_ioreq_server(d, op.id, op.type, - op.start, op.end); - - out: - rcu_unlock_domain(d); - return rc; -} - -static int hvmop_unmap_io_range_from_ioreq_server( - XEN_GUEST_HANDLE_PARAM(xen_hvm_io_range_t) uop) -{ - xen_hvm_io_range_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_unmap_io_range_from_ioreq_server); - if ( rc != 0 ) - goto out; - - rc = hvm_unmap_io_range_from_ioreq_server(d, op.id, op.type, - op.start, op.end); - - out: - rcu_unlock_domain(d); - return rc; -} - -static int hvmop_set_ioreq_server_state( - XEN_GUEST_HANDLE_PARAM(xen_hvm_set_ioreq_server_state_t) uop) -{ - xen_hvm_set_ioreq_server_state_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_set_ioreq_server_state); - if ( rc != 0 ) - goto out; - - rc = hvm_set_ioreq_server_state(d, op.id, !!op.enabled); - - out: - rcu_unlock_domain(d); - return rc; -} - -static int hvmop_destroy_ioreq_server( - XEN_GUEST_HANDLE_PARAM(xen_hvm_destroy_ioreq_server_t) uop) -{ - xen_hvm_destroy_ioreq_server_t op; - struct domain *d; - int rc; - - if ( copy_from_guest(&op, uop, 1) ) - return -EFAULT; - - rc = rcu_lock_remote_domain_by_id(op.domid, &d); - if ( rc != 0 ) - return rc; - - rc = -EINVAL; - if ( !is_hvm_domain(d) ) - goto out; - - rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, HVMOP_destroy_ioreq_server); - if ( rc != 0 ) - goto out; - - rc = hvm_destroy_ioreq_server(d, op.id); - - out: - rcu_unlock_domain(d); - return rc; -} - static int hvmop_set_evtchn_upcall_vector( XEN_GUEST_HANDLE_PARAM(xen_hvm_evtchn_upcall_vector_t) uop) { @@ -5192,36 +5003,6 @@ long do_hvm_op(unsigned long op, XEN_GUE switch ( op ) { - case HVMOP_create_ioreq_server: - rc = hvmop_create_ioreq_server( - guest_handle_cast(arg, xen_hvm_create_ioreq_server_t)); - break; - - case HVMOP_get_ioreq_server_info: - rc = hvmop_get_ioreq_server_info( - guest_handle_cast(arg, xen_hvm_get_ioreq_server_info_t)); - break; - - case HVMOP_map_io_range_to_ioreq_server: - rc = hvmop_map_io_range_to_ioreq_server( - guest_handle_cast(arg, xen_hvm_io_range_t)); - break; - - case HVMOP_unmap_io_range_from_ioreq_server: - rc = hvmop_unmap_io_range_from_ioreq_server( - guest_handle_cast(arg, xen_hvm_io_range_t)); - break; - - case HVMOP_set_ioreq_server_state: - rc = hvmop_set_ioreq_server_state( - guest_handle_cast(arg, xen_hvm_set_ioreq_server_state_t)); - break; - - case HVMOP_destroy_ioreq_server: - rc = hvmop_destroy_ioreq_server( - guest_handle_cast(arg, xen_hvm_destroy_ioreq_server_t)); - break; - case HVMOP_set_evtchn_upcall_vector: rc = hvmop_set_evtchn_upcall_vector( guest_handle_cast(arg, xen_hvm_evtchn_upcall_vector_t)); --- a/xen/arch/x86/hvm/ioreq.c +++ b/xen/arch/x86/hvm/ioreq.c @@ -513,9 +513,9 @@ static int hvm_ioreq_server_alloc_ranges char *name; rc = asprintf(&name, "ioreq_server %d %s", s->id, - (i == HVMOP_IO_RANGE_PORT) ? "port" : - (i == HVMOP_IO_RANGE_MEMORY) ? "memory" : - (i == HVMOP_IO_RANGE_PCI) ? "pci" : + (i == XEN_HVMCTL_IO_RANGE_PORT) ? "port" : + (i == XEN_HVMCTL_IO_RANGE_MEMORY) ? "memory" : + (i == XEN_HVMCTL_IO_RANGE_PCI) ? "pci" : ""); if ( rc ) goto fail; @@ -686,7 +686,8 @@ int hvm_create_ioreq_server(struct domai struct hvm_ioreq_server *s; int rc; - if ( bufioreq_handling > HVM_IOREQSRV_BUFIOREQ_ATOMIC ) + if ( !is_hvm_domain(d) || + bufioreq_handling > HVM_IOREQSRV_BUFIOREQ_ATOMIC ) return -EINVAL; rc = -ENOMEM; @@ -738,6 +739,9 @@ int hvm_destroy_ioreq_server(struct doma struct hvm_ioreq_server *s; int rc; + if ( !is_hvm_domain(d) ) + return -EINVAL; + spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock); rc = -ENOENT; @@ -772,14 +776,15 @@ int hvm_destroy_ioreq_server(struct doma return rc; } -int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id, - unsigned long *ioreq_pfn, - unsigned long *bufioreq_pfn, - evtchn_port_t *bufioreq_port) +int hvm_get_ioreq_server_info(struct domain *d, + struct xen_hvm_get_ioreq_server_info *info) { struct hvm_ioreq_server *s; int rc; + if ( !is_hvm_domain(d) ) + return -EINVAL; + spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock); rc = -ENOENT; @@ -790,15 +795,15 @@ int hvm_get_ioreq_server_info(struct dom if ( s == d->arch.hvm_domain.default_ioreq_server ) continue; - if ( s->id != id ) + if ( s->id != info->id ) continue; - *ioreq_pfn = s->ioreq.gmfn; + info->ioreq_pfn = s->ioreq.gmfn; if ( s->bufioreq.va != NULL ) { - *bufioreq_pfn = s->bufioreq.gmfn; - *bufioreq_port = s->bufioreq_evtchn; + info->bufioreq_pfn = s->bufioreq.gmfn; + info->bufioreq_port = s->bufioreq_evtchn; } rc = 0; @@ -810,13 +815,15 @@ int hvm_get_ioreq_server_info(struct dom return rc; } -int hvm_map_io_range_to_ioreq_server(struct domain *d, ioservid_t id, - uint32_t type, uint64_t start, - uint64_t end) +int hvm_map_io_range_to_ioreq_server(struct domain *d, + const struct xen_hvm_io_range *ior) { struct hvm_ioreq_server *s; int rc; + if ( ior->rsvd || !is_hvm_domain(d) ) + return -EINVAL; + spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock); rc = -ENOENT; @@ -827,16 +834,16 @@ int hvm_map_io_range_to_ioreq_server(str if ( s == d->arch.hvm_domain.default_ioreq_server ) continue; - if ( s->id == id ) + if ( s->id == ior->id ) { struct rangeset *r; - switch ( type ) + switch ( ior->type ) { - case HVMOP_IO_RANGE_PORT: - case HVMOP_IO_RANGE_MEMORY: - case HVMOP_IO_RANGE_PCI: - r = s->range[type]; + case XEN_HVMCTL_IO_RANGE_PORT: + case XEN_HVMCTL_IO_RANGE_MEMORY: + case XEN_HVMCTL_IO_RANGE_PCI: + r = s->range[ior->type]; break; default: @@ -849,10 +856,10 @@ int hvm_map_io_range_to_ioreq_server(str break; rc = -EEXIST; - if ( rangeset_overlaps_range(r, start, end) ) + if ( rangeset_overlaps_range(r, ior->start, ior->end) ) break; - rc = rangeset_add_range(r, start, end); + rc = rangeset_add_range(r, ior->start, ior->end); break; } } @@ -862,13 +869,15 @@ int hvm_map_io_range_to_ioreq_server(str return rc; } -int hvm_unmap_io_range_from_ioreq_server(struct domain *d, ioservid_t id, - uint32_t type, uint64_t start, - uint64_t end) +int hvm_unmap_io_range_from_ioreq_server(struct domain *d, + const struct xen_hvm_io_range *ior) { struct hvm_ioreq_server *s; int rc; + if ( ior->rsvd || !is_hvm_domain(d) ) + return -EINVAL; + spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock); rc = -ENOENT; @@ -879,16 +888,16 @@ int hvm_unmap_io_range_from_ioreq_server if ( s == d->arch.hvm_domain.default_ioreq_server ) continue; - if ( s->id == id ) + if ( s->id == ior->id ) { struct rangeset *r; - switch ( type ) + switch ( ior->type ) { - case HVMOP_IO_RANGE_PORT: - case HVMOP_IO_RANGE_MEMORY: - case HVMOP_IO_RANGE_PCI: - r = s->range[type]; + case XEN_HVMCTL_IO_RANGE_PORT: + case XEN_HVMCTL_IO_RANGE_MEMORY: + case XEN_HVMCTL_IO_RANGE_PCI: + r = s->range[ior->type]; break; default: @@ -901,10 +910,10 @@ int hvm_unmap_io_range_from_ioreq_server break; rc = -ENOENT; - if ( !rangeset_contains_range(r, start, end) ) + if ( !rangeset_contains_range(r, ior->start, ior->end) ) break; - rc = rangeset_remove_range(r, start, end); + rc = rangeset_remove_range(r, ior->start, ior->end); break; } } @@ -920,6 +929,9 @@ int hvm_set_ioreq_server_state(struct do struct list_head *entry; int rc; + if ( !is_hvm_domain(d) ) + return -EINVAL; + spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock); rc = -ENOENT; @@ -1128,12 +1140,12 @@ struct hvm_ioreq_server *hvm_select_iore /* PCI config data cycle */ - sbdf = HVMOP_PCI_SBDF(0, - PCI_BUS(CF8_BDF(cf8)), - PCI_SLOT(CF8_BDF(cf8)), - PCI_FUNC(CF8_BDF(cf8))); + sbdf = XEN_HVMCTL_PCI_SBDF(0, + PCI_BUS(CF8_BDF(cf8)), + PCI_SLOT(CF8_BDF(cf8)), + PCI_FUNC(CF8_BDF(cf8))); - type = HVMOP_IO_RANGE_PCI; + type = XEN_HVMCTL_IO_RANGE_PCI; addr = ((uint64_t)sbdf << 32) | CF8_ADDR_LO(cf8) | (p->addr & 3); @@ -1152,7 +1164,7 @@ struct hvm_ioreq_server *hvm_select_iore else { type = (p->type == IOREQ_TYPE_PIO) ? - HVMOP_IO_RANGE_PORT : HVMOP_IO_RANGE_MEMORY; + XEN_HVMCTL_IO_RANGE_PORT : XEN_HVMCTL_IO_RANGE_MEMORY; addr = p->addr; } @@ -1174,19 +1186,19 @@ struct hvm_ioreq_server *hvm_select_iore { unsigned long end; - case HVMOP_IO_RANGE_PORT: + case XEN_HVMCTL_IO_RANGE_PORT: end = addr + p->size - 1; if ( rangeset_contains_range(r, addr, end) ) return s; break; - case HVMOP_IO_RANGE_MEMORY: + case XEN_HVMCTL_IO_RANGE_MEMORY: end = addr + (p->size * p->count) - 1; if ( rangeset_contains_range(r, addr, end) ) return s; break; - case HVMOP_IO_RANGE_PCI: + case XEN_HVMCTL_IO_RANGE_PCI: if ( rangeset_contains_singleton(r, addr >> 32) ) { p->type = IOREQ_TYPE_PCI_CONFIG; --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,7 @@ struct hvm_ioreq_vcpu { bool_t pending; }; -#define NR_IO_RANGE_TYPES (HVMOP_IO_RANGE_PCI + 1) +#define NR_IO_RANGE_TYPES (XEN_HVMCTL_IO_RANGE_PCI + 1) #define MAX_NR_IO_RANGES 256 struct hvm_ioreq_server { --- a/xen/include/asm-x86/hvm/ioreq.h +++ b/xen/include/asm-x86/hvm/ioreq.h @@ -19,6 +19,8 @@ #ifndef __ASM_X86_HVM_IOREQ_H__ #define __ASM_X86_HVM_IOREQ_H__ +#include + bool_t hvm_io_pending(struct vcpu *v); bool_t handle_hvm_io_completion(struct vcpu *v); bool_t is_ioreq_server_page(struct domain *d, const struct page_info *page); @@ -27,16 +29,12 @@ int hvm_create_ioreq_server(struct domai bool_t is_default, int bufioreq_handling, ioservid_t *id); int hvm_destroy_ioreq_server(struct domain *d, ioservid_t id); -int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id, - unsigned long *ioreq_pfn, - unsigned long *bufioreq_pfn, - evtchn_port_t *bufioreq_port); -int hvm_map_io_range_to_ioreq_server(struct domain *d, ioservid_t id, - uint32_t type, uint64_t start, - uint64_t end); -int hvm_unmap_io_range_from_ioreq_server(struct domain *d, ioservid_t id, - uint32_t type, uint64_t start, - uint64_t end); +int hvm_get_ioreq_server_info(struct domain *d, + struct xen_hvm_get_ioreq_server_info *info); +int hvm_map_io_range_to_ioreq_server(struct domain *d, + const struct xen_hvm_io_range *r); +int hvm_unmap_io_range_from_ioreq_server(struct domain *d, + const struct xen_hvm_io_range *r); int hvm_set_ioreq_server_state(struct domain *d, ioservid_t id, bool_t enabled); --- a/xen/include/public/hvm/control.h +++ b/xen/include/public/hvm/control.h @@ -26,6 +26,7 @@ #endif #include "../xen.h" +#include "../event_channel.h" #define XEN_HVMCTL_INTERFACE_VERSION 0x00000001 @@ -130,6 +131,131 @@ struct xen_hvm_inject_msi { uint64_t addr; }; +/* + * IOREQ Servers + * + * The interface between an I/O emulator an Xen is called an IOREQ Server. + * A domain supports a single 'legacy' IOREQ Server which is instantiated if + * parameter... + * + * HVM_PARAM_IOREQ_PFN is read (to get the gmfn containing the synchronous + * ioreq structures), or... + * HVM_PARAM_BUFIOREQ_PFN is read (to get the gmfn containing the buffered + * ioreq ring), or... + * HVM_PARAM_BUFIOREQ_EVTCHN is read (to get the event channel that Xen uses + * to request buffered I/O emulation). + * + * The following hypercalls facilitate the creation of IOREQ Servers for + * 'secondary' emulators which are invoked to implement port I/O, memory, or + * PCI config space ranges which they explicitly register. + */ + +typedef uint16_t ioservid_t; + +/* + * XEN_HVMCTL_create_ioreq_server: Instantiate a new IOREQ Server for a + * secondary emulator servicing domain + * . + * + * The handed back is unique for . If is zero + * the buffered ioreq ring will not be allocated and hence all emulation + * requestes to this server will be synchronous. + */ +struct xen_hvm_create_ioreq_server { +#define HVM_IOREQSRV_BUFIOREQ_OFF 0 +#define HVM_IOREQSRV_BUFIOREQ_LEGACY 1 +/* + * Use this when read_pointer gets updated atomically and + * the pointer pair gets read atomically: + */ +#define HVM_IOREQSRV_BUFIOREQ_ATOMIC 2 + uint8_t handle_bufioreq; /* IN - should server handle buffered ioreqs */ + uint8_t rsvd; /* IN - must be zero */ + ioservid_t id; /* OUT - server id */ +}; + +/* + * XEN_HVMCTL_get_ioreq_server_info: Get all the information necessary to + * access IOREQ Server . + * + * The emulator needs to map the synchronous ioreq structures and buffered + * ioreq ring (if it exists) that Xen uses to request emulation. These are + * hosted in domain 's gmfns and + * respectively. In addition, if the IOREQ Server is handling buffered + * emulation requests, the emulator needs to bind to event channel + * to listen for them. (The event channels used for + * synchronous emulation requests are specified in the per-CPU ioreq + * structures in ). + * If the IOREQ Server is not handling buffered emulation requests then the + * values handed back in and will both be 0. + */ +struct xen_hvm_get_ioreq_server_info { + ioservid_t id; /* IN - server id */ + uint16_t rsvd; /* IN - must be zero */ + evtchn_port_t bufioreq_port; /* OUT - buffered ioreq port */ + uint64_aligned_t ioreq_pfn; /* OUT - sync ioreq pfn */ + uint64_aligned_t bufioreq_pfn; /* OUT - buffered ioreq pfn */ +}; + +/* + * XEN_HVMCTL_map_io_range_to_ioreq_server: Register an I/O range of domain + * for emulation by the + * client of IOREQ Server + * XEN_HVMCTL_unmap_io_range_from_ioreq_server: Deregister an I/O range of + * for emulation by the + * client of IOREQ Server + * + * There are three types of I/O that can be emulated: port I/O, memory accesses + * and PCI config space accesses. The field denotes which type of range + * the and (inclusive) fields are specifying. + * PCI config space ranges are specified by segment/bus/device/function values + * which should be encoded using the XEN_HVMCTL_PCI_SBDF helper macro below. + * + * NOTE: unless an emulation request falls entirely within a range mapped + * by a secondary emulator, it will not be passed to that emulator. + */ +struct xen_hvm_io_range { + ioservid_t id; /* IN - server id */ + uint16_t type; /* IN - type of range */ + uint32_t rsvd; /* IN - must be zero */ +#define XEN_HVMCTL_IO_RANGE_PORT 0 /* I/O port range */ +#define XEN_HVMCTL_IO_RANGE_MEMORY 1 /* MMIO range */ +#define XEN_HVMCTL_IO_RANGE_PCI 2 /* PCI segment/bus/dev/func range */ + uint64_aligned_t start, end; /* IN - inclusive start and end of range */ +}; + +#define XEN_HVMCTL_PCI_SBDF(s, b, d, f) \ + ((((s) & 0xffff) << 16) | \ + (((b) & 0xff) << 8) | \ + (((d) & 0x1f) << 3) | \ + ((f) & 0x07)) + +/* + * XEN_HVMCTL_destroy_ioreq_server: Destroy the IOREQ Server servicing + * domain . + * + * Any registered I/O ranges will be automatically deregistered. + */ +struct xen_hvm_destroy_ioreq_server { + ioservid_t id; /* IN - server id */ +}; + +/* + * XEN_HVMCTL_set_ioreq_server_state: Enable or disable the IOREQ Server + * servicing domain . + * + * The IOREQ Server will not be passed any emulation requests until it is in + * the enabled state. + * Note that the contents of the ioreq_pfn and bufioreq_fn (see + * XEN_HVMCTL_get_ioreq_server_info) are not meaningful until the IOREQ Server + * is in the enabled state. + */ +struct xen_hvm_set_ioreq_server_state { + ioservid_t id; /* IN - server id */ + uint8_t enabled; /* IN - enabled? */ + uint8_t rsvd; /* IN - must be zero */ +}; + struct xen_hvmctl { uint16_t interface_version; /* XEN_HVMCTL_INTERFACE_VERSION */ domid_t domain; @@ -142,6 +268,12 @@ struct xen_hvmctl { #define XEN_HVMCTL_set_mem_type 6 #define XEN_HVMCTL_inject_trap 7 #define XEN_HVMCTL_inject_msi 8 +#define XEN_HVMCTL_create_ioreq_server 9 +#define XEN_HVMCTL_get_ioreq_server_info 10 +#define XEN_HVMCTL_map_io_range_to_ioreq_server 11 +#define XEN_HVMCTL_unmap_io_range_from_ioreq_server 12 +#define XEN_HVMCTL_destroy_ioreq_server 13 +#define XEN_HVMCTL_set_ioreq_server_state 14 uint64_t opaque; /* Must be zero on initial invocation. */ union { struct xen_hvm_set_pci_intx_level set_pci_intx_level; @@ -152,6 +284,12 @@ struct xen_hvmctl { struct xen_hvm_set_mem_type set_mem_type; struct xen_hvm_inject_trap inject_trap; struct xen_hvm_inject_msi inject_msi; + struct xen_hvm_create_ioreq_server create_ioreq_server; + struct xen_hvm_get_ioreq_server_info get_ioreq_server_info; + struct xen_hvm_io_range map_io_range_to_ioreq_server; + struct xen_hvm_io_range unmap_io_range_from_ioreq_server; + struct xen_hvm_destroy_ioreq_server destroy_ioreq_server; + struct xen_hvm_set_ioreq_server_state set_ioreq_server_state; uint8_t pad[120]; } u; }; --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -25,7 +25,6 @@ #include "../xen.h" #include "../trace.h" -#include "../event_channel.h" /* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */ #define HVMOP_set_param 0 @@ -137,152 +136,6 @@ struct xen_hvm_get_mem_type { typedef struct xen_hvm_get_mem_type xen_hvm_get_mem_type_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_mem_type_t); -/* Following tools-only interfaces may change in future. */ -#if defined(__XEN__) || defined(__XEN_TOOLS__) - -/* - * IOREQ Servers - * - * The interface between an I/O emulator an Xen is called an IOREQ Server. - * A domain supports a single 'legacy' IOREQ Server which is instantiated if - * parameter... - * - * HVM_PARAM_IOREQ_PFN is read (to get the gmfn containing the synchronous - * ioreq structures), or... - * HVM_PARAM_BUFIOREQ_PFN is read (to get the gmfn containing the buffered - * ioreq ring), or... - * HVM_PARAM_BUFIOREQ_EVTCHN is read (to get the event channel that Xen uses - * to request buffered I/O emulation). - * - * The following hypercalls facilitate the creation of IOREQ Servers for - * 'secondary' emulators which are invoked to implement port I/O, memory, or - * PCI config space ranges which they explicitly register. - */ - -typedef uint16_t ioservid_t; - -/* - * HVMOP_create_ioreq_server: Instantiate a new IOREQ Server for a secondary - * emulator servicing domain . - * - * The handed back is unique for . If is zero - * the buffered ioreq ring will not be allocated and hence all emulation - * requestes to this server will be synchronous. - */ -#define HVMOP_create_ioreq_server 17 -struct xen_hvm_create_ioreq_server { - domid_t domid; /* IN - domain to be serviced */ -#define HVM_IOREQSRV_BUFIOREQ_OFF 0 -#define HVM_IOREQSRV_BUFIOREQ_LEGACY 1 -/* - * Use this when read_pointer gets updated atomically and - * the pointer pair gets read atomically: - */ -#define HVM_IOREQSRV_BUFIOREQ_ATOMIC 2 - uint8_t handle_bufioreq; /* IN - should server handle buffered ioreqs */ - ioservid_t id; /* OUT - server id */ -}; -typedef struct xen_hvm_create_ioreq_server xen_hvm_create_ioreq_server_t; -DEFINE_XEN_GUEST_HANDLE(xen_hvm_create_ioreq_server_t); - -/* - * HVMOP_get_ioreq_server_info: Get all the information necessary to access - * IOREQ Server . - * - * The emulator needs to map the synchronous ioreq structures and buffered - * ioreq ring (if it exists) that Xen uses to request emulation. These are - * hosted in domain 's gmfns and - * respectively. In addition, if the IOREQ Server is handling buffered - * emulation requests, the emulator needs to bind to event channel - * to listen for them. (The event channels used for - * synchronous emulation requests are specified in the per-CPU ioreq - * structures in ). - * If the IOREQ Server is not handling buffered emulation requests then the - * values handed back in and will both be 0. - */ -#define HVMOP_get_ioreq_server_info 18 -struct xen_hvm_get_ioreq_server_info { - domid_t domid; /* IN - domain to be serviced */ - ioservid_t id; /* IN - server id */ - evtchn_port_t bufioreq_port; /* OUT - buffered ioreq port */ - uint64_aligned_t ioreq_pfn; /* OUT - sync ioreq pfn */ - uint64_aligned_t bufioreq_pfn; /* OUT - buffered ioreq pfn */ -}; -typedef struct xen_hvm_get_ioreq_server_info xen_hvm_get_ioreq_server_info_t; -DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_ioreq_server_info_t); - -/* - * HVM_map_io_range_to_ioreq_server: Register an I/O range of domain - * for emulation by the client of IOREQ - * Server - * HVM_unmap_io_range_from_ioreq_server: Deregister an I/O range of - * for emulation by the client of IOREQ - * Server - * - * There are three types of I/O that can be emulated: port I/O, memory accesses - * and PCI config space accesses. The field denotes which type of range - * the and (inclusive) fields are specifying. - * PCI config space ranges are specified by segment/bus/device/function values - * which should be encoded using the HVMOP_PCI_SBDF helper macro below. - * - * NOTE: unless an emulation request falls entirely within a range mapped - * by a secondary emulator, it will not be passed to that emulator. - */ -#define HVMOP_map_io_range_to_ioreq_server 19 -#define HVMOP_unmap_io_range_from_ioreq_server 20 -struct xen_hvm_io_range { - domid_t domid; /* IN - domain to be serviced */ - ioservid_t id; /* IN - server id */ - uint32_t type; /* IN - type of range */ -# define HVMOP_IO_RANGE_PORT 0 /* I/O port range */ -# define HVMOP_IO_RANGE_MEMORY 1 /* MMIO range */ -# define HVMOP_IO_RANGE_PCI 2 /* PCI segment/bus/dev/func range */ - uint64_aligned_t start, end; /* IN - inclusive start and end of range */ -}; -typedef struct xen_hvm_io_range xen_hvm_io_range_t; -DEFINE_XEN_GUEST_HANDLE(xen_hvm_io_range_t); - -#define HVMOP_PCI_SBDF(s,b,d,f) \ - ((((s) & 0xffff) << 16) | \ - (((b) & 0xff) << 8) | \ - (((d) & 0x1f) << 3) | \ - ((f) & 0x07)) - -/* - * HVMOP_destroy_ioreq_server: Destroy the IOREQ Server servicing domain - * . - * - * Any registered I/O ranges will be automatically deregistered. - */ -#define HVMOP_destroy_ioreq_server 21 -struct xen_hvm_destroy_ioreq_server { - domid_t domid; /* IN - domain to be serviced */ - ioservid_t id; /* IN - server id */ -}; -typedef struct xen_hvm_destroy_ioreq_server xen_hvm_destroy_ioreq_server_t; -DEFINE_XEN_GUEST_HANDLE(xen_hvm_destroy_ioreq_server_t); - -/* - * HVMOP_set_ioreq_server_state: Enable or disable the IOREQ Server servicing - * domain . - * - * The IOREQ Server will not be passed any emulation requests until it is in the - * enabled state. - * Note that the contents of the ioreq_pfn and bufioreq_fn (see - * HVMOP_get_ioreq_server_info) are not meaningful until the IOREQ Server is in - * the enabled state. - */ -#define HVMOP_set_ioreq_server_state 22 -struct xen_hvm_set_ioreq_server_state { - domid_t domid; /* IN - domain to be serviced */ - ioservid_t id; /* IN - server id */ - uint8_t enabled; /* IN - enabled? */ -}; -typedef struct xen_hvm_set_ioreq_server_state xen_hvm_set_ioreq_server_state_t; -DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_ioreq_server_state_t); - -#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ - #if defined(__i386__) || defined(__x86_64__) /* --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -609,12 +609,6 @@ static XSM_INLINE int xsm_shadow_control return xsm_default_action(action, current->domain, d); } -static XSM_INLINE int xsm_hvm_ioreq_server(XSM_DEFAULT_ARG struct domain *d, int op) -{ - XSM_ASSERT_ACTION(XSM_DM_PRIV); - return xsm_default_action(action, current->domain, d); -} - static XSM_INLINE int xsm_mem_sharing_op(XSM_DEFAULT_ARG struct domain *d, struct domain *cd, int op) { XSM_ASSERT_ACTION(XSM_DM_PRIV); --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -174,7 +174,6 @@ struct xsm_operations { int (*do_mca) (void); int (*shadow_control) (struct domain *d, uint32_t op); int (*hvm_set_pci_link_route) (struct domain *d); - int (*hvm_ioreq_server) (struct domain *d, int op); int (*mem_sharing_op) (struct domain *d, struct domain *cd, int op); int (*apic) (struct domain *d, int cmd); int (*memtype) (uint32_t access); @@ -648,11 +647,6 @@ static inline int xsm_hvm_set_pci_link_r return xsm_ops->hvm_set_pci_link_route(d); } -static inline int xsm_hvm_ioreq_server (xsm_default_t def, struct domain *d, int op) -{ - return xsm_ops->hvm_ioreq_server(d, op); -} - static inline int xsm_mem_sharing_op (xsm_default_t def, struct domain *d, struct domain *cd, int op) { return xsm_ops->mem_sharing_op(d, cd, op); --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -145,7 +145,6 @@ void xsm_fixup_ops (struct xsm_operation #ifdef CONFIG_X86 set_to_dummy_if_null(ops, do_mca); set_to_dummy_if_null(ops, shadow_control); - set_to_dummy_if_null(ops, hvm_ioreq_server); set_to_dummy_if_null(ops, mem_sharing_op); set_to_dummy_if_null(ops, apic); set_to_dummy_if_null(ops, machine_memory_map); --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1526,11 +1526,6 @@ static int flask_ioport_mapping(struct d return flask_ioport_permission(d, start, end, access); } -static int flask_hvm_ioreq_server(struct domain *d, int op) -{ - return current_has_perm(d, SECCLASS_HVM, HVM__HVMCTL); -} - static int flask_mem_sharing_op(struct domain *d, struct domain *cd, int op) { int rc = current_has_perm(cd, SECCLASS_HVM, HVM__MEM_SHARING); @@ -1799,7 +1794,6 @@ static struct xsm_operations flask_ops = #ifdef CONFIG_X86 .do_mca = flask_do_mca, .shadow_control = flask_shadow_control, - .hvm_ioreq_server = flask_hvm_ioreq_server, .mem_sharing_op = flask_mem_sharing_op, .apic = flask_apic, .machine_memory_map = flask_machine_memory_map,