[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v6 04/19] xen/arm: Implement hypercall DOMCTL_{, un}bind_pt_pirq
From: Julien Grall <julien.grall@xxxxxxxxxx> On x86, an IRQ is assigned in 2 steps to an HVM guest: - The toolstack is calling PHYSDEVOP_map_pirq in order to create a guest PIRQ (IRQ bound to an event channel) - The emulator (QEMU) is calling DOMCTL_bind_pt_irq in order to bind the IRQ On ARM, there is no concept of PIRQ as the IRQ can be assigned to a virtual IRQ using the interrupt controller. It's not clear if we will need 2 different hypercalls on ARM to assign IRQ and, for now, only the toolstack will manage IRQ. In order to avoid re-using a fixed ABI hypercall (PHYSDEVOP_*) for a different purpose and allow us more time to figure out the right out, only DOMCTL_{,un}bind_pt_pirq is implemented on ARM. The DOMCTL is extended with a new type PT_IRQ_TYPE_SPI and only IRQ == vIRQ (i.e machine_irq == spi) is supported. In order to keep the same XSM checks done by the 2 hypercalls on x86, call both xsm_map_domain_irq & xsm_bind_pt_irq in the ARM implementation. Note: The toolstack changes for routing an IRQ to a guest will be done in a separate patch. Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx> Acked-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> --- Contrawise PHYSDEV, DOMCTL interface is not fixed. This version is using a DOMCTL in order to let us more to to see if we need a new PHYSDEV op for vIRQ assignation. DOMCTL_unbind_pt_irq has been implemented, although I haven't test it. I'm not sure if we want to keep it. xc_domain_{,un}bind_pt_irq are left unchanged because QEMU upstream & traditional are using them. I will send a follow-up series to drop this 2 functions in order to avoid defering this series while awaiting changes pushed for QEMU upstream. Changes in v6: - Rebase on the latest staging (conflict in xsm/flask/hooks.c with memaccess changes) - Remove obsolete paragraph in the commit message - Fix indentation in libxc - Don't rely on vspi == spi in xc_domain_{,un}bind_pt_spi_irq - Typoes in comment - Add Daniel's ack (XSM part) Changes in v5: - Do the check of XSM PHYSDEVOP_map_pirq in the ARM implementation - Left xc_domain_{,un}bind_pt_irq unchanged - Introduce xc_domain_{,un}bind_pt_spi_irq Changes in v4: - Move the implementation from PHYSDEV to DOMCTL. Reuse DOMCTL_{,un}bind_pt_irq for this purpose. Changes in v3: - Functions to allocate/release/reserved a VIRQ has been moved in a separate patch - Make clear that only MAP_PIRQ_GSI is only supported for now Changes in v2: - Add PHYSDEVOP_unmap_pirq - Rework commit message - Add functions to allocate/release a VIRQ - is_routable_irq has been renamed into is_assignable_irq --- tools/libxc/include/xenctrl.h | 10 ++++++ tools/libxc/xc_domain.c | 60 +++++++++++++++++++++++++++++++-- xen/arch/arm/domctl.c | 78 +++++++++++++++++++++++++++++++++++++++++++ xen/include/public/domctl.h | 4 +++ xen/include/xsm/dummy.h | 24 ++++++------- xen/include/xsm/xsm.h | 28 ++++++++-------- xen/xsm/dummy.c | 4 +-- xen/xsm/flask/hooks.c | 70 +++++++++++++++++++------------------- 8 files changed, 213 insertions(+), 65 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 6994c51..517a25f 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2115,6 +2115,16 @@ int xc_domain_bind_pt_isa_irq(xc_interface *xch, uint32_t domid, uint8_t machine_irq); +int xc_domain_bind_pt_spi_irq(xc_interface *xch, + uint32_t domid, + uint16_t vspi, + uint16_t spi); + +int xc_domain_unbind_pt_spi_irq(xc_interface *xch, + uint32_t domid, + uint16_t vspi, + uint16_t spi); + int xc_domain_set_machine_address_size(xc_interface *xch, uint32_t domid, unsigned int width); diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index d1dec6c..3ca9215 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -1797,7 +1797,7 @@ int xc_domain_unbind_msi_irq( } /* Pass-through: binds machine irq to guests irq */ -int xc_domain_bind_pt_irq( +static int xc_domain_bind_pt_irq_int( xc_interface *xch, uint32_t domid, uint8_t machine_irq, @@ -1805,7 +1805,8 @@ int xc_domain_bind_pt_irq( uint8_t bus, uint8_t device, uint8_t intx, - uint8_t isa_irq) + uint8_t isa_irq, + uint16_t spi) { int rc; xen_domctl_bind_pt_irq_t * bind; @@ -1829,6 +1830,9 @@ int xc_domain_bind_pt_irq( case PT_IRQ_TYPE_ISA: bind->u.isa.isa_irq = isa_irq; break; + case PT_IRQ_TYPE_SPI: + bind->u.spi.spi = spi; + break; default: errno = EINVAL; return -1; @@ -1838,7 +1842,7 @@ int xc_domain_bind_pt_irq( return rc; } -int xc_domain_unbind_pt_irq( +int xc_domain_bind_pt_irq( xc_interface *xch, uint32_t domid, uint8_t machine_irq, @@ -1848,6 +1852,21 @@ int xc_domain_unbind_pt_irq( uint8_t intx, uint8_t isa_irq) { + return xc_domain_bind_pt_irq_int(xch, domid, machine_irq, irq_type, + bus, device, intx, isa_irq, 0); +} + +static int xc_domain_unbind_pt_irq_int( + xc_interface *xch, + uint32_t domid, + uint8_t machine_irq, + uint8_t irq_type, + uint8_t bus, + uint8_t device, + uint8_t intx, + uint8_t isa_irq, + uint8_t spi) +{ int rc; xen_domctl_bind_pt_irq_t * bind; DECLARE_DOMCTL; @@ -1870,6 +1889,8 @@ int xc_domain_unbind_pt_irq( case PT_IRQ_TYPE_ISA: bind->u.isa.isa_irq = isa_irq; break; + case PT_IRQ_TYPE_SPI: + bind->u.spi.spi = spi; default: errno = EINVAL; return -1; @@ -1879,6 +1900,20 @@ int xc_domain_unbind_pt_irq( return rc; } +int xc_domain_unbind_pt_irq( + xc_interface *xch, + uint32_t domid, + uint8_t machine_irq, + uint8_t irq_type, + uint8_t bus, + uint8_t device, + uint8_t intx, + uint8_t isa_irq) +{ + return xc_domain_unbind_pt_irq_int(xch, domid, machine_irq, irq_type, + bus, device, intx, isa_irq, 0); +} + int xc_domain_bind_pt_pci_irq( xc_interface *xch, uint32_t domid, @@ -1902,6 +1937,25 @@ int xc_domain_bind_pt_isa_irq( PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq)); } +int xc_domain_bind_pt_spi_irq( + xc_interface *xch, + uint32_t domid, + uint16_t vspi, + uint16_t spi) +{ + return (xc_domain_bind_pt_irq_int(xch, domid, vspi, + PT_IRQ_TYPE_SPI, 0, 0, 0, 0, spi)); +} + +int xc_domain_unbind_pt_spi_irq(xc_interface *xch, + uint32_t domid, + uint16_t vspi, + uint16_t spi) +{ + return (xc_domain_unbind_pt_irq_int(xch, domid, vspi, + PT_IRQ_TYPE_SPI, 0, 0, 0, 0, spi)); +} + int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *minfo) { struct domain_info_context _di = { .guest_width = minfo->guest_width, diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index 6f30af7..4600019 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -10,6 +10,8 @@ #include <xen/errno.h> #include <xen/sched.h> #include <xen/hypercall.h> +#include <xen/iocap.h> +#include <xsm/xsm.h> #include <public/domctl.h> long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, @@ -30,6 +32,82 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, return p2m_cache_flush(d, s, e); } + case XEN_DOMCTL_bind_pt_irq: + { + int rc; + xen_domctl_bind_pt_irq_t *bind = &domctl->u.bind_pt_irq; + uint32_t irq = bind->u.spi.spi; + uint32_t virq = bind->machine_irq; + + /* We only support PT_IRQ_TYPE_SPI */ + if ( bind->irq_type != PT_IRQ_TYPE_SPI ) + return -EOPNOTSUPP; + + /* + * XXX: For now map the interrupt 1:1. Other support will require to + * modify domain_pirq_to_irq macro. + */ + if ( irq != virq ) + return -EINVAL; + + /* + * ARM doesn't require separating IRQ assignation into 2 + * hypercalls (PHYSDEVOP_map_pirq and DOMCTL_bind_pt_irq). + * + * Call xsm_map_domain_irq in order to keep the same XSM checks + * done by the 2 hypercalls for consistency with other + * architectures. + */ + rc = xsm_map_domain_irq(XSM_HOOK, d, irq, NULL); + if ( rc ) + return rc; + + rc = xsm_bind_pt_irq(XSM_HOOK, d, bind); + if ( rc ) + return rc; + + if ( !irq_access_permitted(current->domain, irq) ) + return -EPERM; + + if ( !vgic_reserve_virq(d, virq) ) + return -EBUSY; + + rc = route_irq_to_guest(d, virq, irq, "routed IRQ"); + if ( rc ) + vgic_free_virq(d, virq); + + return rc; + } + case XEN_DOMCTL_unbind_pt_irq: + { + int rc; + xen_domctl_bind_pt_irq_t *bind = &domctl->u.bind_pt_irq; + uint32_t irq = bind->u.spi.spi; + uint32_t virq = bind->machine_irq; + + /* We only support PT_IRQ_TYPE_SPI */ + if ( bind->irq_type != PT_IRQ_TYPE_SPI ) + return -EOPNOTSUPP; + + /* For now map the interrupt 1:1 */ + if ( irq != virq ) + return -EINVAL; + + rc = xsm_unbind_pt_irq(XSM_HOOK, d, bind); + if ( rc ) + return rc; + + if ( !irq_access_permitted(current->domain, irq) ) + return -EPERM; + + rc = release_guest_irq(d, virq); + if ( rc ) + return rc; + + vgic_free_virq(d, virq); + + return 0; + } default: return subarch_do_domctl(domctl, d, u_domctl); } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 10b51ef..35ed4f2 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -504,6 +504,7 @@ typedef enum pt_irq_type_e { PT_IRQ_TYPE_ISA, PT_IRQ_TYPE_MSI, PT_IRQ_TYPE_MSI_TRANSLATE, + PT_IRQ_TYPE_SPI, /* ARM: valid range 32-1019 */ } pt_irq_type_t; struct xen_domctl_bind_pt_irq { uint32_t machine_irq; @@ -524,6 +525,9 @@ struct xen_domctl_bind_pt_irq { uint32_t gflags; uint64_aligned_t gtable; } msi; + struct { + uint16_t spi; + } spi; } u; }; typedef struct xen_domctl_bind_pt_irq xen_domctl_bind_pt_irq_t; diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 16967ed..faeb096 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -445,6 +445,18 @@ static XSM_INLINE int xsm_unmap_domain_pirq(XSM_DEFAULT_ARG struct domain *d) return xsm_default_action(action, current->domain, d); } +static XSM_INLINE int xsm_bind_pt_irq(XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + XSM_ASSERT_ACTION(XSM_HOOK); + return xsm_default_action(action, current->domain, d); +} + +static XSM_INLINE int xsm_unbind_pt_irq(XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + XSM_ASSERT_ACTION(XSM_HOOK); + return xsm_default_action(action, current->domain, d); +} + static XSM_INLINE int xsm_unmap_domain_irq(XSM_DEFAULT_ARG struct domain *d, int irq, void *data) { XSM_ASSERT_ACTION(XSM_HOOK); @@ -647,18 +659,6 @@ static XSM_INLINE int xsm_priv_mapping(XSM_DEFAULT_ARG struct domain *d, struct return xsm_default_action(action, d, t); } -static XSM_INLINE int xsm_bind_pt_irq(XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - -static XSM_INLINE int xsm_unbind_pt_irq(XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, d); -} - static XSM_INLINE int xsm_ioport_permission(XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { XSM_ASSERT_ACTION(XSM_HOOK); diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 49f06c9..bbd4a18 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -107,6 +107,8 @@ struct xsm_operations { int (*map_domain_irq) (struct domain *d, int irq, void *data); int (*unmap_domain_pirq) (struct domain *d); int (*unmap_domain_irq) (struct domain *d, int irq, void *data); + int (*bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); + int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); int (*irq_permission) (struct domain *d, int pirq, uint8_t allow); int (*iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow); int (*iomem_mapping) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow); @@ -178,8 +180,6 @@ struct xsm_operations { int (*mmuext_op) (struct domain *d, struct domain *f); int (*update_va_mapping) (struct domain *d, struct domain *f, l1_pgentry_t pte); int (*priv_mapping) (struct domain *d, struct domain *t); - int (*bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); - int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); int (*ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow); int (*ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow); #endif @@ -428,6 +428,18 @@ static inline int xsm_unmap_domain_irq (xsm_default_t def, struct domain *d, int return xsm_ops->unmap_domain_irq(d, irq, data); } +static inline int xsm_bind_pt_irq(xsm_default_t def, struct domain *d, + struct xen_domctl_bind_pt_irq *bind) +{ + return xsm_ops->bind_pt_irq(d, bind); +} + +static inline int xsm_unbind_pt_irq(xsm_default_t def, struct domain *d, + struct xen_domctl_bind_pt_irq *bind) +{ + return xsm_ops->unbind_pt_irq(d, bind); +} + static inline int xsm_irq_permission (xsm_default_t def, struct domain *d, int pirq, uint8_t allow) { return xsm_ops->irq_permission(d, pirq, allow); @@ -666,18 +678,6 @@ static inline int xsm_priv_mapping(xsm_default_t def, struct domain *d, struct d return xsm_ops->priv_mapping(d, t); } -static inline int xsm_bind_pt_irq(xsm_default_t def, struct domain *d, - struct xen_domctl_bind_pt_irq *bind) -{ - return xsm_ops->bind_pt_irq(d, bind); -} - -static inline int xsm_unbind_pt_irq(xsm_default_t def, struct domain *d, - struct xen_domctl_bind_pt_irq *bind) -{ - return xsm_ops->unbind_pt_irq(d, bind); -} - static inline int xsm_ioport_permission (xsm_default_t def, struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { return xsm_ops->ioport_permission(d, s, e, allow); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 3ddb4f6..041ccf9 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -81,6 +81,8 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, map_domain_irq); set_to_dummy_if_null(ops, unmap_domain_pirq); set_to_dummy_if_null(ops, unmap_domain_irq); + set_to_dummy_if_null(ops, bind_pt_irq); + set_to_dummy_if_null(ops, unbind_pt_irq); set_to_dummy_if_null(ops, irq_permission); set_to_dummy_if_null(ops, iomem_permission); set_to_dummy_if_null(ops, iomem_mapping); @@ -149,8 +151,6 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, mmuext_op); set_to_dummy_if_null(ops, update_va_mapping); set_to_dummy_if_null(ops, priv_mapping); - set_to_dummy_if_null(ops, bind_pt_irq); - set_to_dummy_if_null(ops, unbind_pt_irq); set_to_dummy_if_null(ops, ioport_permission); set_to_dummy_if_null(ops, ioport_mapping); #endif diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6215001..29865d2 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -578,12 +578,14 @@ static int flask_domctl(struct domain *d, int cmd) case XEN_DOMCTL_memory_mapping: case XEN_DOMCTL_set_target: case XEN_DOMCTL_vm_event_op: + + /* These have individual XSM hooks (arch/../domctl.c) */ + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: #ifdef CONFIG_X86 /* These have individual XSM hooks (arch/x86/domctl.c) */ case XEN_DOMCTL_shadow_op: case XEN_DOMCTL_ioport_permission: - case XEN_DOMCTL_bind_pt_irq: - case XEN_DOMCTL_unbind_pt_irq: case XEN_DOMCTL_ioport_mapping: /* These have individual XSM hooks (drivers/passthrough/iommu.c) */ case XEN_DOMCTL_get_device_group: @@ -912,6 +914,36 @@ static int flask_unmap_domain_irq (struct domain *d, int irq, void *data) return rc; } +static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + u32 dsid, rsid; + int rc = -EPERM; + int irq; + struct avc_audit_data ad; + + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); + if ( rc ) + return rc; + + irq = domain_pirq_to_irq(d, bind->machine_irq); + + rc = get_irq_sid(irq, &rsid, &ad); + if ( rc ) + return rc; + + rc = avc_current_has_perm(rsid, SECCLASS_HVM, HVM__BIND_IRQ, &ad); + if ( rc ) + return rc; + + dsid = domain_sid(d); + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); +} + +static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE); +} + static int flask_irq_permission (struct domain *d, int pirq, uint8_t access) { /* the PIRQ number is not useful; real IRQ is checked during mapping */ @@ -1483,36 +1515,6 @@ static int flask_priv_mapping(struct domain *d, struct domain *t) { return domain_has_perm(d, t, SECCLASS_MMU, MMU__TARGET_HACK); } - -static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - u32 dsid, rsid; - int rc = -EPERM; - int irq; - struct avc_audit_data ad; - - rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); - if ( rc ) - return rc; - - irq = domain_pirq_to_irq(d, bind->machine_irq); - - rc = get_irq_sid(irq, &rsid, &ad); - if ( rc ) - return rc; - - rc = avc_current_has_perm(rsid, SECCLASS_HVM, HVM__BIND_IRQ, &ad); - if ( rc ) - return rc; - - dsid = domain_sid(d); - return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); -} - -static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE); -} #endif /* CONFIG_X86 */ long do_flask_op(XEN_GUEST_HANDLE_PARAM(xsm_op_t) u_flask_op); @@ -1571,6 +1573,8 @@ static struct xsm_operations flask_ops = { .map_domain_irq = flask_map_domain_irq, .unmap_domain_pirq = flask_unmap_domain_pirq, .unmap_domain_irq = flask_unmap_domain_irq, + .bind_pt_irq = flask_bind_pt_irq, + .unbind_pt_irq = flask_unbind_pt_irq, .irq_permission = flask_irq_permission, .iomem_permission = flask_iomem_permission, .iomem_mapping = flask_iomem_mapping, @@ -1640,8 +1644,6 @@ static struct xsm_operations flask_ops = { .mmuext_op = flask_mmuext_op, .update_va_mapping = flask_update_va_mapping, .priv_mapping = flask_priv_mapping, - .bind_pt_irq = flask_bind_pt_irq, - .unbind_pt_irq = flask_unbind_pt_irq, .ioport_permission = flask_ioport_permission, .ioport_mapping = flask_ioport_mapping, #endif -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |