Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit b5b9955

Browse files
Fuad TabbaMarc Zyngier
authored andcommitted
KVM: arm64: Eagerly restore host fpsimd/sve state in pKVM
When running in protected mode we don't want to leak protected guest state to the host, including whether a guest has used fpsimd/sve. Therefore, eagerly restore the host state on guest exit when running in protected mode, which happens only if the guest has used fpsimd/sve. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Fuad Tabba <tabba@google.com> Link: https://lore.kernel.org/r/20240603122852.3923848-7-tabba@google.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 66d5b53 commit b5b9955

File tree

4 files changed

+93
-5
lines changed

4 files changed

+93
-5
lines changed

arch/arm64/kvm/hyp/include/hyp/switch.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
321321
write_sysreg_el1(__vcpu_sys_reg(vcpu, ZCR_EL1), SYS_ZCR);
322322
}
323323

324+
static inline void __hyp_sve_save_host(void)
325+
{
326+
struct cpu_sve_state *sve_state = *host_data_ptr(sve_state);
327+
328+
sve_state->zcr_el1 = read_sysreg_el1(SYS_ZCR);
329+
write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
330+
__sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
331+
&sve_state->fpsr,
332+
true);
333+
}
334+
324335
static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu);
325336

326337
/*
@@ -355,7 +366,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
355366
/* Valid trap. Switch the context: */
356367

357368
/* First disable enough traps to allow us to update the registers */
358-
if (sve_guest)
369+
if (sve_guest || (is_protected_kvm_enabled() && system_supports_sve()))
359370
cpacr_clear_set(0, CPACR_ELx_FPEN | CPACR_ELx_ZEN);
360371
else
361372
cpacr_clear_set(0, CPACR_ELx_FPEN);

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

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,80 @@ DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
2323

2424
void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
2525

26+
static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
27+
{
28+
__vcpu_sys_reg(vcpu, ZCR_EL1) = read_sysreg_el1(SYS_ZCR);
29+
/*
30+
* On saving/restoring guest sve state, always use the maximum VL for
31+
* the guest. The layout of the data when saving the sve state depends
32+
* on the VL, so use a consistent (i.e., the maximum) guest VL.
33+
*/
34+
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
35+
__sve_save_state(vcpu_sve_pffr(vcpu), &vcpu->arch.ctxt.fp_regs.fpsr, true);
36+
write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
37+
}
38+
39+
static void __hyp_sve_restore_host(void)
40+
{
41+
struct cpu_sve_state *sve_state = *host_data_ptr(sve_state);
42+
43+
/*
44+
* On saving/restoring host sve state, always use the maximum VL for
45+
* the host. The layout of the data when saving the sve state depends
46+
* on the VL, so use a consistent (i.e., the maximum) host VL.
47+
*
48+
* Setting ZCR_EL2 to ZCR_ELx_LEN_MASK sets the effective length
49+
* supported by the system (or limited at EL3).
50+
*/
51+
write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
52+
__sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
53+
&sve_state->fpsr,
54+
true);
55+
write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
56+
}
57+
58+
static void fpsimd_sve_flush(void)
59+
{
60+
*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
61+
}
62+
63+
static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
64+
{
65+
if (!guest_owns_fp_regs())
66+
return;
67+
68+
cpacr_clear_set(0, CPACR_ELx_FPEN | CPACR_ELx_ZEN);
69+
isb();
70+
71+
if (vcpu_has_sve(vcpu))
72+
__hyp_sve_save_guest(vcpu);
73+
else
74+
__fpsimd_save_state(&vcpu->arch.ctxt.fp_regs);
75+
76+
if (system_supports_sve())
77+
__hyp_sve_restore_host();
78+
else
79+
__fpsimd_restore_state(*host_data_ptr(fpsimd_state));
80+
81+
*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
82+
}
83+
2684
static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
2785
{
2886
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
2987

88+
fpsimd_sve_flush();
89+
3090
hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
3191

3292
hyp_vcpu->vcpu.arch.sve_state = kern_hyp_va(host_vcpu->arch.sve_state);
33-
hyp_vcpu->vcpu.arch.sve_max_vl = host_vcpu->arch.sve_max_vl;
93+
/* Limit guest vector length to the maximum supported by the host. */
94+
hyp_vcpu->vcpu.arch.sve_max_vl = min(host_vcpu->arch.sve_max_vl, kvm_host_sve_max_vl);
3495

3596
hyp_vcpu->vcpu.arch.hw_mmu = host_vcpu->arch.hw_mmu;
3697

3798
hyp_vcpu->vcpu.arch.hcr_el2 = host_vcpu->arch.hcr_el2;
3899
hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2;
39-
hyp_vcpu->vcpu.arch.cptr_el2 = host_vcpu->arch.cptr_el2;
40100

41101
hyp_vcpu->vcpu.arch.iflags = host_vcpu->arch.iflags;
42102

@@ -54,10 +114,11 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
54114
struct vgic_v3_cpu_if *host_cpu_if = &host_vcpu->arch.vgic_cpu.vgic_v3;
55115
unsigned int i;
56116

117+
fpsimd_sve_sync(&hyp_vcpu->vcpu);
118+
57119
host_vcpu->arch.ctxt = hyp_vcpu->vcpu.arch.ctxt;
58120

59121
host_vcpu->arch.hcr_el2 = hyp_vcpu->vcpu.arch.hcr_el2;
60-
host_vcpu->arch.cptr_el2 = hyp_vcpu->vcpu.arch.cptr_el2;
61122

62123
host_vcpu->arch.fault = hyp_vcpu->vcpu.arch.fault;
63124

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
588588
if (ret)
589589
unmap_donated_memory(hyp_vcpu, sizeof(*hyp_vcpu));
590590

591+
hyp_vcpu->vcpu.arch.cptr_el2 = kvm_get_reset_cptr_el2(&hyp_vcpu->vcpu);
592+
591593
return ret;
592594
}
593595

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,21 @@ static bool kvm_handle_pvm_sys64(struct kvm_vcpu *vcpu, u64 *exit_code)
184184

185185
static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
186186
{
187-
__fpsimd_save_state(*host_data_ptr(fpsimd_state));
187+
/*
188+
* Non-protected kvm relies on the host restoring its sve state.
189+
* Protected kvm restores the host's sve state as not to reveal that
190+
* fpsimd was used by a guest nor leak upper sve bits.
191+
*/
192+
if (unlikely(is_protected_kvm_enabled() && system_supports_sve())) {
193+
__hyp_sve_save_host();
194+
195+
/* Re-enable SVE traps if not supported for the guest vcpu. */
196+
if (!vcpu_has_sve(vcpu))
197+
cpacr_clear_set(CPACR_ELx_ZEN, 0);
198+
199+
} else {
200+
__fpsimd_save_state(*host_data_ptr(fpsimd_state));
201+
}
188202
}
189203

190204
static const exit_handler_fn hyp_exit_handlers[] = {

0 commit comments

Comments
 (0)