@@ -1,6 +1,8 @@
#ifndef KVM__KVM_CONFIG_ARCH_H
#define KVM__KVM_CONFIG_ARCH_H
+int sve_vls_parser(const struct option *opt, const char *arg, int unset);
+
#define ARM_OPT_ARCH_RUN(cfg) \
OPT_BOOLEAN('\0', "aarch32", &(cfg)->aarch32_guest, \
"Run AArch32 guest"), \
@@ -10,6 +12,9 @@
"Enable SVE for the guest"), \
OPT_BOOLEAN('\0', "show-reg-list", &(cfg)->show_reg_list, \
"Show the list of KVM register IDs on startup"), \
+ OPT_CALLBACK('\0', "sve-vqs", NULL, "comma-separated list", \
+ "Override the SVE vector lengths supported", \
+ sve_vls_parser, NULL), \
OPT_U64('\0', "kaslr-seed", &(cfg)->kaslr_seed, \
"Specify random seed for Kernel Address Space " \
"Layout Randomization (KASLR)"),
@@ -6,6 +6,72 @@
#include "kvm/kvm.h"
#include "kvm/kvm-cpu.h"
+static int vqs_set;
+static u64 sve_vq_map[8];
+
+static int add_vq(int vq)
+{
+ if (vq < 1 || vq > 512) {
+ fprintf(stderr, "%d: VQ out of range\n", vq);
+ return -1;
+ }
+
+ --vq;
+ sve_vq_map[vq / 64] |= (u64)1 << vq;
+ return 0;
+}
+
+int sve_vls_parser(const struct option *opt, const char *arg, int unset)
+{
+ int n = -1, val;
+ size_t offset = 0;
+
+ if (sscanf(arg + offset, "%i%n", &val, &n) < 1 || n < 0)
+ goto mismatch;
+
+ if (add_vq(val))
+ return -1;
+
+ offset += n;
+ while (1) {
+ n = -1;
+ if (sscanf(arg + offset, ",%i%n", &val, &n) < 1 && n < 0)
+ break;
+
+ if (add_vq(val))
+ return -1;
+
+ offset += n;
+ }
+
+mismatch:
+ if (arg[offset]) {
+ fprintf(stderr, "Bad set of vector lengths: %s\n", arg);
+ return -1;
+ }
+
+ vqs_set = -1;
+
+ return 0;
+}
+
+static int try_to_set_vqs(struct kvm_cpu const *vcpu)
+{
+ struct kvm_one_reg reg;
+
+ if (!vqs_set)
+ return 0; /* nothing to do */
+
+ reg.addr = (u64)&sve_vq_map;
+ reg.id = KVM_REG_ARM64_SVE_VLS;
+ if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®)) {
+ perror("KVM_SET_ONE_REG(KVM_REG_ARM64_SVE_VLS)");
+ return -1;
+ }
+
+ return 0;
+}
+
static int kvm_show_reg_list(struct kvm_cpu const *vcpu)
{
int ret = -1;
@@ -263,9 +329,23 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
if (err || target->init(vcpu))
die("Unable to initialise vcpu");
+ if (kvm->cfg.arch.show_reg_list)
+ kvm_show_sve_info(vcpu);
+
+ if (try_to_set_vqs(vcpu))
+ die("SVE vector length configuration failed");
+
if (kvm->cfg.arch.show_reg_list) {
+ puts("After setting SVE vector lengths:");
kvm_show_sve_info(vcpu);
+
kvm_show_reg_list(vcpu);
+
+ if (!try_to_set_vqs(vcpu)) {
+ if (vqs_set)
+ die("SVE vector length configuration after KVM_GET_REG_LIST succeeded unexpectedly");
+ } else
+ puts("(as expected)");
}
coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
By default, for each vcpu KVM enabled the same set of SVE vector as supported by the host. In order to allow a different set of vector lengths permitted (to the extent supported by the SVE architecture), an option --sve-vqs is added, which accepts a comma-separated list of vector lengths to enable. This options follows the "vq" convention, describing the vector length as a multiple of 128-bit quadwords. This is largely for developer convenience and may be confusing for users. Although KVM supports a different set of vector lengths to be enabled on each vcpu, this patch provides no means to request such a configuration for now. Support could be added later, if desired. Signed-off-by: Dave Martin <Dave.Martin@arm.com> --- arm/aarch64/include/kvm/kvm-config-arch.h | 5 ++ arm/kvm-cpu.c | 80 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+)