[PATCH v3 2/3] arm/mpu: Introduce `v8r_el1_msa` device tree property for domains

Luca Fancellu posted 3 patches 4 days, 8 hours ago
[PATCH v3 2/3] arm/mpu: Introduce `v8r_el1_msa` device tree property for domains
Posted by Luca Fancellu 4 days, 8 hours ago
From: Harry Ramsey <harry.ramsey@arm.com>

Add a new device tree property `v8r_el1_msa` to select the MSA (memory
system architecture) at EL1 i.e. MPU(default) or MMU.

Signed-off-by: Harry Ramsey <harry.ramsey@arm.com>
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
---
v3:
- Improve commit message and device tree property description
- Remove macro protection
- Remove unused function is_mpu_domain
- Code formatting
---
 docs/misc/arm/device-tree/booting.txt | 12 ++++++++++++
 xen/arch/arm/dom0less-build.c         | 24 ++++++++++++++++++++++++
 xen/arch/arm/domain.c                 |  4 ++++
 xen/arch/arm/include/asm/domain.h     |  7 +++++++
 xen/arch/arm/include/asm/mpu.h        |  5 +++++
 xen/arch/arm/mpu/arm32/mm.c           |  5 +++++
 xen/arch/arm/mpu/arm64/mm.c           |  5 +++++
 xen/include/public/arch-arm.h         |  2 ++
 8 files changed, 64 insertions(+)

diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt
index 977b4286082f..b1a329c0e8d9 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -322,6 +322,18 @@ with the following properties:
     Should be used together with scmi-smc-passthrough Xen command line
     option.
 
+- v8r_el1_msa
+
+    A string property specifying whether, on Armv8-R systems, a domain
+    should use PMSAv8 (MPU) at EL1 or VMSAv8 (MMU) at EL1.
+
+    - "mmu"
+    Enables VMSAv8 at EL1. This requires hardware support and is only
+    optionally available on AArch64.
+
+    - "mpu"
+    Enables PMSAv8 at EL1. (Default)
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index 4181c105389a..456dc553bb23 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -24,6 +24,7 @@
 #include <asm/domain_build.h>
 #include <asm/firmware/sci.h>
 #include <asm/grant_table.h>
+#include <asm/mpu.h>
 #include <asm/setup.h>
 
 #ifdef CONFIG_VGICV2
