Skip to content

Commit 5db1bef

Browse files
Fuad TabbaMarc Zyngier
andcommitted
KVM: arm64: Track SVE state in the hypervisor vcpu structure
When dealing with a guest with SVE enabled, make sure the host SVE state is pinned at EL2 S1, and that the hypervisor vCPU state is correctly initialised (and then unpinned on teardown). Co-authored-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Fuad Tabba <tabba@google.com> Signed-off-by: Quentin Perret <qperret@google.com> Link: https://lore.kernel.org/r/20250416152648.2982950-2-qperret@google.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent b443265 commit 5db1bef

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -971,20 +971,22 @@ struct kvm_vcpu_arch {
971971
#define vcpu_sve_zcr_elx(vcpu) \
972972
(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
973973

974-
#define vcpu_sve_state_size(vcpu) ({ \
974+
#define sve_state_size_from_vl(sve_max_vl) ({ \
975975
size_t __size_ret; \
976-
unsigned int __vcpu_vq; \
976+
unsigned int __vq; \
977977
\
978-
if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) { \
978+
if (WARN_ON(!sve_vl_valid(sve_max_vl))) { \
979979
__size_ret = 0; \
980980
} else { \
981-
__vcpu_vq = vcpu_sve_max_vq(vcpu); \
982-
__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq); \
981+
__vq = sve_vq_from_vl(sve_max_vl); \
982+
__size_ret = SVE_SIG_REGS_SIZE(__vq); \
983983
} \
984984
\
985985
__size_ret; \
986986
})
987987

988+
#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.sve_max_vl)
989+
988990
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
989991
KVM_GUESTDBG_USE_SW_BP | \
990992
KVM_GUESTDBG_USE_HW | \

arch/arm64/kvm/hyp/nvhe/hyp-main.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,6 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
123123

124124
hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
125125

126-
hyp_vcpu->vcpu.arch.sve_state = kern_hyp_va(host_vcpu->arch.sve_state);
127-
/* Limit guest vector length to the maximum supported by the host. */
128-
hyp_vcpu->vcpu.arch.sve_max_vl = min(host_vcpu->arch.sve_max_vl, kvm_host_sve_max_vl);
129-
130126
hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2;
131127
hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI | HCR_TWE);
132128
hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) &

arch/arm64/kvm/hyp/nvhe/pkvm.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,18 @@ static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu)
372372
hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
373373
}
374374

375+
static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
376+
{
377+
void *sve_state;
378+
379+
if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SVE))
380+
return;
381+
382+
sve_state = kern_hyp_va(hyp_vcpu->vcpu.arch.sve_state);
383+
hyp_unpin_shared_mem(sve_state,
384+
sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
385+
}
386+
375387
static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[],
376388
unsigned int nr_vcpus)
377389
{
@@ -384,6 +396,7 @@ static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[],
384396
continue;
385397

386398
unpin_host_vcpu(hyp_vcpu->host_vcpu);
399+
unpin_host_sve_state(hyp_vcpu);
387400
}
388401
}
389402

@@ -398,12 +411,40 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
398411
pkvm_init_features_from_host(hyp_vm, host_kvm);
399412
}
400413

401-
static void pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu)
414+
static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu)
402415
{
403416
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
417+
unsigned int sve_max_vl;
418+
size_t sve_state_size;
419+
void *sve_state;
420+
int ret = 0;
404421

405-
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE))
422+
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
406423
vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
424+
return 0;
425+
}
426+
427+
/* Limit guest vector length to the maximum supported by the host. */
428+
sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
429+
sve_state_size = sve_state_size_from_vl(sve_max_vl);
430+
sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
431+
432+
if (!sve_state || !sve_state_size) {
433+
ret = -EINVAL;
434+
goto err;
435+
}
436+
437+
ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
438+
if (ret)
439+
goto err;
440+
441+
vcpu->arch.sve_state = sve_state;
442+
vcpu->arch.sve_max_vl = sve_max_vl;
443+
444+
return 0;
445+
err:
446+
clear_bit(KVM_ARM_VCPU_SVE, vcpu->kvm->arch.vcpu_features);
447+
return ret;
407448
}
408449

409450
static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
@@ -432,7 +473,7 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
432473
if (ret)
433474
goto done;
434475

435-
pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu);
476+
ret = pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu);
436477
done:
437478
if (ret)
438479
unpin_host_vcpu(host_vcpu);

0 commit comments

Comments
 (0)