From: Bradley Morgan <brads@mainlining.org>
To: ankita@nvidia.com
Cc: Smita.KoralahalliChannabasappa@amd.com, aik@amd.com,
alison.schofield@intel.com, andriy.shevchenko@linux.intel.com,
aneesh.kumar@kernel.org, bhelgaas@google.com,
dave.jiang@intel.com, dave@stgolabs.net, icheng@nvidia.com,
ilpo.jarvinen@linux.intel.com, iweiny@kernel.org, jgg@nvidia.com,
jic23@kernel.org, linux-coco@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org, ming.li@zohomail.com,
smadhavan@nvidia.com, vishal.l.verma@intel.com,
yilun.xu@linux.intel.com
Subject: Re: [RFC PATCH 1/4] PCI/TSM: Create MMIO descriptors via TDISP Report
Date: Mon, 05 Oct 2026 12:17:49 +0100 [thread overview]
Message-ID: <317D506F-8079-4776-8EBC-2BA1A7535BC9@mainlining.org> (raw)
In-Reply-To: <20261005070252.84810-2-ankita@nvidia.com>
On 5 October 2026 08:02:49 BST, Ankit Agrawal <ankita@nvidia.com> wrote:
>After pci_tsm_bind() and pci_tsm_lock() the low level TSM driver is
>expected to populate the TDISP GET_DEVICE_INTERFACE_REPORT response
>payload for the device.
>
>Add pci_tsm_mmio_alloc()/pci_tsm_mmio_free() to parse that report into
>a set of encrypted MMIO ranges, and pci_tsm_mmio_setup()/
>pci_tsm_mmio_teardown() to mark those ranges as encrypted in iomem via
>a new encrypted_iomem_resource tree (IORES_DESC_ENCRYPTED). With those
>descriptors the TSM driver can use pci_tsm_mmio_setup() to inform
>ioremap() how to map the device per the device expectations. The VM
>is expected to validate the interface with the relying party before
>accepting the device for operation.
>
>pci_tsm_mmio_alloc() also recovers the obfuscated starting address for
>each encrypted MMIO range, since the VM is never disclosed the HPA
>that correlates to the GPA of the device's MMIO. The obfuscated
>address is BAR aligned.
>
>Based on an original patch by Aneesh Kumar K.V [1], and cherry-picked
>from Dan Williams' upstream commit [2]. Major functional differences
>from Dan's posting is due to the lack of evidence-store infrastructure
>yet (device_evidence / DEVICE_EVIDENCE_TYPE_REPORT). The
>pci_tsm_mmio_alloc() takes the raw report bytes directly from the caller
>instead of pulling them from a device evidence store.
>
>Link: https://lore.kernel.org/linux-coco/20251117140007.122062-8-aneesh.kumar@kernel.org/ [1]
>Link: https://lore.kernel.org/all/20260705220819.2472765-15-djbw@kernel.org/ [2]
LGTM from a kernel/resource.c standpoint:
Reviewed-by: Bradley Morgan <brads@mainlining.org> # kernel/
>
>Signed-off-by: Ankit Agrawal <ankita@nvidia.com>
>Assisted-by: Claude:sonnet-5
>---
> drivers/pci/tsm.c | 236 ++++++++++++++++++++++++++++++++++++++++
> include/linux/ioport.h | 2 +
> include/linux/pci-tsm.h | 33 ++++++
> kernel/resource.c | 8 ++
> 4 files changed, 279 insertions(+)
>
>diff --git a/drivers/pci/tsm.c b/drivers/pci/tsm.c
>index 5fdcd7f2e820..c8cfe89b6224 100644
>--- a/drivers/pci/tsm.c
>+++ b/drivers/pci/tsm.c
>@@ -9,11 +9,16 @@
> #define dev_fmt(fmt) "PCI/TSM: " fmt
>
> #include <linux/bitfield.h>
>+#include <linux/overflow.h>
> #include <linux/pci.h>
> #include <linux/pci-doe.h>
> #include <linux/pci-tsm.h>
>+#include <linux/range.h>
>+#include <linux/sizes.h>
>+#include <linux/slab.h>
> #include <linux/sysfs.h>
> #include <linux/tsm.h>
>+#include <linux/unaligned.h>
> #include <linux/xarray.h>
> #include "pci.h"
>
>@@ -898,3 +903,234 @@ int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req,
> resp, resp_sz);
> }
> EXPORT_SYMBOL_GPL(pci_tsm_doe_transfer);
>+
>+static void mmio_teardown(struct pci_tsm_mmio *mmio, int nr)
>+{
>+ while (nr--) {
>+ struct resource *res = pci_tsm_mmio_resource(mmio, nr);
>+
>+ /*
>+ * Entries past the point where pci_tsm_mmio_setup() stopped
>+ * (or that were never run through setup() at all, e.g. a
>+ * caller that only wants the resolved range from
>+ * pci_tsm_mmio_alloc()) were never insert_resource()'d, so
>+ * res->parent is NULL. remove_resource() dereferences
>+ * res->parent unconditionally.
>+ */
>+ if (res->parent)
>+ remove_resource(res);
>+ }
>+}
>+
>+/**
>+ * pci_tsm_mmio_setup() - mark device MMIO as encrypted in iomem
>+ * @pdev: device owner of MMIO resources
>+ * @mmio: container of an array of resources to mark encrypted
>+ */
>+int pci_tsm_mmio_setup(struct pci_dev *pdev, struct pci_tsm_mmio *mmio)
>+{
>+ int i;
>+
>+ device_lock_assert(&pdev->dev);
>+ if (pdev->dev.driver)
>+ return -EBUSY;
>+
>+ for (i = 0; i < mmio->nr; i++) {
>+ struct resource *res = pci_tsm_mmio_resource(mmio, i);
>+ int j;
>+
>+ if (resource_size(res) == 0 || !(res->flags & IORESOURCE_MEM))
>+ break;
>+
>+ /* Only require the caller to set the range, init remainder */
>+ *res = DEFINE_RES_NAMED_DESC(res->start, resource_size(res),
>+ pci_name(pdev), IORESOURCE_MEM,
>+ IORES_DESC_ENCRYPTED);
>+
>+ for (j = 0; j < PCI_NUM_RESOURCES; j++)
>+ if (resource_contains(pci_resource_n(pdev, j), res))
>+ break;
>+
>+ /* Request is outside of device MMIO */
>+ if (j >= PCI_NUM_RESOURCES)
>+ break;
>+
>+ if (insert_resource(&encrypted_iomem_resource, res) != 0)
>+ break;
>+ }
>+
>+ if (i >= mmio->nr)
>+ return 0;
>+
>+ mmio_teardown(mmio, i);
>+
>+ return -EINVAL;
>+}
>+EXPORT_SYMBOL_GPL(pci_tsm_mmio_setup);
>+
>+void pci_tsm_mmio_teardown(struct pci_tsm_mmio *mmio)
>+{
>+ mmio_teardown(mmio, mmio->nr);
>+}
>+EXPORT_SYMBOL_GPL(pci_tsm_mmio_teardown);
>+
>+/*
>+ * PCIe ECN TEE Device Interface Security Protocol (TDISP)
>+ *
>+ * Device Interface Report data object layout as defined by PCIe r7.0 section
>+ * 11.3.11
>+ */
>+#define PCI_TSM_DEVIF_REPORT_MMIO_ATTR_MSIX_TABLE BIT(0)
>+#define PCI_TSM_DEVIF_REPORT_MMIO_ATTR_MSIX_PBA BIT(1)
>+#define PCI_TSM_DEVIF_REPORT_MMIO_ATTR_IS_NON_TEE BIT(2)
>+#define PCI_TSM_DEVIF_REPORT_MMIO_ATTR_IS_UPDATABLE BIT(3)
>+#define PCI_TSM_DEVIF_REPORT_MMIO_ATTR_RANGE_ID GENMASK(31, 16)
>+
>+/* An interface report 'pfn' is 4K in size */
>+struct pci_tsm_devif_mmio {
>+ __le64 phys;
>+ __le32 nr_pfns;
>+ __le32 attributes;
>+};
>+
>+struct pci_tsm_devif_report {
>+ __le16 interface_info;
>+ __le16 reserved;
>+ __le16 msi_x_message_control;
>+ __le16 lnr_control;
>+ __le32 tph_control;
>+ __le32 mmio_range_count;
>+ struct pci_tsm_devif_mmio mmio[];
>+};
>+
>+/**
>+ * pci_tsm_mmio_alloc() - allocate encrypted MMIO range descriptor
>+ * @pdev: device owner of MMIO ranges
>+ * @report: raw TDISP Device Interface Report bytes (PCIe r7.0 section
>+ * 11.3.11), e.g. as returned by GET_DEVICE_INTERFACE_REPORT
>+ * @report_len: length of @report in bytes
>+ *
>+ * Return: the encrypted MMIO range descriptor on success, NULL on failure
>+ *
>+ * Unlike upstream, @report is supplied directly by the caller rather than
>+ * pulled from a device evidence store, which this tree does not yet have.
>+ */
>+struct pci_tsm_mmio *pci_tsm_mmio_alloc(struct pci_dev *pdev,
>+ const void *report, size_t report_len)
>+{
>+ const struct pci_tsm_devif_report *devif_report = report;
>+ u64 reporting_bar_base, last_reporting_end;
>+ u32 mmio_range_count;
>+ int last_bar = -1;
>+ int i;
>+
>+ if (report_len < sizeof(*devif_report))
>+ return NULL;
>+
>+ mmio_range_count = __le32_to_cpu(devif_report->mmio_range_count);
>+
>+ /* check that the report is self-consistent on mmio entries */
>+ if (report_len < struct_size(devif_report, mmio, mmio_range_count))
>+ return NULL;
>+
>+ /* create pci_tsm_mmio descriptors from the report data */
>+ struct pci_tsm_mmio *mmio __free(kfree) =
>+ kzalloc_flex(*mmio, mmio, mmio_range_count);
>+ if (!mmio)
>+ return NULL;
>+
>+ for (i = 0; i < mmio_range_count; i++) {
>+ u64 range_off;
>+ struct range range;
>+ const struct pci_tsm_devif_mmio *mmio_data = &devif_report->mmio[i];
>+ struct pci_tsm_mmio_entry *entry =
>+ pci_tsm_mmio_entry(mmio, mmio->nr);
>+ u64 tsm_offset = __le64_to_cpu(mmio_data->phys);
>+ u64 size = (u64)__le32_to_cpu(mmio_data->nr_pfns) * SZ_4K;
>+ u32 attr = __le32_to_cpu(mmio_data->attributes);
>+ int bar = FIELD_GET(PCI_TSM_DEVIF_REPORT_MMIO_ATTR_RANGE_ID,
>+ attr);
>+
>+ if (bar >= PCI_STD_NUM_BARS ||
>+ !(pci_resource_flags(pdev, bar) & IORESOURCE_MEM) ||
>+ (pci_resource_flags(pdev, bar) & IORESOURCE_UNSET)) {
>+ pci_dbg(pdev, "Invalid reporting bar ID %d\n", bar);
>+ return NULL;
>+ }
>+
>+ if (last_bar > bar) {
>+ pci_dbg(pdev, "Reporting bar ID not in ascending order\n");
>+ return NULL;
>+ }
>+
>+ if (last_bar < bar) {
>+ resource_size_t mask = pci_resource_len(pdev, bar) - 1;
>+
>+ /* Transition to a new bar */
>+ last_bar = bar;
>+
>+ /*
>+ * Determine the obfuscated base of the BAR. BAR
>+ * offsets are never obfuscated.
>+ */
>+ reporting_bar_base = tsm_offset & ~mask;
>+ } else if (tsm_offset < last_reporting_end) {
>+ pci_dbg(pdev, "Reporting ranges within BAR not in ascending order\n");
>+ return NULL;
>+ }
>+
>+ /* Per spec the tsm_offset never results in overflow / underflow */
>+ last_reporting_end = tsm_offset + size;
>+ if (last_reporting_end < tsm_offset) {
>+ pci_dbg(pdev, "Reporting range overflow\n");
>+ return NULL;
>+ }
>+
>+ range_off = tsm_offset - reporting_bar_base;
>+ if (pci_resource_len(pdev, bar) < range_off + size) {
>+ pci_dbg(pdev, "Reporting range larger than BAR size\n");
>+ return NULL;
>+ }
>+
>+ range.start = pci_resource_start(pdev, bar) + range_off;
>+ range.end = range.start + size - 1;
>+
>+ /* Only record the TEE ranges for later consideration by ioremap() */
>+ if (FIELD_GET(PCI_TSM_DEVIF_REPORT_MMIO_ATTR_IS_NON_TEE,
>+ attr)) {
>+ pci_dbg(pdev, "Skipping non-TEE range, BAR%d %pra\n",
>+ bar, &range);
>+ continue;
>+ }
>+
>+ entry->res.start = range.start;
>+ entry->res.end = range.end;
>+ entry->res.flags = IORESOURCE_MEM;
>+ entry->tsm_offset = tsm_offset;
>+ mmio->nr++;
>+ }
>+
>+ return_ptr(mmio);
>+}
>+EXPORT_SYMBOL_GPL(pci_tsm_mmio_alloc);
>+
>+/**
>+ * pci_tsm_mmio_free() - free a pci_tsm_mmio instance
>+ * @pdev: device owner of MMIO ranges
>+ * @mmio: instance to free
>+ *
>+ * Returns 0 if @mmio was idle on entry, -EBUSY otherwise
>+ */
>+int pci_tsm_mmio_free(struct pci_dev *pdev, struct pci_tsm_mmio *mmio)
>+{
>+ for (int i = 0; i < mmio->nr; i++) {
>+ struct resource *res = pci_tsm_mmio_resource(mmio, i);
>+
>+ if (dev_WARN_ONCE(&pdev->dev, resource_assigned(res),
>+ "MMIO resource still assigned %pr\n", res))
>+ return -EBUSY;
>+ }
>+ kfree(mmio);
>+ return 0;
>+}
>+EXPORT_SYMBOL_GPL(pci_tsm_mmio_free);
>diff --git a/include/linux/ioport.h b/include/linux/ioport.h
>index f7930b3dfd0a..122f1eefb4b9 100644
>--- a/include/linux/ioport.h
>+++ b/include/linux/ioport.h
>@@ -144,6 +144,7 @@ enum {
> IORES_DESC_RESERVED = 7,
> IORES_DESC_SOFT_RESERVED = 8,
> IORES_DESC_CXL = 9,
>+ IORES_DESC_ENCRYPTED = 10,
> };
>
> /*
>@@ -240,6 +241,7 @@ struct resource_constraint {
> extern struct resource ioport_resource;
> extern struct resource iomem_resource;
> extern struct resource soft_reserve_resource;
>+extern struct resource encrypted_iomem_resource;
>
> extern struct resource *request_resource_conflict(struct resource *root,
> struct resource *new);
> extern int request_resource(struct resource *root, struct resource *new);
>diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
>index a6435aba03f9..e54ad057fa8e 100644
>--- a/include/linux/pci-tsm.h
>+++ b/include/linux/pci-tsm.h
>@@ -199,6 +199,34 @@ enum pci_tsm_req_scope {
> PCI_TSM_REQ_DEBUG_WRITE = 3,
> };
>
>+/**
>+ * struct pci_tsm_mmio_entry - an encrypted MMIO range
>+ * @res: MMIO address range (typically Guest Physical Address, GPA)
>+ * @tsm_offset: Host Physical Address, HPA obfuscation offset added by the TSM.
>+ * Translates report addresses to GPA.
>+ */
>+struct pci_tsm_mmio_entry {
>+ struct resource res;
>+ u64 tsm_offset;
>+};
>+
>+struct pci_tsm_mmio {
>+ int nr;
>+ struct pci_tsm_mmio_entry mmio[];
>+};
>+
>+static inline struct pci_tsm_mmio_entry *
>+pci_tsm_mmio_entry(struct pci_tsm_mmio *mmio, int idx)
>+{
>+ return &mmio->mmio[idx];
>+}
>+
>+static inline struct resource *pci_tsm_mmio_resource(struct pci_tsm_mmio *mmio,
>+ int idx)
>+{
>+ return &mmio->mmio[idx].res;
>+}
>+
> #ifdef CONFIG_PCI_TSM
> int pci_tsm_register(struct tsm_dev *tsm_dev);
> void pci_tsm_unregister(struct tsm_dev *tsm_dev);
>@@ -216,6 +244,11 @@ void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
> ssize_t pci_tsm_guest_req(struct pci_dev *pdev, enum pci_tsm_req_scope
> scope,
> sockptr_t req_in, size_t in_len, sockptr_t req_out,
> size_t out_len, u64 *tsm_code);
>+int pci_tsm_mmio_setup(struct pci_dev *pdev, struct pci_tsm_mmio *mmio);
>+void pci_tsm_mmio_teardown(struct pci_tsm_mmio *mmio);
>+struct pci_tsm_mmio *pci_tsm_mmio_alloc(struct pci_dev *pdev,
>+ const void *report, size_t report_len);
>+int pci_tsm_mmio_free(struct pci_dev *pdev, struct pci_tsm_mmio *mmio);
> #else
> static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
> {
>diff --git a/kernel/resource.c b/kernel/resource.c
>index cfc1a00e86aa..5500f7828b2d 100644
>--- a/kernel/resource.c
>+++ b/kernel/resource.c
>@@ -56,6 +56,14 @@ struct resource soft_reserve_resource = {
> .flags = IORESOURCE_MEM,
> };
>
>+struct resource encrypted_iomem_resource = {
>+ .name = "Encrypted MMIO",
>+ .start = 0,
>+ .end = -1,
>+ .desc = IORES_DESC_ENCRYPTED,
>+ .flags = IORESOURCE_MEM,
>+};
>+
> static DEFINE_RWLOCK(resource_lock);
>
> /*
>
--- Thanks!
"I'm not a very positive person" - Linus torvalds
next prev parent reply other threads:[~2026-10-05 11:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-05 7:02 [RFC PATCH 0/4] PCI/TSM: Resolve TDISP coherent (CXL) ranges from precommitted HDM decoders Ankit Agrawal
2026-10-05 7:02 ` [RFC PATCH 1/4] PCI/TSM: Create MMIO descriptors via TDISP Report Ankit Agrawal
2026-10-05 11:17 ` Bradley Morgan [this message]
2026-10-05 7:02 ` [RFC PATCH 2/4] PCI/CXL: Populate and insert/remove pdev->coh_resource[] Ankit Agrawal
2026-10-05 7:02 ` [RFC PATCH 3/4] PCI/TSM: Derive the coherent-range IPA from CXL Ankit Agrawal
2026-10-05 7:02 ` [RFC PATCH 4/4] PCI/TSM: Support multiple coherent ranges via coh_idx Ankit Agrawal
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=317D506F-8079-4776-8EBC-2BA1A7535BC9@mainlining.org \
--to=brads@mainlining.org \
--cc=Smita.KoralahalliChannabasappa@amd.com \
--cc=aik@amd.com \
--cc=alison.schofield@intel.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=aneesh.kumar@kernel.org \
--cc=ankita@nvidia.com \
--cc=bhelgaas@google.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=icheng@nvidia.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=iweiny@kernel.org \
--cc=jgg@nvidia.com \
--cc=jic23@kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=ming.li@zohomail.com \
--cc=smadhavan@nvidia.com \
--cc=vishal.l.verma@intel.com \
--cc=yilun.xu@linux.intel.com \
/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®