From nobody Thu Nov 6 10:32:13 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1540428954515435.17461055387264; Wed, 24 Oct 2018 17:55:54 -0700 (PDT) Received: from localhost ([::1]:51442 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFTwH-0004Yj-7e for importer@patchew.org; Wed, 24 Oct 2018 20:55:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57767) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFTtH-0002JJ-Ks for qemu-devel@nongnu.org; Wed, 24 Oct 2018 20:52:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gFTtG-0004DW-9s for qemu-devel@nongnu.org; Wed, 24 Oct 2018 20:52:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:45336) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gFTtE-00047p-Rn; Wed, 24 Oct 2018 20:52:46 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E63858046F; Thu, 25 Oct 2018 00:52:40 +0000 (UTC) Received: from redhat.com (ovpn-120-69.rdu2.redhat.com [10.10.120.69]) by smtp.corp.redhat.com (Postfix) with SMTP id 819F860C46; Thu, 25 Oct 2018 00:52:33 +0000 (UTC) Date: Wed, 24 Oct 2018 20:52:32 -0400 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Message-ID: <20181025005110.249256-4-mst@redhat.com> References: <20181025005110.249256-1-mst@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20181025005110.249256-1-mst@redhat.com> X-Mutt-Fcc: =sent X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Thu, 25 Oct 2018 00:52:41 +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 v2 03/28] intel_iommu: better handling of dmar state switch 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 , Eduardo Habkost , Jason Wang , Cong Li , QEMU Stable , Peter Xu , Eric Auger , Paolo Bonzini , Richard Henderson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Peter Xu QEMU is not handling the global DMAR switch well, especially when from "on" to "off". Let's first take the example of system reset. Assuming that a guest has IOMMU enabled. When it reboots, we will drop all the existing DMAR mappings to handle the system reset, however we'll still keep the existing memory layouts which has the IOMMU memory region enabled. So after the reboot and before the kernel reloads again, there will be no mapping at all for the host device. That's problematic since any software (for example, SeaBIOS) that runs earlier than the kernel after the reboot will assume the IOMMU is disabled, so any DMA from the software will fail. For example, a guest that boots on an assigned NVMe device might fail to find the boot device after a system reboot/reset and we'll be able to observe SeaBIOS errors if we capture the debugging log: WARNING - Timeout at nvme_wait:144! Meanwhile, we should see DMAR errors on the host of that NVMe device. It's the DMA fault that caused a NVMe driver timeout. The correct fix should be that we do proper switching of device DMA address spaces when system resets, which will setup correct memory regions and notify the backend of the devices. This might not affect much on non-assigned devices since QEMU VT-d emulation will assume a default passthrough mapping if DMAR is not enabled in the GCMD register (please refer to vtd_iommu_translate). However that's required for an assigned devices, since that'll rebuild the correct GPA to HPA mapping that is needed for any DMA operation during guest bootstrap. Besides the system reset, we have some other places that might change the global DMAR status and we'd better do the same thing there. For example, when we change the state of GCMD register, or the DMAR root pointer. Do the same refresh for all these places. For these two places we'll also need to explicitly invalidate the context entry cache and iotlb cache. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=3D1625173 CC: QEMU Stable Reported-by: Cong Li Signed-off-by: Peter Xu -- v2: - do the same for GCMD write, or root pointer update [Alex] - test is carried out by me this time, by observing the vtd_switch_address_space tracepoint after system reboot v3: - rewrite commit message as suggested by Alex Signed-off-by: Peter Xu Reviewed-by: Eric Auger Reviewed-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1137861a9d..306708eb3b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -37,6 +37,8 @@ #include "kvm_i386.h" #include "trace.h" =20 +static void vtd_address_space_refresh_all(IntelIOMMUState *s); + static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val, uint64_t wmask, uint64_t w1cmask) { @@ -1436,7 +1438,7 @@ static void vtd_context_global_invalidate(IntelIOMMUS= tate *s) vtd_reset_context_cache_locked(s); } vtd_iommu_unlock(s); - vtd_switch_address_space_all(s); + vtd_address_space_refresh_all(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 @@ -1727,6 +1729,8 @@ static void vtd_handle_gcmd_srtp(IntelIOMMUState *s) vtd_root_table_setup(s); /* Ok - report back to driver */ vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_RTPS); + vtd_reset_caches(s); + vtd_address_space_refresh_all(s); } =20 /* Set Interrupt Remap Table Pointer */ @@ -1759,7 +1763,8 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bo= ol en) vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0); } =20 - vtd_switch_address_space_all(s); + vtd_reset_caches(s); + vtd_address_space_refresh_all(s); } =20 /* Handle Interrupt Remap Enable/Disable */ @@ -3059,6 +3064,12 @@ static void vtd_address_space_unmap_all(IntelIOMMUSt= ate *s) } } =20 +static void vtd_address_space_refresh_all(IntelIOMMUState *s) +{ + vtd_address_space_unmap_all(s); + vtd_switch_address_space_all(s); +} + static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) { memory_region_notify_one((IOMMUNotifier *)private, entry); @@ -3231,11 +3242,7 @@ static void vtd_reset(DeviceState *dev) IntelIOMMUState *s =3D INTEL_IOMMU_DEVICE(dev); =20 vtd_init(s); - - /* - * When device reset, throw away all mappings and external caches - */ - vtd_address_space_unmap_all(s); + vtd_address_space_refresh_all(s); } =20 static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int dev= fn) --=20 MST