diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt index 977b428608..f73839df09 100644 --- a/docs/misc/arm/device-tree/booting.txt +++ b/docs/misc/arm/device-tree/booting.txt @@ -322,6 +322,20 @@ 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 at EL1, a domain + should use PMSAv8 (MPU) or VMSAv8 (MMU). + + - "mmu" + Enables VMSAv8 at EL1. This requires hardware support and is only + optionally available on AArch64. Not supported on AArch32. + + - "mpu" + Enables PMSAv8 at EL1. This is the default behavior when the property is + not passed. This configuration requires static allocation (xen,static-mem) + and direct mapping (direct-map). + 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 52cf788a45..3f48f74226 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -302,6 +302,65 @@ static int __init domu_dt_sci_parse(struct dt_device_node *node, return 0; } +static int __init +domu_dt_v8r_el1_msa_parse(const struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg, + unsigned int flags) +{ + const char *value; + int ret; + + if ( !IS_ENABLED(CONFIG_MPU) ) + { + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE; + + if ( !dt_property_read_bool(node, "v8r_el1_msa") ) + return 0; + + printk(XENLOG_ERR + "v8r_el1_msa not supported on this build for domain %s\n", + dt_node_full_name(node)); + return -EINVAL; + } + + ret = dt_property_read_string(node, "v8r_el1_msa", &value); + /* Property absent: PMSA is the default */ + if ( ret == -EINVAL ) + value = "mpu"; + else if ( ret ) + return ret; + + if ( !strcmp(value, "mpu") ) + { + if ( !(flags & CDF_staticmem) || !(flags & CDF_directmap) ) + { + printk(XENLOG_ERR + "v8r_el1_msa=mpu requires static-mem and direct-map for domain %s\n", + dt_node_full_name(node)); + return -EINVAL; + } + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA; + return 0; + } + + if ( !strcmp(value, "mmu") ) + { + if ( !has_v8r_vmsa_support() ) + { + printk(XENLOG_ERR + "v8r_el1_msa=mmu unsupported by platform for domain %s\n", + dt_node_full_name(node)); + return -EINVAL; + } + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA; + return 0; + } + + printk(XENLOG_ERR "v8r_el1_msa value '%s' not valid for domain %s\n", + value, dt_node_full_name(node)); + return -EINVAL; +} + int __init arch_parse_dom0less_node(struct dt_device_node *node, struct boot_domain *bd) { @@ -315,6 +374,9 @@ 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 ( domu_dt_v8r_el1_msa_parse(node, d_cfg, flags) ) + panic("Error getting v8r_el1_msa configuration\n"); + 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 26380a807c..baa3a5d708 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -538,6 +538,25 @@ void vcpu_switch_to_aarch64_mode(struct vcpu *v) v->arch.hcr_el2 |= HCR_RW; } +static bool v8r_el1_msa_domain_sanitise_config( + const struct xen_domctl_createdomain *config) +{ + switch ( config->arch.v8r_el1_msa ) + { + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE: + return !IS_ENABLED(CONFIG_MPU); + + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA: + return IS_ENABLED(CONFIG_MPU); + + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA: + return IS_ENABLED(CONFIG_MPU) && IS_ENABLED(CONFIG_ARM_64); + + default: + return false; + } +} + int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) { unsigned int max_vcpus; @@ -554,6 +573,14 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) return -EINVAL; } + /* Check config structure padding */ + if ( config->arch.pad ) + { + dprintk(XENLOG_INFO, + "Invalid domain configuration during domain creation\n"); + return -EINVAL; + } + /* Check feature flags */ if ( sve_vl_bits > 0 ) { @@ -630,6 +657,12 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) return -EINVAL; } + if ( !v8r_el1_msa_domain_sanitise_config(config) ) + { + dprintk(XENLOG_INFO, "Unsupported v8r_el1_msa value\n"); + return -EINVAL; + } + return sci_domain_sanitise_config(config); } @@ -722,6 +755,10 @@ int arch_domain_create(struct domain *d, d->arch.sve_vl = config->arch.sve_vl; #endif +#ifdef CONFIG_MPU + d->arch.v8r_el1_msa = config->arch.v8r_el1_msa; +#endif + if ( (rc = sci_domain_init(d, config)) != 0 ) goto fail; diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index 46a5cdc0c8..c3d2c4981f 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -98,6 +98,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/domain_build.h b/xen/arch/arm/include/asm/domain_build.h index 6674dac5e2..df8b361b3d 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -19,6 +19,16 @@ int prepare_acpi(struct domain *d, struct kernel_info *kinfo); int add_ext_regions(unsigned long s_gfn, unsigned long e_gfn, void *data); +#if defined(CONFIG_MPU) && defined(CONFIG_ARM_64) +/* Utility function to determine if an Armv8-R processor supports VMSA. */ +bool has_v8r_vmsa_support(void); +#else +static inline bool has_v8r_vmsa_support(void) +{ + return false; +} +#endif /* CONFIG_MPU */ + #endif /* diff --git a/xen/arch/arm/mpu/arm64/mm.c b/xen/arch/arm/mpu/arm64/mm.c index ed643cad40..b07e729a7d 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 cd563cf706..7d6f87e8b2 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -330,6 +330,10 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); #define XEN_DOMCTL_CONFIG_ARM_SCI_NONE 0 #define XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC 1 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE 0 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA 1 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA 2 + struct xen_arch_domainconfig { /* IN/OUT */ uint8_t gic_version; @@ -355,6 +359,9 @@ struct xen_arch_domainconfig { uint32_t clock_frequency; /* IN */ uint8_t arm_sci_type; + /* IN */ + uint8_t v8r_el1_msa; + uint16_t pad; }; #endif /* __XEN__ || __XEN_TOOLS__ */ diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 8f6708c0a7..23124547f3 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -30,9 +30,9 @@ * fields) don't require a change of the version. * Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION! * - * Last version bump: Xen 4.19 + * Last version bump: Xen 4.22 */ -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000017 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000018 /* * NB. xen_domctl.domain is an IN/OUT parameter for this operation.