@@ -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);
@@ -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,
@@ -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);
}
@@ -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;
@@ -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);
@@ -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);
@@ -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
@@ -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