From nobody Mon Feb 9 13:58:00 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D088378822 for ; Tue, 3 Feb 2026 22:09:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770156600; cv=none; b=rAjG0gHYupKEQY38fm0QTfuhCYZmON2kcmRnQgcOj2bIyaSlXAMU4epHpdya3O8JZVrIh0ERIvvJUSCSa5TQuihZfA9OnMr+fjA3B1ahjP4QNRxdnDmW7Q3q62tuPvuy8YNJZaoho1jbvVEIngFhlLpHE9AHxmGI62LQKfUT+GI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770156600; c=relaxed/simple; bh=XmH949+cFNYEHjPb6Flo1g0WANgdqrWkFIs/6XqOnbo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=c+J4Br+ZfuKtRPdjnTongQmEI+zPgdNqiYKe2BNAMAI8yOcL84PF9NY03ryZ91Wpz7WYfkf5Szqz28na/UCQ36UteZ5ajEaj9Uj91lhEZVrmNCYNZwfe/nyHKIE4YFudPdF/W33QBrF6r4y84GP0p1i/bvedXnJ5L5sQp8gZ1sQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=G0HCQ5zc; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="G0HCQ5zc" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2a377e15716so162983795ad.3 for ; Tue, 03 Feb 2026 14:09:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1770156598; x=1770761398; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=yiKJgtR9ONUoXQPN4oexiJxFq7KWJtr+8+pAjx8UEac=; b=G0HCQ5zcM0mFtsB9CivvieMXS54Ms68VJ3V+S54m4DUsk86SjMyjQNybGwxhaYfLAw EDoCajjptvM3QUe8Z5FX9QyX2+3/a8b5Z7W6FS0QHUmM4h6UDPpc40J9oD2EpKa9JkqP 1DSSS0D2HBlV/OZbn1FSfiD7Bsp2fqBYLISQnHiQfJaLS6hzDG6rtHH3er8KhmZsSb1q 0KbLtkb6DOg0ZFithjlzXfHWIzO2aPdF/6bp/0mV3s52EUYRwDHoSPeoRp/PHvafeZt3 07jY5YhGpIbCQEqahVlMtemoIMiThFMLICGIpxhSFXs90dGhAUxtsJJsDMCCPL8BpDMO ahVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770156598; x=1770761398; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=yiKJgtR9ONUoXQPN4oexiJxFq7KWJtr+8+pAjx8UEac=; b=kLrVSNNlk8jT2Xnc8+0mU7BhJZxTQBXVk4x3Y+fBNd9LHd4GSW59yEuXZYCZP23e7/ kxfN5t8ORcTBNIHejqp59MgFXV6fPc7gpfZwKZCnPEgiYrvkKJ3pKQ86y883KBjwRWEt QdSL7siYhMl4D4GUjf3+29OL5dq1gpI+RDeVMIg8vyZ6Xqc+M/W1QcepHqtx1VotDSrk MyS9d4xRb0y1vGnzTOt4bqIIBOQLRt5CO/p4jeOfTCNa7Ye+xVLFrOc8PTA+iHlD7IhJ 3CRa51ZN7FF8wLfk+PLwyAYFosiFNFzMbzerAZVpbD+wegr6L8vbAlsCx5xyxNIXrD1d tcOw== X-Forwarded-Encrypted: i=1; AJvYcCXJVibDZ67a7DC/xKEQsRNQPaKpC8k2ggCoTkNUuxodHcPLmhAEj5Cz4djdnc+UKqq6RPLVzIbUe43iPus=@vger.kernel.org X-Gm-Message-State: AOJu0YxgqY9k29ZKbyXLxzXhY4ce5kfjEXpwN14cF/WW1ekON2uarLva 8BHFx9AxTEJs2Q/PiOsZGfdZoXpfAJ3Wd9iukdFu7Z2plOqZsvBDw35Er/xKh6RfGCk7d+Z0LiE p+ijDMKndBdagmw== X-Received: from plgz17.prod.google.com ([2002:a17:903:191:b0:2a7:8c71:aa97]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:1ac3:b0:2a0:d629:9035 with SMTP id d9443c01a7336-2a933bbe729mr7724415ad.3.1770156598471; Tue, 03 Feb 2026 14:09:58 -0800 (PST) Date: Tue, 3 Feb 2026 22:09:39 +0000 In-Reply-To: <20260203220948.2176157-1-skhawaja@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260203220948.2176157-1-skhawaja@google.com> X-Mailer: git-send-email 2.53.0.rc2.204.g2597b5adb4-goog Message-ID: <20260203220948.2176157-6-skhawaja@google.com> Subject: [PATCH 05/14] iommupt: Implement preserve/unpreserve/restore callbacks From: Samiullah Khawaja To: David Woodhouse , Lu Baolu , Joerg Roedel , Will Deacon , Jason Gunthorpe Cc: Samiullah Khawaja , Robin Murphy , Kevin Tian , Alex Williamson , Shuah Khan , iommu@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Saeed Mahameed , Adithya Jayachandran , Parav Pandit , Leon Romanovsky , William Tu , Pratyush Yadav , Pasha Tatashin , David Matlack , Andrew Morton , Chris Li , Pranjal Shrivastava , Vipin Sharma , YiFei Zhu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement the iommu domain ops for presevation, unpresevation and restoration of iommu domains for liveupdate. Use the existing page walker to preserve the ioptdesc of the top_table and the lower tables. Preserve the top_level also so it can be restored during boot. Signed-off-by: Samiullah Khawaja --- drivers/iommu/generic_pt/iommu_pt.h | 96 +++++++++++++++++++++++++++++ include/linux/generic_pt/iommu.h | 10 +++ 2 files changed, 106 insertions(+) diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt= /iommu_pt.h index 3327116a441c..0a1adb6312dd 100644 --- a/drivers/iommu/generic_pt/iommu_pt.h +++ b/drivers/iommu/generic_pt/iommu_pt.h @@ -921,6 +921,102 @@ int DOMAIN_NS(map_pages)(struct iommu_domain *domain,= unsigned long iova, } EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(map_pages), "GENERIC_PT_IOMMU"); =20 +/** + * unpreserve() - Unpreserve page tables and other state of a domain. + * @domain: Domain to unpreserve + */ +void DOMAIN_NS(unpreserve)(struct iommu_domain *domain, struct iommu_domai= n_ser *ser) +{ + struct pt_iommu *iommu_table =3D + container_of(domain, struct pt_iommu, domain); + struct pt_common *common =3D common_from_iommu(iommu_table); + struct pt_range range =3D pt_all_range(common); + struct pt_iommu_collect_args collect =3D { + .free_list =3D IOMMU_PAGES_LIST_INIT(collect.free_list), + }; + + iommu_pages_list_add(&collect.free_list, range.top_table); + pt_walk_range(&range, __collect_tables, &collect); + + iommu_unpreserve_pages(&collect.free_list, -1); +} +EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(unpreserve), "GENERIC_PT_IOMMU"); + +/** + * preserve() - Preserve page tables and other state of a domain. + * @domain: Domain to preserve + * + * Returns: -ERRNO on failure, on success. + */ +int DOMAIN_NS(preserve)(struct iommu_domain *domain, struct iommu_domain_s= er *ser) +{ + struct pt_iommu *iommu_table =3D + container_of(domain, struct pt_iommu, domain); + struct pt_common *common =3D common_from_iommu(iommu_table); + struct pt_range range =3D pt_all_range(common); + struct pt_iommu_collect_args collect =3D { + .free_list =3D IOMMU_PAGES_LIST_INIT(collect.free_list), + }; + int ret; + + iommu_pages_list_add(&collect.free_list, range.top_table); + pt_walk_range(&range, __collect_tables, &collect); + + ret =3D iommu_preserve_pages(&collect.free_list); + if (ret) + return ret; + + ser->top_table =3D virt_to_phys(range.top_table); + ser->top_level =3D range.top_level; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(preserve), "GENERIC_PT_IOMMU"); + +static int __restore_tables(struct pt_range *range, void *arg, + unsigned int level, struct pt_table_p *table) +{ + struct pt_state pts =3D pt_init(range, level, table); + int ret; + + for_each_pt_level_entry(&pts) { + if (pts.type =3D=3D PT_ENTRY_TABLE) { + iommu_restore_page(virt_to_phys(pts.table_lower)); + ret =3D pt_descend(&pts, arg, __restore_tables); + if (ret) + return ret; + } + } + return 0; +} + +/** + * restore() - Restore page tables and other state of a domain. + * @domain: Domain to preserve + * + * Returns: -ERRNO on failure, on success. + */ +int DOMAIN_NS(restore)(struct iommu_domain *domain, struct iommu_domain_se= r *ser) +{ + struct pt_iommu *iommu_table =3D + container_of(domain, struct pt_iommu, domain); + struct pt_common *common =3D common_from_iommu(iommu_table); + struct pt_range range =3D pt_all_range(common); + + iommu_restore_page(ser->top_table); + + /* Free new table */ + iommu_free_pages(range.top_table); + + /* Set the restored top table */ + pt_top_set(common, phys_to_virt(ser->top_table), ser->top_level); + + /* Restore all pages*/ + range =3D pt_all_range(common); + return pt_walk_range(&range, __restore_tables, NULL); +} +EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(restore), "GENERIC_PT_IOMMU"); + struct pt_unmap_args { struct iommu_pages_list free_list; pt_vaddr_t unmapped; diff --git a/include/linux/generic_pt/iommu.h b/include/linux/generic_pt/io= mmu.h index 9eefbb74efd0..b824a8642571 100644 --- a/include/linux/generic_pt/iommu.h +++ b/include/linux/generic_pt/iommu.h @@ -13,6 +13,7 @@ struct iommu_iotlb_gather; struct pt_iommu_ops; struct pt_iommu_driver_ops; struct iommu_dirty_bitmap; +struct iommu_domain_ser; =20 /** * DOC: IOMMU Radix Page Table @@ -198,6 +199,12 @@ struct pt_iommu_cfg { unsigned long iova, phys_addr_t paddr, \ size_t pgsize, size_t pgcount, \ int prot, gfp_t gfp, size_t *mapped); \ + int pt_iommu_##fmt##_preserve(struct iommu_domain *domain, \ + struct iommu_domain_ser *ser); \ + void pt_iommu_##fmt##_unpreserve(struct iommu_domain *domain, \ + struct iommu_domain_ser *ser); \ + int pt_iommu_##fmt##_restore(struct iommu_domain *domain, \ + struct iommu_domain_ser *ser); \ size_t pt_iommu_##fmt##_unmap_pages( \ struct iommu_domain *domain, unsigned long iova, \ size_t pgsize, size_t pgcount, \ @@ -224,6 +231,9 @@ struct pt_iommu_cfg { #define IOMMU_PT_DOMAIN_OPS(fmt) \ .iova_to_phys =3D &pt_iommu_##fmt##_iova_to_phys, \ .map_pages =3D &pt_iommu_##fmt##_map_pages, \ + .preserve =3D &pt_iommu_##fmt##_preserve, \ + .unpreserve =3D &pt_iommu_##fmt##_unpreserve, \ + .restore =3D &pt_iommu_##fmt##_restore, \ .unmap_pages =3D &pt_iommu_##fmt##_unmap_pages #define IOMMU_PT_DIRTY_OPS(fmt) \ .read_and_clear_dirty =3D &pt_iommu_##fmt##_read_and_clear_dirty --=20 2.53.0.rc2.204.g2597b5adb4-goog