Loading hw/i386/intel_iommu.c +58 −11 Original line number Diff line number Diff line Loading @@ -2008,9 +2008,13 @@ static Property vtd_properties[] = { /* Read IRTE entry with specific index */ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, VTD_IRTE *entry) VTD_IRTE *entry, uint16_t sid) { static const uint16_t vtd_svt_mask[VTD_SQ_MAX] = \ {0xffff, 0xfffb, 0xfff9, 0xfff8}; dma_addr_t addr = 0x00; uint16_t mask, source_id; uint8_t bus, bus_max, bus_min; addr = iommu->intr_root + index * sizeof(*entry); if (dma_memory_read(&address_space_memory, addr, entry, Loading @@ -2037,21 +2041,56 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, return -VTD_FR_IR_IRTE_RSVD; } /* * TODO: Check Source-ID corresponds to SVT (Source Validation * Type) bits */ if (sid != X86_IOMMU_SID_INVALID) { /* Validate IRTE SID */ source_id = le32_to_cpu(entry->source_id); switch (entry->sid_vtype) { case VTD_SVT_NONE: VTD_DPRINTF(IR, "No SID validation for IRTE index %d", index); break; case VTD_SVT_ALL: mask = vtd_svt_mask[entry->sid_q]; if ((source_id & mask) != (sid & mask)) { VTD_DPRINTF(GENERAL, "SID validation for IRTE index " "%d failed (reqid 0x%04x sid 0x%04x)", index, sid, source_id); return -VTD_FR_IR_SID_ERR; } break; case VTD_SVT_BUS: bus_max = source_id >> 8; bus_min = source_id & 0xff; bus = sid >> 8; if (bus > bus_max || bus < bus_min) { VTD_DPRINTF(GENERAL, "SID validation for IRTE index %d " "failed (bus %d outside %d-%d)", index, bus, bus_min, bus_max); return -VTD_FR_IR_SID_ERR; } break; default: VTD_DPRINTF(GENERAL, "Invalid SVT bits (0x%x) in IRTE index " "%d", entry->sid_vtype, index); /* Take this as verification failure. */ return -VTD_FR_IR_SID_ERR; break; } } return 0; } /* Fetch IRQ information of specific IR index */ static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, VTDIrq *irq) static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, VTDIrq *irq, uint16_t sid) { VTD_IRTE irte = {}; int ret = 0; ret = vtd_irte_get(iommu, index, &irte); ret = vtd_irte_get(iommu, index, &irte, sid); if (ret) { return ret; } Loading Loading @@ -2103,7 +2142,8 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) /* Interrupt remapping for MSI/MSI-X entry */ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, MSIMessage *translated) MSIMessage *translated, uint16_t sid) { int ret = 0; VTD_IR_MSIAddress addr; Loading Loading @@ -2146,7 +2186,7 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, index += origin->data & VTD_IR_MSI_DATA_SUBHANDLE; } ret = vtd_remap_irq_get(iommu, index, &irq); ret = vtd_remap_irq_get(iommu, index, &irq, sid); if (ret) { return ret; } Loading Loading @@ -2193,7 +2233,8 @@ do_not_translate: static int vtd_int_remap(X86IOMMUState *iommu, MSIMessage *src, MSIMessage *dst, uint16_t sid) { return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), src, dst); return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), src, dst, sid); } static MemTxResult vtd_mem_ir_read(void *opaque, hwaddr addr, Loading @@ -2209,11 +2250,17 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, { int ret = 0; MSIMessage from = {}, to = {}; uint16_t sid = X86_IOMMU_SID_INVALID; from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST; from.data = (uint32_t) value; ret = vtd_interrupt_remap_msi(opaque, &from, &to); if (!attrs.unspecified) { /* We have explicit Source ID */ sid = attrs.requester_id; } ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid); if (ret) { /* TODO: report error */ VTD_DPRINTF(GENERAL, "int remap fail for addr 0x%"PRIx64 Loading include/hw/i386/intel_iommu.h +17 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,23 @@ struct VTDIOTLBEntry { bool write_flags; }; /* VT-d Source-ID Qualifier types */ enum { VTD_SQ_FULL = 0x00, /* Full SID verification */ VTD_SQ_IGN_3 = 0x01, /* Ignore bit 3 */ VTD_SQ_IGN_2_3 = 0x02, /* Ignore bits 2 & 3 */ VTD_SQ_IGN_1_3 = 0x03, /* Ignore bits 1-3 */ VTD_SQ_MAX, }; /* VT-d Source Validation Types */ enum { VTD_SVT_NONE = 0x00, /* No validation */ VTD_SVT_ALL = 0x01, /* Do full validation */ VTD_SVT_BUS = 0x02, /* Validate bus range */ VTD_SVT_MAX, }; /* Interrupt Remapping Table Entry Definition */ union VTD_IRTE { struct { Loading Loading
hw/i386/intel_iommu.c +58 −11 Original line number Diff line number Diff line Loading @@ -2008,9 +2008,13 @@ static Property vtd_properties[] = { /* Read IRTE entry with specific index */ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, VTD_IRTE *entry) VTD_IRTE *entry, uint16_t sid) { static const uint16_t vtd_svt_mask[VTD_SQ_MAX] = \ {0xffff, 0xfffb, 0xfff9, 0xfff8}; dma_addr_t addr = 0x00; uint16_t mask, source_id; uint8_t bus, bus_max, bus_min; addr = iommu->intr_root + index * sizeof(*entry); if (dma_memory_read(&address_space_memory, addr, entry, Loading @@ -2037,21 +2041,56 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, return -VTD_FR_IR_IRTE_RSVD; } /* * TODO: Check Source-ID corresponds to SVT (Source Validation * Type) bits */ if (sid != X86_IOMMU_SID_INVALID) { /* Validate IRTE SID */ source_id = le32_to_cpu(entry->source_id); switch (entry->sid_vtype) { case VTD_SVT_NONE: VTD_DPRINTF(IR, "No SID validation for IRTE index %d", index); break; case VTD_SVT_ALL: mask = vtd_svt_mask[entry->sid_q]; if ((source_id & mask) != (sid & mask)) { VTD_DPRINTF(GENERAL, "SID validation for IRTE index " "%d failed (reqid 0x%04x sid 0x%04x)", index, sid, source_id); return -VTD_FR_IR_SID_ERR; } break; case VTD_SVT_BUS: bus_max = source_id >> 8; bus_min = source_id & 0xff; bus = sid >> 8; if (bus > bus_max || bus < bus_min) { VTD_DPRINTF(GENERAL, "SID validation for IRTE index %d " "failed (bus %d outside %d-%d)", index, bus, bus_min, bus_max); return -VTD_FR_IR_SID_ERR; } break; default: VTD_DPRINTF(GENERAL, "Invalid SVT bits (0x%x) in IRTE index " "%d", entry->sid_vtype, index); /* Take this as verification failure. */ return -VTD_FR_IR_SID_ERR; break; } } return 0; } /* Fetch IRQ information of specific IR index */ static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, VTDIrq *irq) static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, VTDIrq *irq, uint16_t sid) { VTD_IRTE irte = {}; int ret = 0; ret = vtd_irte_get(iommu, index, &irte); ret = vtd_irte_get(iommu, index, &irte, sid); if (ret) { return ret; } Loading Loading @@ -2103,7 +2142,8 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) /* Interrupt remapping for MSI/MSI-X entry */ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, MSIMessage *translated) MSIMessage *translated, uint16_t sid) { int ret = 0; VTD_IR_MSIAddress addr; Loading Loading @@ -2146,7 +2186,7 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, index += origin->data & VTD_IR_MSI_DATA_SUBHANDLE; } ret = vtd_remap_irq_get(iommu, index, &irq); ret = vtd_remap_irq_get(iommu, index, &irq, sid); if (ret) { return ret; } Loading Loading @@ -2193,7 +2233,8 @@ do_not_translate: static int vtd_int_remap(X86IOMMUState *iommu, MSIMessage *src, MSIMessage *dst, uint16_t sid) { return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), src, dst); return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), src, dst, sid); } static MemTxResult vtd_mem_ir_read(void *opaque, hwaddr addr, Loading @@ -2209,11 +2250,17 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, { int ret = 0; MSIMessage from = {}, to = {}; uint16_t sid = X86_IOMMU_SID_INVALID; from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST; from.data = (uint32_t) value; ret = vtd_interrupt_remap_msi(opaque, &from, &to); if (!attrs.unspecified) { /* We have explicit Source ID */ sid = attrs.requester_id; } ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid); if (ret) { /* TODO: report error */ VTD_DPRINTF(GENERAL, "int remap fail for addr 0x%"PRIx64 Loading
include/hw/i386/intel_iommu.h +17 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,23 @@ struct VTDIOTLBEntry { bool write_flags; }; /* VT-d Source-ID Qualifier types */ enum { VTD_SQ_FULL = 0x00, /* Full SID verification */ VTD_SQ_IGN_3 = 0x01, /* Ignore bit 3 */ VTD_SQ_IGN_2_3 = 0x02, /* Ignore bits 2 & 3 */ VTD_SQ_IGN_1_3 = 0x03, /* Ignore bits 1-3 */ VTD_SQ_MAX, }; /* VT-d Source Validation Types */ enum { VTD_SVT_NONE = 0x00, /* No validation */ VTD_SVT_ALL = 0x01, /* Do full validation */ VTD_SVT_BUS = 0x02, /* Validate bus range */ VTD_SVT_MAX, }; /* Interrupt Remapping Table Entry Definition */ union VTD_IRTE { struct { Loading