@@ -10,6 +10,7 @@
#include <xen/sched.h>
#include <xen/hypercall.h>
#include <public/domctl.h>
+#include <asm/arm64/sve.h>
#include <asm/cpufeature.h>
static long switch_mode(struct domain *d, enum domain_type type)
@@ -43,6 +44,9 @@ long subarch_do_domctl(struct xen_domctl *domctl, struct domain *d,
case 32:
if ( !cpu_has_el1_32 )
return -EINVAL;
+ /* SVE is not supported for 32 bit domain */
+ if ( is_sve_domain(d) )
+ return -EINVAL;
return switch_mode(d, DOMAIN_32BIT);
case 64:
return switch_mode(d, DOMAIN_64BIT);
@@ -8,6 +8,7 @@
#include <xen/types.h>
#include <asm/arm64/sve.h>
#include <asm/arm64/sysregs.h>
+#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -49,6 +50,17 @@ register_t compute_max_zcr(void)
return vl_to_zcr(hw_vl);
}
+/* Get the system sanitized value for VL in bits */
+unsigned int get_sys_vl_len(void)
+{
+ if ( !cpu_has_sve )
+ return 0;
+
+ /* ZCR_ELx len field is ((len + 1) * 128) = vector bits length */
+ return ((system_cpuinfo.zcr64.bits[0] & ZCR_ELx_LEN_MASK) + 1U) *
+ SVE_VL_MULTIPLE_VAL;
+}
+
/*
* Local variables:
* mode: C
@@ -13,6 +13,7 @@
#include <xen/wait.h>
#include <asm/alternative.h>
+#include <asm/arm64/sve.h>
#include <asm/cpuerrata.h>
#include <asm/cpufeature.h>
#include <asm/current.h>
@@ -555,6 +556,8 @@ int arch_vcpu_create(struct vcpu *v)
v->arch.vmpidr = MPIDR_SMP | vcpuid_to_vaffinity(v->vcpu_id);
v->arch.cptr_el2 = get_default_cptr_flags();
+ if ( is_sve_domain(v->domain) )
+ v->arch.cptr_el2 &= ~HCPTR_CP(8);
v->arch.hcr_el2 = get_default_hcr_flags();
@@ -599,6 +602,7 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
unsigned int max_vcpus;
unsigned int flags_required = (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap);
unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu);
+ unsigned int sve_vl_bits = sve_decode_vl(config->arch.sve_vl);
if ( (config->flags & ~flags_optional) != flags_required )
{
@@ -607,6 +611,26 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
return -EINVAL;
}
+ /* Check feature flags */
+ if ( sve_vl_bits > 0 )
+ {
+ unsigned int zcr_max_bits = get_sys_vl_len();
+
+ if ( !zcr_max_bits )
+ {
+ dprintk(XENLOG_INFO, "SVE is unsupported on this machine.\n");
+ return -EINVAL;
+ }
+
+ if ( sve_vl_bits > zcr_max_bits )
+ {
+ dprintk(XENLOG_INFO,
+ "Requested SVE vector length (%u) > supported length (%u)\n",
+ sve_vl_bits, zcr_max_bits);
+ return -EINVAL;
+ }
+ }
+
/* The P2M table must always be shared between the CPU and the IOMMU */
if ( config->iommu_opts & XEN_DOMCTL_IOMMU_no_sharept )
{
@@ -749,6 +773,11 @@ int arch_domain_create(struct domain *d,
if ( (rc = domain_vpci_init(d)) != 0 )
goto fail;
+#ifdef CONFIG_ARM64_SVE
+ /* Copy the encoded vector length sve_vl from the domain configuration */
+ d->arch.sve_vl = config->arch.sve_vl;
+#endif
+
return 0;
fail:
@@ -26,6 +26,7 @@
#include <asm/platform.h>
#include <asm/psci.h>
#include <asm/setup.h>
+#include <asm/arm64/sve.h>
#include <asm/cpufeature.h>
#include <asm/domain_build.h>
#include <xen/event.h>
@@ -3691,6 +3692,12 @@ static int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
return -EINVAL;
}
+ if ( is_sve_domain(d) && (kinfo->type == DOMAIN_32BIT) )
+ {
+ printk("SVE is not available for 32-bit domain\n");
+ return -EINVAL;
+ }
+
if ( is_64bit_domain(d) )
vcpu_switch_to_aarch64_mode(v);
@@ -8,13 +8,44 @@
#ifndef _ARM_ARM64_SVE_H
#define _ARM_ARM64_SVE_H
+#include <xen/sched.h>
+
#define SVE_VL_MAX_BITS 2048U
/* Vector length must be multiple of 128 */
#define SVE_VL_MULTIPLE_VAL 128U
+static inline unsigned int sve_decode_vl(unsigned int sve_vl)
+{
+ /* SVE vector length is stored as VL/128 in xen_arch_domainconfig */
+ return sve_vl * SVE_VL_MULTIPLE_VAL;
+}
+
register_t compute_max_zcr(void);
+#ifdef CONFIG_ARM64_SVE
+
+static inline bool is_sve_domain(const struct domain *d)
+{
+ return d->arch.sve_vl > 0;
+}
+
+unsigned int get_sys_vl_len(void);
+
+#else /* !CONFIG_ARM64_SVE */
+
+static inline bool is_sve_domain(const struct domain *d)
+{
+ return false;
+}
+
+static inline unsigned int get_sys_vl_len(void)
+{
+ return 0;
+}
+
+#endif /* CONFIG_ARM64_SVE */
+
#endif /* _ARM_ARM64_SVE_H */
/*
@@ -67,6 +67,11 @@ struct arch_domain
enum domain_type type;
#endif
+#ifdef CONFIG_ARM64_SVE
+ /* max SVE encoded vector length */
+ uint8_t sve_vl;
+#endif
+
/* Virtual MMU */
struct p2m_domain p2m;
@@ -300,6 +300,8 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
struct xen_arch_domainconfig {
/* IN/OUT */
uint8_t gic_version;
+ /* IN - Contains SVE vector length divided by 128 */
+ uint8_t sve_vl;
/* IN */
uint16_t tee_type;
/* IN */