From patchwork Thu Jul 21 16:28:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 651284 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rwKdb0gYZz9t0P for ; Fri, 22 Jul 2016 02:54:59 +1000 (AEST) Received: from localhost ([::1]:42117 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bQHFQ-0000et-Kf for incoming@patchwork.ozlabs.org; Thu, 21 Jul 2016 12:54:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46372) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bQGpl-0002kf-UL for qemu-devel@nongnu.org; Thu, 21 Jul 2016 12:28:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bQGph-0008IR-MG for qemu-devel@nongnu.org; Thu, 21 Jul 2016 12:28:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51632) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bQGph-0008IM-EF for qemu-devel@nongnu.org; Thu, 21 Jul 2016 12:28:21 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0F80C8E39E; Thu, 21 Jul 2016 16:28:21 +0000 (UTC) Received: from redhat.com (vpn1-7-84.ams2.redhat.com [10.36.7.84]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id u6LGSHcO030598; Thu, 21 Jul 2016 12:28:18 -0400 Date: Thu, 21 Jul 2016 19:28:17 +0300 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Message-ID: <1469118288-4776-29-git-send-email-mst@redhat.com> References: <1469118288-4776-1-git-send-email-mst@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1469118288-4776-1-git-send-email-mst@redhat.com> X-Mutt-Fcc: =sent X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 21 Jul 2016 16:28:21 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v4 28/57] intel_iommu: add SID validation for IR X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Richard Henderson , Eduardo Habkost , Peter Xu , Paolo Bonzini Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Peter Xu This patch enables SID validation. Invalid interrupts will be dropped. Signed-off-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/i386/intel_iommu.h | 17 +++++++++++ hw/i386/intel_iommu.c | 69 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 745b4e7..2eba7ed 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -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 { diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index aa7fb9b..3f49c17 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -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, @@ -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 = { 0 }; int ret = 0; - ret = vtd_irte_get(iommu, index, &irte); + ret = vtd_irte_get(iommu, index, &irte, sid); if (ret) { return ret; } @@ -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; @@ -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; } @@ -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, @@ -2209,11 +2250,17 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, { int ret = 0; MSIMessage from = {0}, to = {0}; + 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