diff options
-rw-r--r-- | xen/arch/x86/hvm/hvm.c | 35 | ||||
-rw-r--r-- | xen/arch/x86/hvm/irq.c | 15 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmsi.c | 49 | ||||
-rw-r--r-- | xen/drivers/passthrough/io.c | 7 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/hvm.h | 6 | ||||
-rw-r--r-- | xen/include/asm-x86/msi.h | 3 | ||||
-rw-r--r-- | xen/include/public/hvm/hvm_op.h | 18 | ||||
-rw-r--r-- | xen/include/xen/hvm/irq.h | 2 | ||||
-rw-r--r-- | xen/include/xsm/xsm.h | 6 |
9 files changed, 117 insertions, 24 deletions
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 35bec23b75..9b92fc0186 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3285,6 +3285,36 @@ static int hvmop_set_pci_link_route( return rc; } +static int hvmop_inj_msi( + XEN_GUEST_HANDLE(xen_hvm_inj_msi_t) uop) +{ + struct xen_hvm_inj_msi op; + struct domain *d; + int rc; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + + rc = rcu_lock_remote_target_domain_by_id(op.domid, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto out; + + rc = xsm_hvm_inj_msi(d); + if ( rc ) + goto out; + + rc = 0; + hvm_inj_msi(d, op.addr, op.data); + + out: + rcu_unlock_domain(d); + return rc; +} + static int hvmop_flush_tlb_all(void) { struct domain *d = current->domain; @@ -3563,6 +3593,11 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) guest_handle_cast(arg, xen_hvm_set_isa_irq_level_t)); break; + case HVMOP_inj_msi: + rc = hvmop_inj_msi( + guest_handle_cast(arg, xen_hvm_inj_msi_t)); + break; + case HVMOP_set_pci_link_route: rc = hvmop_set_pci_link_route( guest_handle_cast(arg, xen_hvm_set_pci_link_route_t)); diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c index f560e392e6..f6f2613e21 100644 --- a/xen/arch/x86/hvm/irq.c +++ b/xen/arch/x86/hvm/irq.c @@ -26,6 +26,7 @@ #include <xen/irq.h> #include <asm/hvm/domain.h> #include <asm/hvm/support.h> +#include <asm/msi.h> /* Must be called with hvm_domain->irq_lock hold */ static void assert_irq(struct domain *d, unsigned ioapic_gsi, unsigned pic_irq) @@ -259,6 +260,20 @@ void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq) d->domain_id, link, old_isa_irq, isa_irq); } +void hvm_inj_msi(struct domain *d, uint64_t addr, uint32_t data) +{ + uint32_t tmp = (uint32_t) addr; + uint8_t dest = (tmp & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; + uint8_t dest_mode = !!(tmp & MSI_ADDR_DESTMODE_MASK); + uint8_t delivery_mode = (data & MSI_DATA_DELIVERY_MODE_MASK) + >> MSI_DATA_DELIVERY_MODE_SHIFT; + uint8_t trig_mode = (data & MSI_DATA_TRIGGER_MASK) + >> MSI_DATA_TRIGGER_SHIFT; + uint8_t vector = data & MSI_DATA_VECTOR_MASK; + + vmsi_deliver(d, vector, dest, dest_mode, delivery_mode, trig_mode); +} + void hvm_set_callback_via(struct domain *d, uint64_t via) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c index cba074852f..2457fb407e 100644 --- a/xen/arch/x86/hvm/vmsi.c +++ b/xen/arch/x86/hvm/vmsi.c @@ -65,29 +65,14 @@ static void vmsi_inj_irq( } } -int vmsi_deliver(struct domain *d, int pirq) +int vmsi_deliver( + struct domain *d, int vector, + uint8_t dest, uint8_t dest_mode, + uint8_t delivery_mode, uint8_t trig_mode) { - struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; - uint32_t flags = hvm_irq_dpci->mirq[pirq].gmsi.gflags; - int vector = hvm_irq_dpci->mirq[pirq].gmsi.gvec; - uint8_t dest = (uint8_t)flags; - uint8_t dest_mode = !!(flags & VMSI_DM_MASK); - uint8_t delivery_mode = (flags & VMSI_DELIV_MASK) >> GFLAGS_SHIFT_DELIV_MODE; - uint8_t trig_mode = (flags & VMSI_TRIG_MODE) >> GFLAGS_SHIFT_TRG_MODE; struct vlapic *target; struct vcpu *v; - HVM_DBG_LOG(DBG_LEVEL_IOAPIC, - "msi: dest=%x dest_mode=%x delivery_mode=%x " - "vector=%x trig_mode=%x\n", - dest, dest_mode, delivery_mode, vector, trig_mode); - - if ( !( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI ) ) - { - gdprintk(XENLOG_WARNING, "pirq %x not msi \n", pirq); - return 0; - } - switch ( delivery_mode ) { case dest_LowestPrio: @@ -125,6 +110,32 @@ int vmsi_deliver(struct domain *d, int pirq) return 1; } +int vmsi_deliver_pirq(struct domain *d, int pirq) +{ + struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; + uint32_t flags = hvm_irq_dpci->mirq[pirq].gmsi.gflags; + int vector = hvm_irq_dpci->mirq[pirq].gmsi.gvec; + uint8_t dest = (uint8_t)flags; + uint8_t dest_mode = !!(flags & VMSI_DM_MASK); + uint8_t delivery_mode = (flags & VMSI_DELIV_MASK) + >> GFLAGS_SHIFT_DELIV_MODE; + uint8_t trig_mode = (flags&VMSI_TRIG_MODE) >> GFLAGS_SHIFT_TRG_MODE; + + HVM_DBG_LOG(DBG_LEVEL_IOAPIC, + "msi: dest=%x dest_mode=%x delivery_mode=%x " + "vector=%x trig_mode=%x\n", + dest, dest_mode, delivery_mode, vector, trig_mode); + + if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI) ) + { + gdprintk(XENLOG_WARNING, "pirq %x not msi \n", pirq); + return 0; + } + + vmsi_deliver(d, vector, dest, dest_mode, delivery_mode, trig_mode); + return 1; +} + /* Return value, -1 : multi-dests, non-negative value: dest_vcpu_id */ int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode) { diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index d918c9ca62..aa7f07d844 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -454,10 +454,9 @@ void hvm_dpci_msi_eoi(struct domain *d, int vector) static int hvm_pci_msi_assert(struct domain *d, int pirq) { - if ( hvm_domain_use_pirq(d, pirq) ) - return send_guest_pirq(d, pirq); - else - return vmsi_deliver(d, pirq); + return (hvm_domain_use_pirq(d, pirq) + ? send_guest_pirq(d, pirq) + : vmsi_deliver_pirq(d, pirq)); } #endif diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 3ce78d7578..f9981414cd 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -199,7 +199,11 @@ void hvm_init_guest_time(struct domain *d); void hvm_set_guest_time(struct vcpu *v, u64 guest_time); u64 hvm_get_guest_time(struct vcpu *v); -int vmsi_deliver(struct domain *d, int pirq); +int vmsi_deliver( + struct domain *d, int vector, + uint8_t dest, uint8_t dest_mode, + uint8_t delivery_mode, uint8_t trig_mode); +int vmsi_deliver_pirq(struct domain *d, int pirq); int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode); #define hvm_paging_enabled(v) \ diff --git a/xen/include/asm-x86/msi.h b/xen/include/asm-x86/msi.h index 760315e923..f7290ee768 100644 --- a/xen/include/asm-x86/msi.h +++ b/xen/include/asm-x86/msi.h @@ -19,6 +19,7 @@ #define MSI_DATA_DELIVERY_MODE_SHIFT 8 #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT) #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT) +#define MSI_DATA_DELIVERY_MODE_MASK 0x00000700 #define MSI_DATA_LEVEL_SHIFT 14 #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) @@ -27,6 +28,7 @@ #define MSI_DATA_TRIGGER_SHIFT 15 #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_MASK 0x00008000 /* * Shift/mask fields for msi address @@ -39,6 +41,7 @@ #define MSI_ADDR_DESTMODE_SHIFT 2 #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) +#define MSI_ADDR_DESTMODE_MASK 0x4 #define MSI_ADDR_REDIRECTION_SHIFT 3 #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h index 2a597da7d6..afe82789f6 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -240,4 +240,22 @@ 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__) + +/* MSI injection for emulated devices */ +#define HVMOP_inj_msi 16 +struct xen_hvm_inj_msi { + /* Domain to be injected */ + domid_t domid; + /* Data -- lower 32 bits */ + uint32_t data; + /* Address (0xfeexxxxx) */ + uint64_t addr; +}; +typedef struct xen_hvm_inj_msi xen_hvm_inj_msi_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_inj_msi_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index ae0531b328..3ef46b03cc 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -116,6 +116,8 @@ void hvm_isa_irq_deassert( void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq); +void hvm_inj_msi(struct domain *d, uint64_t addr, uint32_t data); + void hvm_maybe_deassert_evtchn_irq(void); void hvm_assert_evtchn_irq(struct vcpu *v); void hvm_set_callback_via(struct domain *d, uint64_t via); diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 512c070c81..e6587574c6 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -123,6 +123,7 @@ struct xsm_operations { int (*hvm_set_pci_intx_level) (struct domain *d); int (*hvm_set_isa_irq_level) (struct domain *d); int (*hvm_set_pci_link_route) (struct domain *d); + int (*hvm_inj_msi) (struct domain *d); int (*apic) (struct domain *d, int cmd); int (*assign_vector) (struct domain *d, uint32_t pirq); int (*xen_settime) (void); @@ -507,6 +508,11 @@ static inline int xsm_hvm_set_pci_link_route (struct domain *d) return xsm_call(hvm_set_pci_link_route(d)); } +static inline int xsm_hvm_inj_msi (struct domain *d) +{ + return xsm_call(hvm_inj_msi(d)); +} + static inline int xsm_apic (struct domain *d, int cmd) { return xsm_call(apic(d, cmd)); |