KVM/arm64 fixes for 7.1, take #4

- Restore CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC to its former glory by
   making sure the config symbol is correctly spelled out in the code
 
 - Don't reset the AArch32 view of the PMU counters to zero when the
   guest is writing to them
 
 - Fix an assorted collection of memory leaks in the newly added tracing
   code
 
 - Fix the capping of ZCR_EL2 which could be used in an unsanitised way
   by an L2 guest
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAmoZbFAACgkQI9DQutE9
 ekMqHA/+MUfOMP8C8q87SVWsb8JrtMoZKBl6YWsn19kSGXkR14HVTLwmTWsYCNfi
 KvuOf5p0ALvCt9KhE8EUpsIScwdcLMJWjwKbzKkgooX9YwlgMLxA5w3He6GgyTzB
 0fCqQ/2H/frJP1kdQI567Zc4eO7JNcMJfI+/lrZxUM6xbo0KyhehQcFlTBVm5/h/
 RptX9n1NqdJ1qqbJw7UkAAt0hDMIAvDxZyTKGYTQla/+ckK+UEa6UUl/1pfXPs6Y
 Domxu7OO9qQFSxR3KfFlHEml4lrLxNTiCFzoBgPCrf83vAkK0Ceudj3luCs7UDMX
 j4sH44ddHDoO/8BmueNzsQ+gHTqmDaQGRu3G8m/4EN0dCnD5TsQ9FtaB7LErRFze
 wZCTxiAuAxAaQC41H/Nul3S+7D92/vRW664b7HPf92uvD4QpGA96qvafnz9SK8AN
 CyiB4EBElau+D4nOBJ7MO9vu0doWwnTXRHSIvJv8mRkkYedhEv9G8OX8QOgLGi2r
 /uYtMYRcZ6tglvVhQzcOwpHe//oJ7CGxfACgwUhH2XjL1V3tDuCtCfQheo242UAe
 nBUfs1R38UyaWKZmlkzymHygAprw2s/idAIJV7i80rDGwAuNTdMV3SyjC1so7ZGP
 1grcr7yi2aPr3phA1RWD5bbGZhTl8a+fzyKrwIltz3rTAaV7lOk=
 =bNQ/
 -----END PGP SIGNATURE-----

Merge tag 'kvmarm-fixes-7.1-4' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 7.1, take #4

- Restore CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC to its former glory by
  making sure the config symbol is correctly spelled out in the code

- Don't reset the AArch32 view of the PMU counters to zero when the
  guest is writing to them

- Fix an assorted collection of memory leaks in the newly added tracing
  code

- Fix the capping of ZCR_EL2 which could be used in an unsanitised way
  by an L2 guest
This commit is contained in:
Paolo Bonzini 2026-05-29 19:30:56 +02:00
commit 5ff17b1958
7 changed files with 28 additions and 21 deletions

View File

@ -511,7 +511,6 @@ enum vcpu_sysreg {
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
HACR_EL2, /* Hypervisor Auxiliary Control Register */
ZCR_EL2, /* SVE Control Register (EL2) */
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
TCR_EL2, /* Translation Control Register (EL2) */
@ -543,6 +542,7 @@ enum vcpu_sysreg {
SCTLR2_EL2, /* System Control Register 2 (EL2) */
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
ZCR_EL2, /* SVE Control Register (EL2) */
/* Any VNCR-capable reg goes after this point */
MARKER(__VNCR_START__),

View File

@ -462,11 +462,13 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
{
u64 zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
/*
* The vCPU's saved SVE state layout always matches the max VL of the
* vCPU. Start off with the max VL so we can load the SVE state.
*/
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
__sve_restore_state(vcpu_sve_pffr(vcpu),
&vcpu->arch.ctxt.fp_regs.fpsr,
true);
@ -476,8 +478,10 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
* nested guest, as the guest hypervisor could select a smaller VL. Slap
* that into hardware before wrapping up.
*/
if (is_nested_ctxt(vcpu))
sve_cond_update_zcr_vq(__vcpu_sys_reg(vcpu, ZCR_EL2), SYS_ZCR_EL2);
if (is_nested_ctxt(vcpu)) {
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
}
write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
}
@ -501,11 +505,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
return;
if (vcpu_has_sve(vcpu)) {
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
/* A guest hypervisor may restrict the effective max VL. */
if (is_nested_ctxt(vcpu))
zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2);
else
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
write_sysreg_el2(zcr_el2, SYS_ZCR);

View File

@ -120,7 +120,7 @@ SYM_FUNC_START(__hyp_do_panic)
mov x29, x0
#ifdef PKVM_DISABLE_STAGE2_ON_PANIC
#ifdef CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC
/* Ensure host stage-2 is disabled */
mrs x0, hcr_el2
bic x0, x0, #HCR_VM

View File

@ -189,7 +189,7 @@ static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer,
if (cpu > last_cpu)
break;
__share_page(rb_desc->meta_va);
__unshare_page(rb_desc->meta_va);
for (p = 0; p < rb_desc->nr_page_va; p++)
__unshare_page(rb_desc->page_va[p]);
}
@ -212,14 +212,15 @@ static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
}
if (ret) {
for (p--; p >= 0; p--)
while (--p >= 0)
__unshare_page(rb_desc->page_va[p]);
__unshare_page(rb_desc->meta_va);
break;
}
}
if (ret)
hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--);
hyp_trace_buffer_unshare_hyp(trace_buffer, --cpu);
return ret;
}
@ -248,6 +249,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
goto err_free_desc;
trace_buffer->desc = desc;
trace_buffer->desc_size = desc_size;
ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size);
if (ret)
@ -297,6 +299,7 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
hyp_trace_buffer_free_bpages_backing(trace_buffer);
free_pages_exact(trace_buffer->desc, trace_buffer->desc_size);
trace_buffer->desc = NULL;
trace_buffer->desc_size = 0;
}
static int hyp_trace_enable_tracing(bool enable, void *priv)

View File

@ -1834,6 +1834,11 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
resx.res1 = VNCR_EL2_RES1;
set_sysreg_masks(kvm, VNCR_EL2, resx);
/* ZCR_EL2 - bits 8:4 are RAZ/WI so treat them as RES0 */
resx.res0 = ZCR_ELx_RES0 | GENMASK_ULL(8, 4);
resx.res1 = ZCR_ELx_RES1;
set_sysreg_masks(kvm, ZCR_EL2, resx);
out:
for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++)
__vcpu_rmw_sys_reg(vcpu, sr, |=, 0);

View File

@ -174,8 +174,8 @@ static void kvm_pmu_set_pmc_value(struct kvm_pmc *pmc, u64 val, bool force)
* action is to use PMCR.P, which will reset them to
* 0 (the only use of the 'force' parameter).
*/
val = __vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32);
val |= lower_32_bits(val);
val = (__vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32)) |
lower_32_bits(val);
}
__vcpu_assign_sys_reg(vcpu, reg, val);

View File

@ -2862,21 +2862,16 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
unsigned int vq;
if (guest_hyp_sve_traps_enabled(vcpu)) {
kvm_inject_nested_sve_trap(vcpu);
return false;
}
if (!p->is_write) {
if (!p->is_write)
p->regval = __vcpu_sys_reg(vcpu, ZCR_EL2);
return true;
}
else
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval);
vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
vq = min(vq, vcpu_sve_max_vq(vcpu));
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1);
return true;
}