From: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
To: linux-coco@lists.linux.dev, kvmarm@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, iommu@lists.linux.dev
Cc: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Baoquan He" <baoquan.he@linux.dev>,
"Mike Rapoport" <rppt@kernel.org>,
"Pasha Tatashin" <pasha.tatashin@soleen.com>,
"Pratyush Yadav" <pratyush@kernel.org>,
"Catalin Marinas" <catalin.marinas@arm.com>,
"Christian König" <christian.koenig@amd.com>,
"Jason Gunthorpe" <jgg@ziepe.ca>,
"Joerg Roedel" <joro@8bytes.org>, "Marc Zyngier" <maz@kernel.org>,
"Marek Szyprowski" <m.szyprowski@samsung.com>,
"Robin Murphy" <robin.murphy@arm.com>,
"Steven Price" <steven.price@arm.com>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Suzuki K Poulose" <suzuki.poulose@arm.com>,
"Thomas Gleixner" <tglx@kernel.org>,
"Will Deacon" <will@kernel.org>,
"Russell King" <linux@armlinux.org.uk>,
"Benjamin Gaignard" <benjamin.gaignard@collabora.com>,
"Brian Starkey" <Brian.Starkey@arm.com>,
"John Stultz" <jstultz@google.com>,
"Mark Rutland" <mark.rutland@arm.com>,
"Radu Rendec" <radu@rendec.net>,
"T.J. Mercier" <tjmercier@google.com>,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
"Michael Ellerman" <mpe@ellerman.id.au>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Christophe Leroy" <chleroy@kernel.org>,
"Ritesh Harjani" <ritesh.list@gmail.com>,
"Shrikanth Hegde" <sshegde@linux.ibm.com>,
"Alexander Gordeev" <agordeev@linux.ibm.com>,
"Gerald Schaefer" <gerald.schaefer@linux.ibm.com>,
"Heiko Carstens" <hca@linux.ibm.com>,
"Vasily Gorbik" <gor@linux.ibm.com>,
"Christian Borntraeger" <borntraeger@linux.ibm.com>,
"Sven Schnelle" <svens@linux.ibm.com>,
"Ingo Molnar" <mingo@redhat.com>,
"Borislav Petkov" <bp@alien8.de>,
"Dave Hansen" <dave.hansen@linux.intel.com>,
x86@kernel.org, "H . Peter Anvin" <hpa@zytor.com>,
"Kiryl Shutsemau" <kas@kernel.org>,
"Rick Edgecombe" <rick.p.edgecombe@intel.com>,
"K . Y . Srinivasan" <kys@microsoft.com>,
"Haiyang Zhang" <haiyangz@microsoft.com>,
"Wei Liu" <wei.liu@kernel.org>,
"Dexuan Cui" <decui@microsoft.com>,
"Long Li" <longli@microsoft.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Andy Lutomirski" <luto@kernel.org>,
"Peter Zijlstra" <peterz@infradead.org>,
dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org,
linux-media@vger.kernel.org, linux-mm@kvack.org
Subject: [RFC PATCH v8 01/14] mm: Add an allocator for CoCo shared memory
Date: Thu, 24 Sep 2026 15:35:16 +0530 [thread overview]
Message-ID: <20260924100529.1398790-2-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20260924100529.1398790-1-aneesh.kumar@kernel.org>
Confidential-computing guests may require memory shared with the host to
be aligned and transitioned in units larger than PAGE_SIZE. Several DMA
users need struct page-backed allocations satisfying these requirements.
Provide a common allocator instead of requiring each user to open-code
this sequence.
Add alloc_cc_shared_pages() and its node-aware variant. The allocator
rounds the requested size to the architecture's shared granule,
allocates suitably aligned contiguous pages and transitions the
complete range to shared state. It also preserves the caller's GFP
policy.
A private-to-shared transition may alter memory contents. Mask
__GFP_ZERO from the underlying allocation and when requested, clear the
complete transitioned range after cc_make_shared() succeeds.
Return the page and transitioned size so free_cc_shared_pages() can
restore the complete range to private state before freeing it. If
private state cannot be established, retain the allocation instead of
returning a possibly shared page to the buddy allocator.
Also provide the shared-granule geometry and byte-oriented transition
helpers used by the allocator and by callers managing their own backing
memory.
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
include/linux/cc_shared.h | 39 +++++++
mm/Makefile | 1 +
mm/cc_shared.c | 232 ++++++++++++++++++++++++++++++++++++++
3 files changed, 272 insertions(+)
create mode 100644 include/linux/cc_shared.h
create mode 100644 mm/cc_shared.c
diff --git a/include/linux/cc_shared.h b/include/linux/cc_shared.h
new file mode 100644
index 000000000000..5f8db7c468c5
--- /dev/null
+++ b/include/linux/cc_shared.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_CC_SHARED_H
+#define _LINUX_CC_SHARED_H
+
+#include <linux/gfp_types.h>
+#include <linux/types.h>
+
+struct page;
+
+struct cc_shared_pages {
+ struct page *page;
+ size_t shared_size;
+};
+
+struct cc_shared_layout {
+ size_t requested_size;
+ size_t shared_size;
+ size_t alignment;
+};
+
+/*
+ * Architectures may override this to return the granule used for transitions
+ * between private and shared memory. The value must be a power of two and no
+ * smaller than PAGE_SIZE.
+ */
+size_t arch_cc_shared_granule_size(void);
+
+size_t cc_shared_granule_size(void);
+int cc_shared_calc_layout(size_t requested, struct cc_shared_layout *layout);
+bool cc_shared_range_valid(phys_addr_t base, size_t size);
+int cc_make_shared(void *addr, size_t size);
+int cc_make_private(void *addr, size_t size);
+int alloc_cc_shared_pages_node(int nid, gfp_t gfp,
+ size_t requested, struct cc_shared_pages *mem);
+int alloc_cc_shared_pages(gfp_t gfp,
+ size_t requested, struct cc_shared_pages *mem);
+void free_cc_shared_pages(struct cc_shared_pages *mem);
+
+#endif /* _LINUX_CC_SHARED_H */
diff --git a/mm/Makefile b/mm/Makefile
index e7245cb88c66..6e6544428422 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -56,6 +56,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \
compaction.o show_mem.o \
interval_tree.o list_lru.o workingset.o \
debug.o gup.o mmap_lock.o vma_init.o $(mmu-y)
+obj-y += cc_shared.o
# Give 'page_alloc' its own module-parameter namespace
page-alloc-y := page_alloc.o
diff --git a/mm/cc_shared.c b/mm/cc_shared.c
new file mode 100644
index 000000000000..85e16f4504b8
--- /dev/null
+++ b/mm/cc_shared.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ */
+#include <linux/align.h>
+#include <linux/cc_platform.h>
+#include <linux/cc_shared.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+#include <linux/log2.h>
+#include <linux/mm.h>
+#include <linux/mem_encrypt.h>
+#include <linux/numa.h>
+#include <linux/overflow.h>
+#include <linux/set_memory.h>
+
+size_t __weak arch_cc_shared_granule_size(void)
+{
+ return PAGE_SIZE;
+}
+
+size_t cc_shared_granule_size(void)
+{
+ size_t granule = arch_cc_shared_granule_size();
+
+ if (WARN_ON_ONCE(granule < PAGE_SIZE || !is_power_of_2(granule)))
+ return PAGE_SIZE;
+
+ return granule;
+}
+EXPORT_SYMBOL_GPL(cc_shared_granule_size);
+
+int cc_shared_calc_layout(size_t requested, struct cc_shared_layout *layout)
+{
+ size_t granule, rounded;
+
+ if (!requested || !layout)
+ return -EINVAL;
+
+ granule = cc_shared_granule_size();
+ if (check_add_overflow(requested, granule - 1, &rounded))
+ return -EOVERFLOW;
+
+ rounded = ALIGN_DOWN(rounded, granule);
+ layout->requested_size = requested;
+ layout->shared_size = rounded;
+ layout->alignment = granule;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cc_shared_calc_layout);
+
+bool cc_shared_range_valid(phys_addr_t base, size_t size)
+{
+ size_t granule = cc_shared_granule_size();
+
+ if (!size)
+ return false;
+
+ return IS_ALIGNED(base, granule) && IS_ALIGNED(size, granule);
+}
+EXPORT_SYMBOL_GPL(cc_shared_range_valid);
+
+static int cc_validate_transition(void *addr, size_t size)
+{
+ phys_addr_t phys;
+
+ if (!addr || !size || !PAGE_ALIGNED(addr) ||
+ !virt_addr_valid(addr))
+ return -EINVAL;
+
+ phys = page_to_phys(virt_to_page(addr));
+ if (!cc_shared_range_valid(phys, size))
+ return -EINVAL;
+
+ return 0;
+}
+
+int cc_make_shared(void *addr, size_t size)
+{
+ int ret = cc_validate_transition(addr, size);
+
+ if (ret)
+ return ret;
+
+ return set_memory_decrypted((unsigned long)addr, size >> PAGE_SHIFT);
+}
+
+int cc_make_private(void *addr, size_t size)
+{
+ int ret = cc_validate_transition(addr, size);
+
+ if (ret)
+ return ret;
+
+ return set_memory_encrypted((unsigned long)addr, size >> PAGE_SHIFT);
+}
+
+static int __alloc_cc_shared_pages_node(int nid, gfp_t gfp,
+ size_t requested,
+ struct cc_shared_pages *mem)
+{
+ struct cc_shared_layout layout;
+ struct page *page;
+ unsigned int order;
+ bool zero = gfp & __GFP_ZERO;
+ int ret;
+
+ ret = cc_shared_calc_layout(requested, &layout);
+ if (ret)
+ return ret;
+
+ order = get_order(layout.shared_size);
+ if (order > MAX_PAGE_ORDER)
+ return -EINVAL;
+
+ /*
+ * State transitions require a linear-map address and may modify memory.
+ * Allocate from low memory and defer requested zeroing until afterwards.
+ */
+ gfp &= ~(__GFP_HIGHMEM | __GFP_ZERO);
+ if (nid == NUMA_NO_NODE)
+ page = alloc_pages(gfp, order);
+ else
+ page = alloc_pages_node(nid, gfp, order);
+ if (!page)
+ return -ENOMEM;
+
+ ret = cc_make_shared(page_address(page), layout.shared_size);
+ if (ret) {
+ if (!cc_make_private(page_address(page), layout.shared_size))
+ __free_pages(page, order);
+ else
+ pr_warn_ratelimited("leaking %zu bytes with uncertain shared state\n",
+ layout.shared_size);
+ return ret;
+ }
+
+ if (zero)
+ memset(page_address(page), 0, layout.shared_size);
+
+ mem->page = page;
+ mem->shared_size = layout.shared_size;
+ return 0;
+}
+
+/**
+ * alloc_cc_shared_pages_node - allocate memory that can be shared
+ * @nid: NUMA node from which to allocate, or %NUMA_NO_NODE
+ * @gfp: allocation flags
+ * @requested: number of bytes requested; must be nonzero
+ * @mem: storage for the allocated page and the size of the shared range
+ *
+ * Allocate at least @requested bytes and make the allocation shared when
+ * memory encryption is active. A memory-state transition requires a valid
+ * linear-map address, so such allocations never come from high memory
+ *
+ * The shared range may be rounded up to the architecture's transition
+ * granule. On success, @mem->shared_size records the actual size that was
+ * made shared and must be retained unchanged for free_cc_shared_pages().
+ * @mem is not modified on failure.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int alloc_cc_shared_pages_node(int nid, gfp_t gfp,
+ size_t requested,
+ struct cc_shared_pages *mem)
+{
+ struct page *page;
+ unsigned int order;
+
+ if (!mem || !requested)
+ return -EINVAL;
+
+ if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
+ return __alloc_cc_shared_pages_node(nid, gfp, requested, mem);
+
+ order = get_order(requested);
+ if (order > MAX_PAGE_ORDER)
+ return -EINVAL;
+
+ if (nid == NUMA_NO_NODE)
+ page = alloc_pages(gfp, order);
+ else
+ page = alloc_pages_node(nid, gfp, order);
+ if (!page)
+ return -ENOMEM;
+
+ mem->page = page;
+ mem->shared_size = requested;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(alloc_cc_shared_pages_node);
+
+/**
+ * alloc_cc_shared_pages - allocate memory that can be shared
+ * @gfp: allocation flags
+ * @requested: number of bytes requested; must be nonzero
+ * @mem: storage for the allocated page and the size of the shared range
+ *
+ * Equivalent to alloc_cc_shared_pages_node() with %NUMA_NO_NODE.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int alloc_cc_shared_pages(gfp_t gfp,
+ size_t requested, struct cc_shared_pages *mem)
+{
+ return alloc_cc_shared_pages_node(NUMA_NO_NODE, gfp, requested, mem);
+}
+EXPORT_SYMBOL_GPL(alloc_cc_shared_pages);
+
+void free_cc_shared_pages(struct cc_shared_pages *mem)
+{
+ if (!mem || !mem->page)
+ return;
+
+ if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT))
+ goto free_pages;
+
+ if (cc_make_private(page_address(mem->page), mem->shared_size)) {
+ pr_warn_ratelimited("leaking %zu bytes that cannot be made private\n",
+ mem->shared_size);
+ return;
+ }
+
+free_pages:
+ __free_pages(mem->page, get_order(mem->shared_size));
+ mem->page = NULL;
+ mem->shared_size = 0;
+}
+EXPORT_SYMBOL_GPL(free_cc_shared_pages);
--
2.43.0
next prev parent reply other threads:[~2026-09-24 10:06 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 10:05 [RFC PATCH v8 00/14] coco: guest: Add a shared-granule allocator for host-shared memory Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` Aneesh Kumar K.V (Arm) [this message]
2026-09-24 10:05 ` [RFC PATCH v8 02/14] mm: Zero memory during shared memory transitions Aneesh Kumar K.V (Arm)
2026-09-25 12:08 ` Kiryl Shutsemau
2026-09-24 10:05 ` [RFC PATCH v8 03/14] irqchip/gic-v3-its: Resolve the default NUMA node explicitly Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 04/14] irqchip/gic-v3-its: Allocate shared tables using CoCo shared memory allocator Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 05/14] dma-contiguous: Derive shared alignment from DMA attributes Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 06/14] dma-pool: Allocate CoCo atomic pools using CoCo shared memory allocator Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 07/14] dma-direct: Align CoCo shared DMA allocations to the shared granule size Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 08/14] swiotlb: Align shared IO TLB pools " Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 09/14] swiotlb: Reject misaligned restricted DMA pools for CoCo guests Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 10/14] dma-buf: system_heap: Limit scatterlist entries to the buffer size Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 11/14] dma-buf: system_heap: Allocate shared buffers using CoCo shared memory allocator Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 12/14] swiotlb: Make rounded shared pool capacity allocatable Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 13/14] mm: Assert CoCo shared allocations may sleep Aneesh Kumar K.V (Arm)
2026-09-24 10:05 ` [RFC PATCH v8 14/14] irqchip/gic-v3-its: Preallocate VPE L1 tables Aneesh Kumar K.V (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260924100529.1398790-2-aneesh.kumar@kernel.org \
--to=aneesh.kumar@kernel.org \
--cc=Brian.Starkey@arm.com \
--cc=agordeev@linux.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=baoquan.he@linux.dev \
--cc=benjamin.gaignard@collabora.com \
--cc=borntraeger@linux.ibm.com \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=chleroy@kernel.org \
--cc=christian.koenig@amd.com \
--cc=dave.hansen@linux.intel.com \
--cc=decui@microsoft.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gerald.schaefer@linux.ibm.com \
--cc=gor@linux.ibm.com \
--cc=haiyangz@microsoft.com \
--cc=hca@linux.ibm.com \
--cc=hpa@zytor.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=jstultz@google.com \
--cc=kas@kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=kys@microsoft.com \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux@armlinux.org.uk \
--cc=longli@microsoft.com \
--cc=luto@kernel.org \
--cc=m.szyprowski@samsung.com \
--cc=maddy@linux.ibm.com \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=mingo@redhat.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=pasha.tatashin@soleen.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=pratyush@kernel.org \
--cc=radu@rendec.net \
--cc=rick.p.edgecombe@intel.com \
--cc=ritesh.list@gmail.com \
--cc=robin.murphy@arm.com \
--cc=rppt@kernel.org \
--cc=sshegde@linux.ibm.com \
--cc=steven.price@arm.com \
--cc=sumit.semwal@linaro.org \
--cc=suzuki.poulose@arm.com \
--cc=svens@linux.ibm.com \
--cc=tglx@kernel.org \
--cc=tjmercier@google.com \
--cc=vkuznets@redhat.com \
--cc=wei.liu@kernel.org \
--cc=will@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®