lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20231202092245.14335-1-yan.y.zhao@intel.com>
Date:   Sat,  2 Dec 2023 17:22:45 +0800
From:   Yan Zhao <yan.y.zhao@...el.com>
To:     iommu@...ts.linux.dev, kvm@...r.kernel.org,
        linux-kernel@...r.kernel.org
Cc:     alex.williamson@...hat.com, jgg@...dia.com, pbonzini@...hat.com,
        seanjc@...gle.com, joro@...tes.org, will@...nel.org,
        robin.murphy@....com, kevin.tian@...el.com,
        baolu.lu@...ux.intel.com, dwmw2@...radead.org, yi.l.liu@...el.com,
        Yan Zhao <yan.y.zhao@...el.com>
Subject: [RFC PATCH 15/42] iommufd: Add iopf handler to KVM hw pagetable

Add iopf handler to KVM HW page table. The iopf handler is implemented to
forward IO page fault requests to KVM and return complete status back to
IOMMU driver via iommu_page_response().

Signed-off-by: Yan Zhao <yan.y.zhao@...el.com>
---
 drivers/iommu/iommufd/hw_pagetable_kvm.c | 87 ++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/drivers/iommu/iommufd/hw_pagetable_kvm.c b/drivers/iommu/iommufd/hw_pagetable_kvm.c
index e0e205f384ed5..bff9fa3d9f703 100644
--- a/drivers/iommu/iommufd/hw_pagetable_kvm.c
+++ b/drivers/iommu/iommufd/hw_pagetable_kvm.c
@@ -6,6 +6,89 @@
 #include "../iommu-priv.h"
 #include "iommufd_private.h"
 
+static int iommufd_kvmtdp_fault(void *data, struct mm_struct *mm,
+				unsigned long addr, u32 perm)
+{
+	struct iommufd_hw_pagetable *hwpt = data;
+	struct kvm_tdp_fault_type fault_type = {0};
+	unsigned long gfn = addr >> PAGE_SHIFT;
+	struct kvm_tdp_fd *tdp_fd;
+	int ret;
+
+	if (!hwpt || !hwpt_is_kvm(hwpt))
+		return IOMMU_PAGE_RESP_INVALID;
+
+	tdp_fd = to_hwpt_kvm(hwpt)->context;
+	if (!tdp_fd->ops->fault)
+		return IOMMU_PAGE_RESP_INVALID;
+
+	fault_type.read = !!(perm & IOMMU_FAULT_PERM_READ);
+	fault_type.write = !!(perm & IOMMU_FAULT_PERM_WRITE);
+	fault_type.exec = !!(perm & IOMMU_FAULT_PERM_EXEC);
+
+	ret = tdp_fd->ops->fault(tdp_fd, mm, gfn, fault_type);
+	return ret ? IOMMU_PAGE_RESP_FAILURE : IOMMU_PAGE_RESP_SUCCESS;
+}
+
+static int iommufd_kvmtdp_complete_group(struct device *dev, struct iopf_fault *iopf,
+				    enum iommu_page_response_code status)
+{
+	struct iommu_page_response resp = {
+		.pasid			= iopf->fault.prm.pasid,
+		.grpid			= iopf->fault.prm.grpid,
+		.code			= status,
+	};
+
+	if ((iopf->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID) &&
+	    (iopf->fault.prm.flags & IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID))
+		resp.flags = IOMMU_PAGE_RESP_PASID_VALID;
+
+	return iommu_page_response(dev, &resp);
+}
+
+static void iommufd_kvmtdp_handle_iopf(struct work_struct *work)
+{
+	struct iopf_fault *iopf;
+	struct iopf_group *group;
+	enum iommu_page_response_code status = IOMMU_PAGE_RESP_SUCCESS;
+	struct iommu_domain *domain;
+	void *fault_data;
+	int ret;
+
+	group = container_of(work, struct iopf_group, work);
+	domain = group->domain;
+	fault_data = domain->fault_data;
+
+	list_for_each_entry(iopf, &group->faults, list) {
+		/*
+		 * For the moment, errors are sticky: don't handle subsequent
+		 * faults in the group if there is an error.
+		 */
+		if (status != IOMMU_PAGE_RESP_SUCCESS)
+			break;
+
+		status = iommufd_kvmtdp_fault(fault_data, domain->mm,
+					      iopf->fault.prm.addr,
+					      iopf->fault.prm.perm);
+	}
+
+	ret = iommufd_kvmtdp_complete_group(group->dev, &group->last_fault, status);
+
+	iopf_free_group(group);
+
+}
+
+static int iommufd_kvmtdp_iopf_handler(struct iopf_group *group)
+{
+	struct iommu_fault_param *fault_param = group->dev->iommu->fault_param;
+
+	INIT_WORK(&group->work, iommufd_kvmtdp_handle_iopf);
+	if (!queue_work(fault_param->queue->wq, &group->work))
+		return -EBUSY;
+
+	return 0;
+}
+
 static void iommufd_kvmtdp_invalidate(void *data,
 				      unsigned long start, unsigned long size)
 {
@@ -169,6 +252,10 @@ iommufd_hwpt_kvm_alloc(struct iommufd_ctx *ictx,
 		goto out_abort;
 	}
 
+	hwpt->domain->mm = current->mm;
+	hwpt->domain->iopf_handler = iommufd_kvmtdp_iopf_handler;
+	hwpt->domain->fault_data = hwpt;
+
 	rc = kvmtdp_register(tdp_fd, hwpt);
 	if (rc)
 		goto out_abort;
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