@@ -777,9 +777,9 @@ Specify the bit width of the DMA heap.
### dom0
= List of [ pv | pvh, shadow=<bool>, verbose=<bool>,
- cpuid-faulting=<bool>, msr-relaxed=<bool> ]
+ cpuid-faulting=<bool>, msr-relaxed=<bool> ] (x86)
- Applicability: x86
+ = List of [ sve=<integer> ] (Arm64)
Controls for how dom0 is constructed on x86 systems.
@@ -838,6 +838,22 @@ Controls for how dom0 is constructed on x86 systems.
If using this option is necessary to fix an issue, please report a bug.
+Enables features on dom0 on Arm systems.
+
+* The `sve` integer parameter enables Arm SVE usage for Dom0 and sets the
+ maximum SVE vector length, the option is applicable only to Arm64 Dom0
+ kernels.
+ A value equal to 0 disables the feature, this is the default value.
+ Values below 0 means the feature uses the maximum SVE vector length
+ supported by hardware, if SVE is supported.
+ Values above 0 explicitly set the maximum SVE vector length for Dom0,
+ allowed values are from 128 to maximum 2048, being multiple of 128.
+ Please note that when the user explicitly specifies the value, if that value
+ is above the hardware supported maximum SVE vector length, the domain
+ creation will fail and the system will stop, the same will occur if the
+ option is provided with a positive non zero value, but the platform doesn't
+ support SVE.
+
### dom0-cpuid
= List of comma separated booleans
@@ -13,6 +13,9 @@
#include <asm/processor.h>
#include <asm/system.h>
+/* opt_dom0_sve: allow Dom0 to use SVE and set maximum vector length. */
+int __initdata opt_dom0_sve;
+
extern unsigned int sve_get_hw_vl(void);
/*
@@ -152,6 +155,23 @@ void sve_restore_state(struct vcpu *v)
sve_load_ctx(v->arch.vfp.sve_zreg_ctx_end, v->arch.vfp.fpregs, 1);
}
+bool __init sve_domctl_vl_param(int val, unsigned int *out)
+{
+ /*
+ * Negative SVE parameter value means to use the maximum supported
+ * vector length, otherwise if a positive value is provided, check if the
+ * vector length is a multiple of 128
+ */
+ if ( val < 0 )
+ *out = get_sys_vl_len();
+ else if ( (val % SVE_VL_MULTIPLE_VAL) == 0 )
+ *out = val;
+ else
+ return false;
+
+ return true;
+}
+
/*
* Local variables:
* mode: C
@@ -62,6 +62,22 @@ custom_param("dom0_mem", parse_dom0_mem);
int __init parse_arch_dom0_param(const char *s, const char *e)
{
+ long long val;
+
+ if ( !parse_signed_integer("sve", s, e, &val) )
+ {
+#ifdef CONFIG_ARM64_SVE
+ if ( (val >= INT_MIN) && (val <= INT_MAX) )
+ opt_dom0_sve = val;
+ else
+ printk(XENLOG_INFO "'sve=%lld' value out of range!\n", val);
+
+ return 0;
+#else
+ panic("'sve' property found, but CONFIG_ARM64_SVE not selected");
+#endif
+ }
+
return -EINVAL;
}
@@ -4134,6 +4150,16 @@ void __init create_dom0(void)
if ( iommu_enabled )
dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
+ if ( opt_dom0_sve )
+ {
+ unsigned int vl;
+
+ if ( sve_domctl_vl_param(opt_dom0_sve, &vl) )
+ dom0_cfg.arch.sve_vl = sve_encode_vl(vl);
+ else
+ panic("SVE vector length error\n");
+ }
+
dom0 = domain_create(0, &dom0_cfg, CDF_privileged | CDF_directmap);
if ( IS_ERR(dom0) )
panic("Error creating domain 0 (rc = %ld)\n", PTR_ERR(dom0));
@@ -21,14 +21,22 @@ static inline unsigned int sve_decode_vl(unsigned int sve_vl)
return sve_vl * SVE_VL_MULTIPLE_VAL;
}
+static inline unsigned int sve_encode_vl(unsigned int sve_vl_bits)
+{
+ return sve_vl_bits / SVE_VL_MULTIPLE_VAL;
+}
+
register_t compute_max_zcr(void);
int sve_context_init(struct vcpu *v);
void sve_context_free(struct vcpu *v);
void sve_save_state(struct vcpu *v);
void sve_restore_state(struct vcpu *v);
+bool sve_domctl_vl_param(int val, unsigned int *out);
#ifdef CONFIG_ARM64_SVE
+extern int opt_dom0_sve;
+
static inline bool is_sve_domain(const struct domain *d)
{
return d->arch.sve_vl > 0;
@@ -38,6 +46,8 @@ unsigned int get_sys_vl_len(void);
#else /* !CONFIG_ARM64_SVE */
+#define opt_dom0_sve 0
+
static inline bool is_sve_domain(const struct domain *d)
{
return false;
@@ -314,6 +314,34 @@ int parse_boolean(const char *name, const char *s, const char *e)
return -1;
}
+int __init parse_signed_integer(const char *name, const char *s, const char *e,
+ long long *val)
+{
+ size_t slen, nlen;
+ const char *str;
+ long long pval;
+
+ slen = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
+ nlen = strlen(name);
+
+ if ( !e )
+ e = s + slen;
+
+ /* Check that this is the name we're looking for and a value was provided */
+ if ( slen <= nlen || strncmp(s, name, nlen) || s[nlen] != '=' )
+ return -1;
+
+ pval = simple_strtoll(&s[nlen + 1], &str, 10);
+
+ /* Number not recognised */
+ if ( str != e )
+ return -2;
+
+ *val = pval;
+
+ return 0;
+}
+
int cmdline_strcmp(const char *frag, const char *name)
{
for ( ; ; frag++, name++ )
@@ -94,6 +94,16 @@ int parse_bool(const char *s, const char *e);
*/
int parse_boolean(const char *name, const char *s, const char *e);
+/**
+ * Given a specific name, parses a string of the form:
+ * $NAME=<integer number>
+ * returning 0 and a value in val, for a recognised integer.
+ * Returns -1 for name not found, general errors, or -2 if name is found but
+ * not recognised number.
+ */
+int parse_signed_integer(const char *name, const char *s, const char *e,
+ long long *val);
+
/**
* Very similar to strcmp(), but will declare a match if the NUL in 'name'
* lines up with comma, colon, semicolon or equals in 'frag'. Designed for