Message ID | 20240819131924.372366-3-steven.price@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64: Support for running as a guest in Arm CCA | expand |
On Mon, Aug 19, 2024 at 02:19:07PM +0100, Steven Price wrote: > From: Will Deacon <will@kernel.org> > > Confidential Computing environments such as pKVM and Arm's CCA > distinguish between shared (i.e. emulated) and private (i.e. assigned) > MMIO regions. > > Introduce a hook into our implementation of ioremap_prot() so that MMIO > regions can be shared if necessary. > > Signed-off-by: Will Deacon <will@kernel.org> > Signed-off-by: Steven Price <steven.price@arm.com> > --- > Patch 'borrowed' from Will's series for pKVM: > https://lore.kernel.org/r/20240730151113.1497-6-will%40kernel.org > --- > arch/arm64/include/asm/io.h | 4 ++++ > arch/arm64/mm/ioremap.c | 23 ++++++++++++++++++++++- > 2 files changed, 26 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h > index 41fd90895dfc..1ada23a6ec19 100644 > --- a/arch/arm64/include/asm/io.h > +++ b/arch/arm64/include/asm/io.h > @@ -271,6 +271,10 @@ __iowrite64_copy(void __iomem *to, const void *from, size_t count) > * I/O memory mapping functions. > */ > > +typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size, > + pgprot_t *prot); > +int arm64_ioremap_prot_hook_register(const ioremap_prot_hook_t hook); > + > #define ioremap_prot ioremap_prot > > #define _PAGE_IOREMAP PROT_DEVICE_nGnRE > diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c > index 269f2f63ab7d..6cc0b7e7eb03 100644 > --- a/arch/arm64/mm/ioremap.c > +++ b/arch/arm64/mm/ioremap.c > @@ -3,10 +3,22 @@ > #include <linux/mm.h> > #include <linux/io.h> > > +static ioremap_prot_hook_t ioremap_prot_hook; > + > +int arm64_ioremap_prot_hook_register(ioremap_prot_hook_t hook) > +{ > + if (WARN_ON(ioremap_prot_hook)) > + return -EBUSY; > + > + ioremap_prot_hook = hook; > + return 0; > +} > + > void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, > unsigned long prot) > { > unsigned long last_addr = phys_addr + size - 1; > + pgprot_t pgprot = __pgprot(prot); > > /* Don't allow outside PHYS_MASK */ > if (last_addr & ~PHYS_MASK) > @@ -16,7 +28,16 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, > if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr)))) > return NULL; > > - return generic_ioremap_prot(phys_addr, size, __pgprot(prot)); > + /* > + * If a hook is registered (e.g. for confidential computing > + * purposes), call that now and barf if it fails. > + */ > + if (unlikely(ioremap_prot_hook) && > + WARN_ON(ioremap_prot_hook(phys_addr, size, &pgprot))) { > + return NULL; > + } > + > + return generic_ioremap_prot(phys_addr, size, pgprot); > } > EXPORT_SYMBOL(ioremap_prot); I should have commented on Will's original series since it's more likely to affect pKVM than CCA. Anyway, this is all good with the hook, especially if the guest needs to do some paravirtual call. However, we have other instances of mapping I/O memory without going through ioremap() - io_remap_pfn_range() which uses pgprot_decrypted(). We'll need some hooks there as well. And I think there are a few other cases of pgprot_decrypted() but we can fix them on a case by case bases (e.g. routing them through io_remap_pfn_range()). For this patch: Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 41fd90895dfc..1ada23a6ec19 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -271,6 +271,10 @@ __iowrite64_copy(void __iomem *to, const void *from, size_t count) * I/O memory mapping functions. */ +typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size, + pgprot_t *prot); +int arm64_ioremap_prot_hook_register(const ioremap_prot_hook_t hook); + #define ioremap_prot ioremap_prot #define _PAGE_IOREMAP PROT_DEVICE_nGnRE diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index 269f2f63ab7d..6cc0b7e7eb03 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -3,10 +3,22 @@ #include <linux/mm.h> #include <linux/io.h> +static ioremap_prot_hook_t ioremap_prot_hook; + +int arm64_ioremap_prot_hook_register(ioremap_prot_hook_t hook) +{ + if (WARN_ON(ioremap_prot_hook)) + return -EBUSY; + + ioremap_prot_hook = hook; + return 0; +} + void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, unsigned long prot) { unsigned long last_addr = phys_addr + size - 1; + pgprot_t pgprot = __pgprot(prot); /* Don't allow outside PHYS_MASK */ if (last_addr & ~PHYS_MASK) @@ -16,7 +28,16 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr)))) return NULL; - return generic_ioremap_prot(phys_addr, size, __pgprot(prot)); + /* + * If a hook is registered (e.g. for confidential computing + * purposes), call that now and barf if it fails. + */ + if (unlikely(ioremap_prot_hook) && + WARN_ON(ioremap_prot_hook(phys_addr, size, &pgprot))) { + return NULL; + } + + return generic_ioremap_prot(phys_addr, size, pgprot); } EXPORT_SYMBOL(ioremap_prot);