int vmsi_deliver(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) >> GLFAGS_SHIFT_DELIV_MODE; uint8_t trig_mode = (flags & VMSI_TRIG_MODE) >> GLFAGS_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: { target = vlapic_lowest_prio(d, NULL, 0, dest, dest_mode); if ( target != NULL ) vmsi_inj_irq(d, target, vector, trig_mode, delivery_mode); else HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "null round robin: " "vector=%x delivery_mode=%x\n", vector, dest_LowestPrio); break; } case dest_Fixed: case dest_ExtINT: { for_each_vcpu ( d, v ) if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mode) ) vmsi_inj_irq(d, vcpu_vlapic(v), vector, trig_mode, delivery_mode); break; } case dest_SMI: case dest_NMI: case dest_INIT: case dest__reserved_2: default: gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n", delivery_mode); break; } 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) { int dest_vcpu_id = -1, w = 0; struct vcpu *v; if ( d->max_vcpus == 1 ) return 0; for_each_vcpu ( d, v ) { if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mode) ) { w++; dest_vcpu_id = v->vcpu_id; } } if ( w > 1 ) return -1; return dest_vcpu_id; }
int vmsi_deliver( struct domain *d, int vector, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t trig_mode) { struct vlapic *target; struct vcpu *v; switch ( delivery_mode ) { case dest_LowestPrio: target = vlapic_lowest_prio(d, NULL, 0, dest, dest_mode); if ( target != NULL ) { vmsi_inj_irq(target, vector, trig_mode, delivery_mode); break; } HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "null MSI round robin: vector=%02x\n", vector); return -ESRCH; case dest_Fixed: for_each_vcpu ( d, v ) if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mode) ) vmsi_inj_irq(vcpu_vlapic(v), vector, trig_mode, delivery_mode); break; default: printk(XENLOG_G_WARNING "%pv: Unsupported MSI delivery mode %d for Dom%d\n", current, delivery_mode, d->domain_id); return -EINVAL; } return 0; }