@@ -315,6 +316,7 @@ int __init arch_parse_dom0less_node(struct dt_device_node *node,
     struct xen_domctl_createdomain *d_cfg = &bd->create_cfg;
     unsigned int flags = bd->create_flags;
     uint32_t val;
+    const char *v8r_el1_msa;
 
     d_cfg->arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE;
     d_cfg->flags |= XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap;
@@ -322,6 +324,28 @@ int __init arch_parse_dom0less_node(struct dt_device_node *node,
     if ( domu_dt_sci_parse(node, d_cfg) )
         panic("Error getting SCI configuration\n");
 
+    if (!dt_property_read_string(node, "v8r_el1_msa", &v8r_el1_msa))
+    {
+#ifdef CONFIG_MPU
+        if ( !strcmp(v8r_el1_msa, "mmu") )
+        {
+            if ( !has_v8r_vmsa_support() )
+                panic("Platform does not support VMSA at EL1 (v8r_el1_msa)\n");
+            d_cfg->arch.v8r_el1_msa = MPU_EL1_VMSA;
+        }
+        else if ( !strcmp(v8r_el1_msa, "mpu") )
+        {
+            d_cfg->arch.v8r_el1_msa = MPU_EL1_PMSA;
+            if ( !(flags & CDF_staticmem) || !(flags & CDF_directmap) )
+                panic("PMSA is not valid for domain without static allocation and direct map (v8r_el1_msa)\n");
+        }
+        else
+            panic("Invalid device tree option for v8r_el1_msa\n");
+#else
+        panic("'v8r_el1_msa' property found, but CONFIG_MPU not selected\n");
+#endif
+    }
+
     if ( !dt_property_read_u32(node, "nr_spis", &d_cfg->arch.nr_spis) )
     {
         int vpl011_virq = GUEST_VPL011_SPI;
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 26380a807cad..c044293acd39 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -725,6 +725,10 @@ int arch_domain_create(struct domain *d,
     if ( (rc = sci_domain_init(d, config)) != 0 )
         goto fail;
 
+#ifdef CONFIG_MPU
+    d->arch.v8r_el1_msa = config->arch.v8r_el1_msa;
+#endif
+
     return 0;
 
 fail:
diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h
index ffe5d0d9f0a6..fd0a83046893 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -30,6 +30,9 @@ enum domain_type {
 #define is_64bit_domain(d) (0)
 #endif
 
+#define MPU_EL1_PMSA 0
+#define MPU_EL1_VMSA 1
+
 /*
  * Is the domain using the host memory layout?
  *
@@ -128,6 +131,10 @@ struct arch_domain
 #endif
 
     struct resume_info resume_ctx;
+
+#ifdef CONFIG_MPU
+    uint8_t v8r_el1_msa;
+#endif
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h
index 72fa5b00b861..8a8c01086206 100644
--- a/xen/arch/arm/include/asm/mpu.h
+++ b/xen/arch/arm/include/asm/mpu.h
@@ -27,6 +27,11 @@
 
 #ifndef __ASSEMBLER__
 
+/*
+ * Utility function to determine if an Armv8-R processor supports VMSA.
+ */
+bool has_v8r_vmsa_support(void);
+
 /*
  * Set base address of MPU protection region.
  *
diff --git a/xen/arch/arm/mpu/arm32/mm.c b/xen/arch/arm/mpu/arm32/mm.c
index a4673c351141..5eaeb3400e6c 100644
--- a/xen/arch/arm/mpu/arm32/mm.c
+++ b/xen/arch/arm/mpu/arm32/mm.c
@@ -38,6 +38,11 @@
         break;                                            \
     }
 
+bool has_v8r_vmsa_support(void)
+{
+    return false;
+}
+
 /*
  * Armv8-R supports direct access and indirect access to the MPU regions through
  * registers:
diff --git a/xen/arch/arm/mpu/arm64/mm.c b/xen/arch/arm/mpu/arm64/mm.c
index ed643cad4073..b07e729a7d05 100644
--- a/xen/arch/arm/mpu/arm64/mm.c
+++ b/xen/arch/arm/mpu/arm64/mm.c
@@ -32,6 +32,11 @@
         break;                                                  \
     }
 
+bool has_v8r_vmsa_support(void)
+{
+    return system_cpuinfo.mm64.msa_frac == MM64_MSA_FRAC_VMSA_SUPPORT;
+}
+
 /*
  * Armv8-R supports direct access and indirect access to the MPU regions through
  * registers:
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index cd563cf70684..23df2f24cb09 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -355,6 +355,8 @@ struct xen_arch_domainconfig {
     uint32_t clock_frequency;
     /* IN */
     uint8_t arm_sci_type;
+    /* IN */
+    uint8_t v8r_el1_msa;
 };
 #endif /* __XEN__ || __XEN_TOOLS__ */
 
-- 
2.34.1
Re: [PATCH v3 2/3] arm/mpu: Introduce `v8r_el1_msa` device tree property for domains
Posted by Andrew Cooper 4 days, 6 hours ago
On 08/04/2026 2:55 pm, Luca Fancellu wrote:
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index cd563cf70684..23df2f24cb09 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -355,6 +355,8 @@ struct xen_arch_domainconfig {
>      uint32_t clock_frequency;
>      /* IN */
>      uint8_t arm_sci_type;
> +    /* IN */
> +    uint8_t v8r_el1_msa;
>  };
>  #endif /* __XEN__ || __XEN_TOOLS__ */
>  

This isn't ok as the singular change to the public headers.  (Also, I
haven't had time to fix the other API abuses that have crept into ARM's
arch domain config)

You're introducing a new hypercall input parameter (which is fine), but
has no defines (ones private to xen/arch/arm/include/asm/domain.h are
not permitted for use in the public API), and for which there is no
input validation.  Userspace can currently pass any arbitrary byte here
which will be copied into d->arch.v8r_el1_msa, not that there's any
consumer of this field I can see in the series.

Frankly, I think this series is chopped up too much.  You really must
not be introducing new hypercall parameters like this without the whole
series which lets you `xl create` such a VM.

~Andrew

Re: [PATCH v3 2/3] arm/mpu: Introduce `v8r_el1_msa` device tree property for domains
Posted by Luca Fancellu 3 days, 14 hours ago
Hi Andrew,

> On 8 Apr 2026, at 16:40, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
> 
> On 08/04/2026 2:55 pm, Luca Fancellu wrote:
>> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
>> index cd563cf70684..23df2f24cb09 100644
>> --- a/xen/include/public/arch-arm.h
>> +++ b/xen/include/public/arch-arm.h
>> @@ -355,6 +355,8 @@ struct xen_arch_domainconfig {
>>     uint32_t clock_frequency;
>>     /* IN */
>>     uint8_t arm_sci_type;
>> +    /* IN */
>> +    uint8_t v8r_el1_msa;
>> };
>> #endif /* __XEN__ || __XEN_TOOLS__ */
>> 
> 
> This isn't ok as the singular change to the public headers.  (Also, I
> haven't had time to fix the other API abuses that have crept into ARM's
> arch domain config)
> 
> You're introducing a new hypercall input parameter (which is fine), but
> has no defines (ones private to xen/arch/arm/include/asm/domain.h are
> not permitted for use in the public API), and for which there is no
> input validation.  Userspace can currently pass any arbitrary byte here
> which will be copied into d->arch.v8r_el1_msa, not that there's any
> consumer of this field I can see in the series.
> 
> Frankly, I think this series is chopped up too much.  You really must
> not be introducing new hypercall parameters like this without the whole
> series which lets you `xl create` such a VM.

Thanks for this feedback, while reworking this patch I was wrongly assuming I had always
zero from the toolstack as this is not supported atm, while instead it’s not true for malicious
userspace hypercall callers.

The full branch is available at https://gitlab.com/xen-project/people/lucafancellu/xen/-/commits/r82_rebased?ref_type=heads,
but it doesn’t support domain creation by the toolstack, only by Dom0less.

For the defines, should I have something in the file xen/xen/include/public/arch-arm.h like this:

#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA      0
#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA      1

And check the value of config->arch.v8r_el1_msa against them in arch_sanitise_domain_config?

Cheers,
Luca