diff mbox series

[v5,02/19] arm64: mm: Add confidential computing hook to ioremap_prot()

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

Commit Message

Steven Price Aug. 19, 2024, 1:19 p.m. UTC
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(-)

Comments

Catalin Marinas Aug. 26, 2024, 10:01 a.m. UTC | #1
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 mbox series

Patch

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);