x86/ioremap, resource: Introduce IORES_DESC_ENCRYPTED for encrypted PCI MMIO
PCIe Trusted Execution Environment Device Interface Security Protocol
(TDISP) arranges for a PCI device to support encrypted MMIO. In support of
that capability, ioremap() needs a mechanism to detect when a PCI device
has been dynamically transitioned into this secure state and enforce
encrypted MMIO mappings.
Teach ioremap() about a new IORES_DESC_ENCRYPTED type that supplements the
existing PCI Memory Space (MMIO) BAR resources. The proposal is that a
resource, "PCI MMIO Encrypted", with this description type is injected by
the PCI/TSM core for each PCI device BAR that is to be protected.
Unlike the existing encryption determination which is "implied with a
silent fallback to an unencrypted mapping", this indication is "explicit
with an expectation that the request fails instead of fallback".
IORES_MUST_ENCRYPT is added to manage this expectation.
Given that "PCI MMIO Encrypted" is an additional resource in the tree, the
IORESOURCE_BUSY flag will only be set on a descendant/child of that
resource. That means it cannot share the same walk as the check for "System
RAM". Add walk_iomem_res_desc() to check if any IORES_DESC_ENCRYPTED
intersects the ioremap() range and set IORES_MUST_ENCRYPT accordingly.
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 12c8180..ad9cf2c 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -93,18 +93,24 @@ static unsigned int __ioremap_check_ram(struct resource *res)
*/
static unsigned int __ioremap_check_encrypted(struct resource *res)
{
+ u32 flags = 0;
+
+ if (res->desc == IORES_DESC_ENCRYPTED)
+ flags |= IORES_MUST_ENCRYPT;
+
if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
- return 0;
+ return flags;
switch (res->desc) {
case IORES_DESC_NONE:
case IORES_DESC_RESERVED:
break;
+ case IORES_DESC_ENCRYPTED:
default:
- return IORES_MAP_ENCRYPTED;
+ flags |= IORES_MAP_ENCRYPTED;
}
- return 0;
+ return flags;
}
/*
@@ -133,15 +139,14 @@ static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *des
static int __ioremap_collect_map_flags(struct resource *res, void *arg)
{
struct ioremap_desc *desc = arg;
+ const unsigned long all_flags =
+ IORES_MAP_SYSTEM_RAM | IORES_MAP_ENCRYPTED | IORES_MUST_ENCRYPT;
- if (!(desc->flags & IORES_MAP_SYSTEM_RAM))
- desc->flags |= __ioremap_check_ram(res);
+ desc->flags |= __ioremap_check_ram(res);
+ desc->flags |= __ioremap_check_encrypted(res);
- if (!(desc->flags & IORES_MAP_ENCRYPTED))
- desc->flags |= __ioremap_check_encrypted(res);
-
- return ((desc->flags & (IORES_MAP_SYSTEM_RAM | IORES_MAP_ENCRYPTED)) ==
- (IORES_MAP_SYSTEM_RAM | IORES_MAP_ENCRYPTED));
+ /* continue until all possible mapping types saturated */
+ return (desc->flags & all_flags) == all_flags;
}
/*
@@ -162,6 +167,12 @@ static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
memset(desc, 0, sizeof(struct ioremap_desc));
walk_mem_res(start, end, desc, __ioremap_collect_map_flags);
+ /*
+ * Encrypted MMIO may parent a driver's requested region, so it needs a
+ * separate search
+ */
+ walk_iomem_res_desc(IORES_DESC_ENCRYPTED, IORESOURCE_MEM, start, end,
+ desc, __ioremap_collect_map_flags);
__ioremap_check_other(addr, desc);
}
@@ -209,6 +220,13 @@ __ioremap_caller(resource_size_t phys_addr, unsigned long size,
__ioremap_check_mem(phys_addr, size, &io_desc);
+ if ((io_desc.flags & IORES_MUST_ENCRYPT) &&
+ !(io_desc.flags & IORES_MAP_ENCRYPTED)) {
+ pr_err("ioremap: encrypted mapping unavailable for %pa - %pa\n",
+ &phys_addr, &last_addr);
+ return NULL;
+ }
+
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 9afa30f..3efd074 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -143,6 +143,7 @@ enum {
IORES_DESC_RESERVED = 7,
IORES_DESC_SOFT_RESERVED = 8,
IORES_DESC_CXL = 9,
+ IORES_DESC_ENCRYPTED = 10,
};
/*
@@ -151,6 +152,7 @@ enum {
enum {
IORES_MAP_SYSTEM_RAM = BIT(0),
IORES_MAP_ENCRYPTED = BIT(1),
+ IORES_MUST_ENCRYPT = BIT(2), /* disable transparent fallback */
};
/* helpers to define resources */