From patchwork Mon Nov 28 15:51:52 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Aviv B.D." X-Patchwork-Id: 9449731 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 876B4600CB for ; Mon, 28 Nov 2016 15:58:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 72D6227DCE for ; Mon, 28 Nov 2016 15:58:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 63F4227E22; Mon, 28 Nov 2016 15:58:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8A6C827DCE for ; Mon, 28 Nov 2016 15:58:38 +0000 (UTC) Received: from localhost ([::1]:59622 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cBOKD-0004iT-Ko for patchwork-qemu-devel@patchwork.kernel.org; Mon, 28 Nov 2016 10:58:37 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45846) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cBOFO-00011E-WE for qemu-devel@nongnu.org; Mon, 28 Nov 2016 10:53:41 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cBOFL-0008Qc-Jv for qemu-devel@nongnu.org; Mon, 28 Nov 2016 10:53:39 -0500 Received: from mail-wj0-f195.google.com ([209.85.210.195]:33361) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cBOFL-0008QH-A1 for qemu-devel@nongnu.org; Mon, 28 Nov 2016 10:53:35 -0500 Received: by mail-wj0-f195.google.com with SMTP id kp2so14618756wjc.0 for ; Mon, 28 Nov 2016 07:53:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jecDkqmMtyXi4uTdP0VJwJLE9jzKUefDdVihxtJf0zc=; b=W/6h9fhLPB/AKJclXFedeFAlbMFCfy96gW6RAzYCyelsk8FjtHL7LN1YbSLp5xgmiV o4zeWvJ0h0xUEoB0z8+RfZkHd9O6HlWMDeudmDiOj4LMgSN8ic4DIY0WtdqWo1Zam9hr aXsv/+8o0oWfsfbF3jzBSU0ngt23IEXgCkcZrYqwmxS0At1VvcdgdZ+KIVF2lxUVZRP7 xYcaTQn2ivL+fh770jA4b9Ns4b+mbPktCkS531EJAF15JNKnXdRDO3ojBCEaulis3HS6 yKfYgLiUPZSFlvYTPiHGsISv+9mmO6X0j+IW6dAsRAePWPj6CEtCgjC5nm0I1JUqq8By iumw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jecDkqmMtyXi4uTdP0VJwJLE9jzKUefDdVihxtJf0zc=; b=Cn1+/zZ/y7GAckBbdfee/ECIRqkBoU654J8WlliepvbinfjqNsFapCuJMIzuBoh7m5 VZmIjBuZaTNOUe+G3SQuVnk2wzwtpzPyoTTuOuQ1m1scPzLtOIUSeVgCcfmJP4MwOeRP nRU6/YJKnG9rSfmb+NvPE2I5L9K7rd74k1vqRnk3N+JvWRY8u2waRnA5jMq9lZ9fikia nvim4gwizcH7RfzEpM5c7V4rnjkLbV3dLI1WriVxlzQN6FwJtXr/bwiWoFePk2ysUCbP BPJ8KU/sQWih0CtKp5exi8cobjS/5dDALzHcCg0q7dFvjs6Fozfxt7XwF+xnsaRB/O5t 1RHA== X-Gm-Message-State: AKaTC02BqPMvs8jhtoVr3rTvrHeG7+0BvrSotWaqJpCQxj7OluVFLThsBt0b74TxOF2qMw== X-Received: by 10.194.158.100 with SMTP id wt4mr23615148wjb.148.1480348353618; Mon, 28 Nov 2016 07:52:33 -0800 (PST) Received: from tapuz2.cslcs.technion.ac.il (tapuz2.cslcs.technion.ac.il. [132.68.206.212]) by smtp.gmail.com with ESMTPSA id jm6sm63173534wjb.27.2016.11.28.07.52.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 28 Nov 2016 07:52:32 -0800 (PST) From: "Aviv B.D" To: qemu-devel@nongnu.org Date: Mon, 28 Nov 2016 17:51:52 +0200 Message-Id: <1480348315-13332-3-git-send-email-bd.aviv@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1480348315-13332-1-git-send-email-bd.aviv@gmail.com> References: <1480348315-13332-1-git-send-email-bd.aviv@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.210.195 Subject: [Qemu-devel] [PATCH v7 2/5] IOMMU: change iommu_op->translate's is_write to flags, add support to NO_FAIL flag mode 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: "Michael S. Tsirkin" , Jan Kiszka , Aviv Ben-David , Peter Xu , Alex Williamson , Jason Wang Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: "Aviv Ben-David" Supports translation trials without reporting error to guest on translation failure. Signed-off-by: Aviv Ben-David --- exec.c | 3 ++- hw/alpha/typhoon.c | 2 +- hw/i386/amd_iommu.c | 4 ++-- hw/i386/intel_iommu.c | 59 +++++++++++++++++++++++++++++++------------------ hw/pci-host/apb.c | 2 +- hw/ppc/spapr_iommu.c | 2 +- hw/s390x/s390-pci-bus.c | 2 +- include/exec/memory.h | 6 +++-- memory.c | 3 ++- 9 files changed, 52 insertions(+), 31 deletions(-) diff --git a/exec.c b/exec.c index 3d867f1..126fb31 100644 --- a/exec.c +++ b/exec.c @@ -466,7 +466,8 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, break; } - iotlb = mr->iommu_ops->translate(mr, addr, is_write); + iotlb = mr->iommu_ops->translate(mr, addr, + is_write ? IOMMU_WO : IOMMU_RO); addr = ((iotlb.translated_addr & ~iotlb.addr_mask) | (addr & iotlb.addr_mask)); *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1); diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 883db13..a2840ac 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -664,7 +664,7 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr, /* TODO: A translation failure here ought to set PCI error codes on the Pchip and generate a machine check interrupt. */ static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); IOMMUTLBEntry ret; diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 47b79d9..1f0d76b 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -988,7 +988,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr) } static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); AMDVIState *s = as->iommu_state; @@ -1017,7 +1017,7 @@ static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr, return ret; } - amdvi_do_translate(as, addr, is_write, &ret); + amdvi_do_translate(as, addr, flags & IOMMU_WO, &ret); trace_amdvi_translation_result(as->bus_num, PCI_SLOT(as->devfn), PCI_FUNC(as->devfn), addr, ret.translated_addr); return ret; diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2cf07cd..05973b9 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -631,7 +631,8 @@ static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level) /* Given the @gpa, get relevant @slptep. @slpte_level will be the last level * of the translation, can be used for deciding the size of large page. */ -static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, bool is_write, +static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, + IOMMUAccessFlags flags, uint64_t *slptep, uint32_t *slpte_level, bool *reads, bool *writes) { @@ -640,7 +641,7 @@ static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, bool is_write, uint32_t offset; uint64_t slpte; uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce); - uint64_t access_right_check; + uint64_t access_right_check = 0; /* Check if @gpa is above 2^X-1, where X is the minimum of MGAW in CAP_REG * and AW in context-entry. @@ -651,7 +652,15 @@ static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, bool is_write, } /* FIXME: what is the Atomics request here? */ - access_right_check = is_write ? VTD_SL_W : VTD_SL_R; + if (flags & IOMMU_WO) { + access_right_check |= VTD_SL_W; + } + if (flags & IOMMU_RO) { + access_right_check |= VTD_SL_R; + } + if (flags & IOMMU_NO_FAIL) { + access_right_check |= VTD_SL_R | VTD_SL_W; + } while (true) { offset = vtd_gpa_level_offset(gpa, level); @@ -673,8 +682,8 @@ static int vtd_gpa_to_slpte(VTDContextEntry *ce, uint64_t gpa, bool is_write, if (!(slpte & access_right_check)) { VTD_DPRINTF(GENERAL, "error: lack of %s permission for " "gpa 0x%"PRIx64 " slpte 0x%"PRIx64, - (is_write ? "write" : "read"), gpa, slpte); - return is_write ? -VTD_FR_WRITE : -VTD_FR_READ; + (flags & IOMMU_WO ? "write" : "read"), gpa, slpte); + return (flags & IOMMU_WO) ? -VTD_FR_WRITE : -VTD_FR_READ; } if (vtd_slpte_nonzero_rsvd(slpte, level)) { VTD_DPRINTF(GENERAL, "error: non-zero reserved field in second " @@ -791,11 +800,13 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr) * * @bus_num: The bus number * @devfn: The devfn, which is the combined of device and function number - * @is_write: The access is a write operation + * @flags: The access permission of the operation, use IOMMU_NO_FAIL to + * suppress translation errors (e.g. no mapping present) * @entry: IOMMUTLBEntry that contain the addr to be translated and result */ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, - uint8_t devfn, hwaddr addr, bool is_write, + uint8_t devfn, hwaddr addr, + IOMMUAccessFlags flags, IOMMUTLBEntry *entry) { IntelIOMMUState *s = vtd_as->iommu_state; @@ -813,7 +824,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, /* Check if the request is in interrupt address range */ if (vtd_is_interrupt_addr(addr)) { - if (is_write) { + if (flags & IOMMU_WO) { /* FIXME: since we don't know the length of the access here, we * treat Non-DWORD length write requests without PASID as * interrupt requests, too. Withoud interrupt remapping support, @@ -829,7 +840,8 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, } else { VTD_DPRINTF(GENERAL, "error: read request from interrupt address " "gpa 0x%"PRIx64, addr); - vtd_report_dmar_fault(s, source_id, addr, VTD_FR_READ, is_write); + vtd_report_dmar_fault(s, source_id, addr, VTD_FR_READ, + flags & IOMMU_WO); return; } } @@ -858,12 +870,15 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD; if (ret_fr) { ret_fr = -ret_fr; - if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { - VTD_DPRINTF(FLOG, "fault processing is disabled for DMA " + if (!(flags & IOMMU_NO_FAIL)) { + if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { + VTD_DPRINTF(FLOG, "fault processing is disabled for DMA " "requests through this context-entry " "(with FPD Set)"); - } else { - vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); + } else { + vtd_report_dmar_fault(s, source_id, addr, ret_fr, + flags & IOMMU_WO); + } } return; } @@ -876,15 +891,17 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, cc_entry->context_cache_gen = s->context_cache_gen; } - ret_fr = vtd_gpa_to_slpte(&ce, addr, is_write, &slpte, &level, + ret_fr = vtd_gpa_to_slpte(&ce, addr, flags, &slpte, &level, &reads, &writes); if (ret_fr) { ret_fr = -ret_fr; - if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { - VTD_DPRINTF(FLOG, "fault processing is disabled for DMA requests " - "through this context-entry (with FPD Set)"); - } else { - vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); + if (!(flags & IOMMU_NO_FAIL)) { + if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { + VTD_DPRINTF(FLOG, "fault processing is disabled for DMA " + "requests through this context-entry (with FPD Set)"); + } else { + vtd_report_dmar_fault(s, source_id, addr, ret_fr, flags); + } } return; } @@ -1946,7 +1963,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr, } static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); IntelIOMMUState *s = vtd_as->iommu_state; @@ -1968,7 +1985,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, } vtd_do_iommu_translate(vtd_as, vtd_as->bus, vtd_as->devfn, addr, - is_write, &ret); + flags, &ret); VTD_DPRINTF(MMU, "bus %"PRIu8 " slot %"PRIu8 " func %"PRIu8 " devfn %"PRIu8 " gpa 0x%"PRIx64 " hpa 0x%"PRIx64, pci_bus_num(vtd_as->bus), diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 653e711..eaa7f34 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -209,7 +209,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) /* Called from RCU critical section */ static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { IOMMUState *is = container_of(iommu, IOMMUState, iommu); hwaddr baseaddr, offset; diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index ae30bbe..d19c3ff 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -110,7 +110,7 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table) /* Called from RCU critical section */ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); uint64_t tce; diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 63f6248..24d83e5 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -378,7 +378,7 @@ out: } static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) + IOMMUAccessFlags flags) { uint64_t pte; uint32_t flags; diff --git a/include/exec/memory.h b/include/exec/memory.h index 9728a2f..2d7ee54 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -57,6 +57,7 @@ typedef enum { IOMMU_RO = 1, IOMMU_WO = 2, IOMMU_RW = 3, + IOMMU_NO_FAIL = 4, /* may not be present, don't repport error to guest */ } IOMMUAccessFlags; struct IOMMUTLBEntry { @@ -168,10 +169,11 @@ struct MemoryRegionOps { }; typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps; - struct MemoryRegionIOMMUOps { /* Return a TLB entry that contains a given address. */ - IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, bool is_write); + IOMMUTLBEntry (*translate)(MemoryRegion *iommu, + hwaddr addr, + IOMMUAccessFlags flags); /* Returns minimum supported page size */ uint64_t (*get_min_page_size)(MemoryRegion *iommu); /* Called when IOMMU Notifier flag changed */ diff --git a/memory.c b/memory.c index 33110e9..9b88638 100644 --- a/memory.c +++ b/memory.c @@ -1627,7 +1627,8 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, granularity = memory_region_iommu_get_min_page_size(mr); for (addr = 0; addr < memory_region_size(mr); addr += granularity) { - iotlb = mr->iommu_ops->translate(mr, addr, is_write); + iotlb = mr->iommu_ops->translate(mr, addr, + is_write ? IOMMU_WO : IOMMU_RO); if (iotlb.perm != IOMMU_NONE) { n->notify(n, &iotlb); }