static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, MSIMessage *translated) { int ret = 0; VTD_IR_MSIAddress addr; uint16_t index; VTDIrq irq = {}; assert(origin && translated); if (!iommu || !iommu->intr_enabled) { goto do_not_translate; } if (origin->address & VTD_MSI_ADDR_HI_MASK) { VTD_DPRINTF(GENERAL, "error: MSI addr high 32 bits nonzero" " during interrupt remapping: 0x%"PRIx32, (uint32_t)((origin->address & VTD_MSI_ADDR_HI_MASK) >> \ VTD_MSI_ADDR_HI_SHIFT)); return -VTD_FR_IR_REQ_RSVD; } addr.data = origin->address & VTD_MSI_ADDR_LO_MASK; if (le16_to_cpu(addr.__head) != 0xfee) { VTD_DPRINTF(GENERAL, "error: MSI addr low 32 bits invalid: " "0x%"PRIx32, addr.data); return -VTD_FR_IR_REQ_RSVD; } /* This is compatible mode. */ if (addr.int_mode != VTD_IR_INT_FORMAT_REMAP) { goto do_not_translate; } index = addr.index_h << 15 | le16_to_cpu(addr.index_l); #define VTD_IR_MSI_DATA_SUBHANDLE (0x0000ffff) #define VTD_IR_MSI_DATA_RESERVED (0xffff0000) if (addr.sub_valid) { /* See VT-d spec 5.1.2.2 and 5.1.3 on subhandle */ index += origin->data & VTD_IR_MSI_DATA_SUBHANDLE; } ret = vtd_remap_irq_get(iommu, index, &irq); if (ret) { return ret; } if (addr.sub_valid) { VTD_DPRINTF(IR, "received MSI interrupt"); if (origin->data & VTD_IR_MSI_DATA_RESERVED) { VTD_DPRINTF(GENERAL, "error: MSI data bits non-zero for " "interrupt remappable entry: 0x%"PRIx32, origin->data); return -VTD_FR_IR_REQ_RSVD; } } else { uint8_t vector = origin->data & 0xff; VTD_DPRINTF(IR, "received IOAPIC interrupt"); /* IOAPIC entry vector should be aligned with IRTE vector * (see vt-d spec 5.1.5.1). */ if (vector != irq.vector) { VTD_DPRINTF(GENERAL, "IOAPIC vector inconsistent: " "entry: %d, IRTE: %d, index: %d", vector, irq.vector, index); } } /* * We'd better keep the last two bits, assuming that guest OS * might modify it. Keep it does not hurt after all. */ irq.msi_addr_last_bits = addr.__not_care; /* Translate VTDIrq to MSI message */ vtd_generate_msi_message(&irq, translated); VTD_DPRINTF(IR, "mapping MSI 0x%"PRIx64":0x%"PRIx32 " -> " "0x%"PRIx64":0x%"PRIx32, origin->address, origin->data, translated->address, translated->data); return 0; do_not_translate: memcpy(translated, origin, sizeof(*origin)); return 0; }