From nobody Wed Nov 5 22:34:37 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 1537520074755702.7084403689399; Fri, 21 Sep 2018 01:54:34 -0700 (PDT) Received: from localhost ([::1]:54575 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g3HCn-0003ou-Ty for importer@patchew.org; Fri, 21 Sep 2018 04:54:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48778) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g3GhH-00067u-Ar for qemu-devel@nongnu.org; Fri, 21 Sep 2018 04:21:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g3GhG-00007a-Au for qemu-devel@nongnu.org; Fri, 21 Sep 2018 04:21:55 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52322) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1g3GhB-0008D3-HR; Fri, 21 Sep 2018 04:21:49 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BE5994E919; Fri, 21 Sep 2018 08:21:48 +0000 (UTC) Received: from laptop.redhat.com (ovpn-117-87.ams2.redhat.com [10.36.117.87]) by smtp.corp.redhat.com (Postfix) with ESMTP id E6F657D90A; Fri, 21 Sep 2018 08:21:35 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org Date: Fri, 21 Sep 2018 10:18:17 +0200 Message-Id: <20180921081819.9203-27-eric.auger@redhat.com> In-Reply-To: <20180921081819.9203-1-eric.auger@redhat.com> References: <20180921081819.9203-1-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Fri, 21 Sep 2018 08:21:48 +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] [RFC v2 26/28] hw/vfio/common: Handle fault_handler 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: yi.l.liu@intel.com, cdall@kernel.org, mst@redhat.com, jean-philippe.brucker@arm.com, peterx@redhat.com, alex.williamson@redhat.com 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 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We introduce a new IOMMU notifier, whose role is to register the fault notifier. The patch also implements the userspace fault handler. When the eventfd is signalled, the fault handler injects the set of collected faults into the IOMMU memory region. Signed-off-by: Eric Auger --- hw/vfio/common.c | 118 ++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 1 + 2 files changed, 119 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 172ddd396f..9548e962e5 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -37,12 +37,16 @@ #include "sysemu/kvm.h" #include "trace.h" #include "qapi/error.h" +#include "qemu/event_notifier.h" +#include "qemu/main-loop.h" =20 struct vfio_group_head vfio_group_list =3D QLIST_HEAD_INITIALIZER(vfio_group_list); struct vfio_as_head vfio_address_spaces =3D QLIST_HEAD_INITIALIZER(vfio_address_spaces); =20 +#define MAX_QUERIED_FAULT_EVENTS 10 + #ifdef CONFIG_KVM /* * We have a single VFIO pseudo device per KVM VM. Once created it lives @@ -349,6 +353,111 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void= **vaddr, return true; } =20 +/* + * At the moment we retrieve MAX_QUERIED_FAULT_EVENTS events + * TODO: loop until the ioctl returns count =3D 0 + */ +static void vfio_iommu_fault_handler(void *data) +{ + VFIOGuestIOMMU *giommu =3D (VFIOGuestIOMMU *)data; + IOMMUMemoryRegion *iommu =3D giommu->iommu; + struct vfio_iommu_type1_get_fault_events *ustruct; + size_t fault_buffer_size =3D + MAX_QUERIED_FAULT_EVENTS * sizeof(struct iommu_fault); + size_t argsz =3D sizeof(*ustruct) + fault_buffer_size; + int ret; + + ustruct =3D g_malloc0(argsz); + ustruct->argsz =3D argsz; + ustruct->count =3D 0; + + ret =3D ioctl(giommu->container->fd, VFIO_IOMMU_GET_FAULT_EVENTS, ustr= uct); + if (ret) { + error_report("%s: failed to get pending faults (%d)", + __func__, ret); + } + + assert(ustruct->count > 0); + memory_region_inject_faults(iommu, ustruct->count, ustruct->events); + + g_free(ustruct); + + ret =3D event_notifier_test_and_clear(giommu->fault_notifier); + if (!ret) { + error_report("Error when clearing fd=3D%d (ret =3D %d)", + event_notifier_get_fd(giommu->fault_notifier), ret); + } +} + +static void +vfio_iommu_fault_handler_register(IOMMUNotifier *n, IOMMUConfig *cfg) + +{ + VFIOGuestIOMMU *giommu =3D container_of(n, VFIOGuestIOMMU, n); + VFIOContainer *container =3D giommu->container; + struct vfio_iommu_type1_set_fault_eventfd info; + int ret; + + info.argsz =3D sizeof(info); + info.flags =3D 0; + + giommu->fault_notifier =3D g_malloc0(sizeof(EventNotifier)); + ret =3D event_notifier_init(giommu->fault_notifier, 0); + if (ret) { + error_report("%s: failed to init fault eventfd (%d)", + __func__, ret); + goto out; + } + + info.eventfd =3D event_notifier_get_fd(giommu->fault_notifier); + qemu_set_fd_handler(info.eventfd, vfio_iommu_fault_handler, NULL, giom= mu); + + memcpy(&info.config, &cfg->fault_cfg, sizeof(cfg->fault_cfg)); + + ret =3D ioctl(container->fd, VFIO_IOMMU_SET_FAULT_EVENTFD, &info); + if (ret) { + error_report("%s: failed to setup iommu fault propagation (%d)", + __func__, ret); + goto cleanup; + } + return; +cleanup: + qemu_set_fd_handler(info.eventfd, NULL, NULL, NULL); + event_notifier_cleanup(giommu->fault_notifier); +out: + g_free(giommu->fault_notifier); +} + +static void vfio_iommu_fault_handler_unregister(IOMMUNotifier *n) +{ + VFIOGuestIOMMU *giommu =3D container_of(n, VFIOGuestIOMMU, n); + VFIOContainer *container =3D giommu->container; + struct vfio_iommu_type1_set_fault_eventfd info; + int eventfd, ret; + + if (!(n->notifier_flags & IOMMU_NOTIFIER_INIT_CFG) || + !giommu->fault_notifier) { + return; + } + + eventfd =3D event_notifier_get_fd(giommu->fault_notifier); + if (eventfd < 0) { + return; + } + + info.argsz =3D sizeof(info); + info.flags =3D 0; + info.eventfd =3D -1; + ret =3D ioctl(container->fd, VFIO_IOMMU_SET_FAULT_EVENTFD, &info); + if (ret) { + error_report("%s: failed to stop iommu fault propagation (%d)", + __func__, ret); + } + qemu_set_fd_handler(eventfd, NULL, NULL, NULL); + event_notifier_cleanup(giommu->fault_notifier); + g_free(giommu->fault_notifier); +} + /* Program the guest @cfg on physical IOMMU stage 1 (nested mode) */ static void vfio_iommu_nested_notify(IOMMUNotifier *n, IOMMUConfig *cfg) @@ -754,6 +863,14 @@ static void vfio_listener_region_add(MemoryListener *l= istener, QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next= ); memory_region_register_iommu_notifier(section->mr, &giommu->n); =20 + /* Config notifier to register fault handler */ + giommu =3D vfio_alloc_guest_iommu(container, iommu_mr, offset); + iommu_config_notifier_init(&giommu->n, + vfio_iommu_fault_handler_register, + IOMMU_NOTIFIER_INIT_CFG, iommu_idx); + QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next= ); + memory_region_register_iommu_notifier(section->mr, &giommu->n); + /* IOTLB unmap notifier to propagate guest IOTLB invalidations= */ giommu =3D vfio_alloc_guest_iommu(container, iommu_mr, offset); iommu_iotlb_notifier_init(&giommu->n, vfio_iommu_unmap_notify, @@ -846,6 +963,7 @@ static void vfio_listener_region_del(MemoryListener *li= stener, } else if (is_iommu_config_notifier(&giommu->n)) { memory_region_unregister_iommu_notifier(section->mr, &giommu->n); + vfio_iommu_fault_handler_unregister(&giommu->n); } QLIST_REMOVE(giommu, giommu_next); g_free(giommu); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 821def0565..db9cd93d77 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -91,6 +91,7 @@ typedef struct VFIOGuestIOMMU { hwaddr iommu_offset; IOMMUNotifier n; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; + EventNotifier *fault_notifier; } VFIOGuestIOMMU; =20 typedef struct VFIOHostDMAWindow { --=20 2.17.1