From patchwork Wed Apr 26 10:06:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Liu, Yi L" X-Patchwork-Id: 9700987 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 D3794603F4 for ; Wed, 26 Apr 2017 10:24:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF407284EE for ; Wed, 26 Apr 2017 10:24:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A40E3285F3; Wed, 26 Apr 2017 10:24:43 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D0854284EE for ; Wed, 26 Apr 2017 10:24:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2998095AbdDZKYl (ORCPT ); Wed, 26 Apr 2017 06:24:41 -0400 Received: from mga02.intel.com ([134.134.136.20]:20231 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2998090AbdDZKYj (ORCPT ); Wed, 26 Apr 2017 06:24:39 -0400 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Apr 2017 03:24:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.37,254,1488873600"; d="scan'208";a="79066528" Received: from sky-dev.bj.intel.com ([10.238.145.47]) by orsmga002.jf.intel.com with ESMTP; 26 Apr 2017 03:24:36 -0700 From: "Liu, Yi L" To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Cc: kvm@vger.kernel.org, jasowang@redhat.com, iommu@lists.linux-foundation.org, kevin.tian@intel.com, ashok.raj@intel.com, jacob.jun.pan@intel.com, tianyu.lan@intel.com, yi.l.liu@intel.com, jean-philippe.brucker@arm.com, "Liu, Yi L" Subject: [RFC PATCH 15/20] intel_iommu: link whole guest pasid table to host Date: Wed, 26 Apr 2017 18:06:45 +0800 Message-Id: <1493201210-14357-16-git-send-email-yi.l.liu@linux.intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1493201210-14357-1-git-send-email-yi.l.liu@linux.intel.com> References: <1493201210-14357-1-git-send-email-yi.l.liu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP VT-d has a nested mode which allows SVM virtualization. Link the whole guest PASID table to host context entry and enable nested mode, pIOMMU would do nested translation for DMA request. Thus achieve GVA->HPA translation. When extended-context-entry is modified in guest, intel_iommu emulator should capture it, then link the whole guest PASID table to host and enable nested mode for the assigned device. Signed-off-by: Liu, Yi L --- hw/i386/intel_iommu.c | 121 +++++++++++++++++++++++++++++++++++++++-- hw/i386/intel_iommu_internal.h | 11 ++++ 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index f291995..cd6db65 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -36,6 +36,7 @@ #include "hw/i386/apic_internal.h" #include "kvm_i386.h" #include "trace.h" +#include /*#define DEBUG_INTEL_IOMMU*/ #ifdef DEBUG_INTEL_IOMMU @@ -55,6 +56,14 @@ static int vtd_dbgflags = VTD_DBGBIT(GENERAL) | VTD_DBGBIT(CSR); #define VTD_DPRINTF(what, fmt, ...) do {} while (0) #endif +typedef void (*vtd_device_hook)(VTDNotifierIterator *iter, + void *hook_info, + void *notify_info); + +static void vtd_context_inv_notify_hook(VTDNotifierIterator *iter, + void *hook_info, + void *notify_info); + #define FOR_EACH_ASSIGN_DEVICE(__notify_info_type, \ __opaque_type, \ __hook_info, \ @@ -1213,6 +1222,66 @@ static void vtd_iommu_replay_all(IntelIOMMUState *s) } } +void vtd_context_inv_notify_hook(VTDNotifierIterator *iter, + void *hook_info, + void *notify_info) +{ + struct pasid_table_info *pasidt_info; + IOMMUNotifierData iommu_data; + VTDContextHookInfo *context_hook_info; + uint16_t *host_sid; + pasidt_info = (struct pasid_table_info *) notify_info; + context_hook_info = (VTDContextHookInfo *) hook_info; + switch (context_hook_info->gran) { + case VTD_INV_DESC_CC_GLOBAL: + /* Fall through */ + case VTD_INV_DESC_CC_DOMAIN: + if (iter->did == *context_hook_info->did) { + break; + } + /* Fall through */ + case VTD_INV_DESC_CC_DEVICE: + if ((iter->did == *context_hook_info->did) && + (iter->sid == *context_hook_info->sid)) { + break; + } + /* Fall through */ + default: + return; + } + + pasidt_info->model = INTEL_IOMMU; + host_sid = (uint16_t *)&pasidt_info->opaque; + + pasidt_info->ptr = iter->ce[1].lo; + pasidt_info->size = iter->ce[1].lo & VTD_PASID_TABLE_SIZE_MASK; + *host_sid = iter->host_sid; + iommu_data.payload = (uint8_t *) pasidt_info; + iommu_data.payload_size = sizeof(*pasidt_info) + sizeof(*host_sid); + memory_region_notify_iommu_svm_bind(&iter->vtd_as->iommu, + &iommu_data); + return; +} + +static void vtd_context_cache_invalidate_notify(IntelIOMMUState *s, + uint16_t *did, + uint16_t *sid, + uint8_t gran, + vtd_device_hook hook_fn) +{ + VTDContextHookInfo context_hook_info = { + .did = did, + .sid = sid, + .gran = gran, + }; + + FOR_EACH_ASSIGN_DEVICE(struct pasid_table_info, + uint16_t, + &context_hook_info, + hook_fn); + return; +} + static void vtd_context_global_invalidate(IntelIOMMUState *s) { trace_vtd_inv_desc_cc_global(); @@ -1228,8 +1297,35 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) * VT-d emulation codes. */ vtd_iommu_replay_all(s); + + if (s->svm) { + vtd_context_cache_invalidate_notify(s, NULL, NULL, + VTD_INV_DESC_CC_GLOBAL, vtd_context_inv_notify_hook); + } } +static void vtd_context_domain_selective_invalidate(IntelIOMMUState *s, + uint16_t did) +{ + trace_vtd_inv_desc_cc_global(); + s->context_cache_gen++; + if (s->context_cache_gen == VTD_CONTEXT_CACHE_GEN_MAX) { + vtd_reset_context_cache(s); + } + /* + * From VT-d spec 6.5.2.1, a global context entry invalidation + * should be followed by a IOTLB global invalidation, so we should + * be safe even without this. Hoewever, let's replay the region as + * well to be safer, and go back here when we need finer tunes for + * VT-d emulation codes. + */ + vtd_iommu_replay_all(s); + + if (s->svm) { + vtd_context_cache_invalidate_notify(s, &did, NULL, + VTD_INV_DESC_CC_DOMAIN, vtd_context_inv_notify_hook); + } +} /* Find the VTD address space currently associated with a given bus number, */ @@ -1258,13 +1354,14 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num) */ static void vtd_context_device_invalidate(IntelIOMMUState *s, uint16_t source_id, + uint16_t did, uint16_t func_mask) { uint16_t mask; VTDBus *vtd_bus; VTDAddressSpace *vtd_as; uint8_t bus_n, devfn; - uint16_t devfn_it; + uint16_t devfn_it, sid_it; trace_vtd_inv_desc_cc_devices(source_id, func_mask); @@ -1311,6 +1408,12 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, * happened. */ memory_region_iommu_replay_all(&vtd_as->iommu); + if (s->svm) { + sid_it = vtd_make_source_id(pci_bus_num(vtd_bus->bus), + devfn_it); + vtd_context_cache_invalidate_notify(s, &did, &sid_it, + VTD_INV_DESC_CC_DEVICE, vtd_context_inv_notify_hook); + } } } } @@ -1324,6 +1427,7 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val) { uint64_t caig; uint64_t type = val & VTD_CCMD_CIRG_MASK; + uint16_t did; switch (type) { case VTD_CCMD_DOMAIN_INVL: @@ -1338,7 +1442,9 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val) case VTD_CCMD_DEVICE_INVL: caig = VTD_CCMD_DEVICE_INVL_A; - vtd_context_device_invalidate(s, VTD_CCMD_SID(val), VTD_CCMD_FM(val)); + did = VTD_CCMD_DID(val); + vtd_context_device_invalidate(s, VTD_CCMD_SID(val), + did, VTD_CCMD_FM(val)); break; default: @@ -1720,7 +1826,7 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) static bool vtd_process_context_cache_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { - uint16_t sid, fmask; + uint16_t sid, fmask, did; if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) { trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo); @@ -1728,17 +1834,22 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s, } switch (inv_desc->lo & VTD_INV_DESC_CC_G) { case VTD_INV_DESC_CC_DOMAIN: + did = VTD_INV_DESC_CC_DID(inv_desc->lo); + vtd_context_domain_selective_invalidate(s, did); trace_vtd_inv_desc_cc_domain( (uint16_t)VTD_INV_DESC_CC_DID(inv_desc->lo)); - /* Fall through */ + break; case VTD_INV_DESC_CC_GLOBAL: + trace_vtd_inv_desc_cc_domain( + (uint16_t)VTD_INV_DESC_CC_DID(inv_desc->lo)); vtd_context_global_invalidate(s); break; case VTD_INV_DESC_CC_DEVICE: sid = VTD_INV_DESC_CC_SID(inv_desc->lo); fmask = VTD_INV_DESC_CC_FM(inv_desc->lo); - vtd_context_device_invalidate(s, sid, fmask); + did = VTD_INV_DESC_CC_DID(inv_desc->lo); + vtd_context_device_invalidate(s, sid, did, fmask); break; default: diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 5178398..5ab7d77 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -439,6 +439,14 @@ typedef struct VTDRootEntry VTDRootEntry; #define VTD_EXT_CONTEXT_TT_NO_DEV_IOTLB (4ULL << 2) #define VTD_EXT_CONTEXT_TT_DEV_IOTLB (5ULL << 2) +struct VTDContextHookInfo { + uint16_t *did; + uint16_t *sid; + uint8_t gran; +}; + +typedef struct VTDContextHookInfo VTDContextHookInfo; + struct VTDNotifierIterator { VTDAddressSpace *vtd_as; VTDContextEntry *ce; @@ -450,6 +458,9 @@ struct VTDNotifierIterator { typedef struct VTDNotifierIterator VTDNotifierIterator; +/* Masks for struct VTDContextEntry - Extended Context */ +#define VTD_PASID_TABLE_SIZE_MASK 0xf + /* Paging Structure common */ #define VTD_SL_PT_PAGE_SIZE_MASK (1ULL << 7) /* Bits to decide the offset for each level */