Skip to content

Commit

Permalink
Merge branch kvm-arm64/nv-resx-fixes-6.14 into kvmarm-master/next
Browse files Browse the repository at this point in the history
* kvm-arm64/nv-resx-fixes-6.14:
  : .
  : Fixes for NV sysreg accessors. From the cover letter:
  :
  : "Joey recently reported that some rather basic tests were failing on
  : NV, and managed to track it down to critical register fields (such as
  : HCR_EL2.E2H) not having their expect value.
  :
  : Further investigation has outlined a couple of critical issues:
  :
  : - Evaluating HCR_EL2.E2H must always be done with a sanitising
  :   accessor, no ifs, no buts. Given that KVM assumes a fixed value for
  :   this bit, we cannot leave it to the guest to mess with.
  :
  : - Resetting the sysreg file must result in the RESx bits taking
  :   effect. Otherwise, we may end-up making the wrong decision (see
  :   above), and we definitely expose invalid values to the guest. Note
  :   that because we compute the RESx masks very late in the VM setup, we
  :   need to apply these masks at that particular point as well.
  : [...]"
  : .
  KVM: arm64: nv: Apply RESx settings to sysreg reset values
  KVM: arm64: nv: Always evaluate HCR_EL2 using sanitising accessors

Signed-off-by: Marc Zyngier <maz@kernel.org>

# Conflicts:
#	arch/arm64/kvm/nested.c
  • Loading branch information
Marc Zyngier committed Jan 17, 2025
2 parents 946904e + 36f998d commit 3643b33
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 27 deletions.
36 changes: 15 additions & 21 deletions arch/arm64/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,29 +184,30 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)
return vcpu_is_el2_ctxt(&vcpu->arch.ctxt);
}

static inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt)
static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
{
return (!cpus_have_final_cap(ARM64_HAS_HCR_NV1) ||
(ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H));
(__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_E2H));
}

static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
{
return __vcpu_el2_e2h_is_set(&vcpu->arch.ctxt);
return ctxt_sys_reg(&vcpu->arch.ctxt, HCR_EL2) & HCR_TGE;
}

static inline bool __vcpu_el2_tge_is_set(const struct kvm_cpu_context *ctxt)
static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
{
return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_TGE;
}
bool e2h, tge;
u64 hcr;

static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
{
return __vcpu_el2_tge_is_set(&vcpu->arch.ctxt);
}
if (!vcpu_has_nv(vcpu))
return false;

hcr = __vcpu_sys_reg(vcpu, HCR_EL2);

e2h = (hcr & HCR_E2H);
tge = (hcr & HCR_TGE);

static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
{
/*
* We are in a hypervisor context if the vcpu mode is EL2 or
* E2H and TGE bits are set. The latter means we are in the user space
Expand All @@ -215,14 +216,7 @@ static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
* Note that the HCR_EL2.{E2H,TGE}={0,1} isn't really handled in the
* rest of the KVM code, and will result in a misbehaving guest.
*/
return vcpu_is_el2_ctxt(ctxt) ||
(__vcpu_el2_e2h_is_set(ctxt) && __vcpu_el2_tge_is_set(ctxt)) ||
__vcpu_el2_tge_is_set(ctxt);
}

static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
{
return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
return vcpu_is_el2(vcpu) || (e2h && tge) || tge;
}

static inline bool vcpu_is_host_el0(const struct kvm_vcpu *vcpu)
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/kvm_nested.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ static inline bool kvm_supported_tlbi_s1e2_op(struct kvm_vcpu *vpcu, u32 instr)
return true;
}

int kvm_init_nv_sysregs(struct kvm *kvm);
int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu);

#ifdef CONFIG_ARM64_PTR_AUTH
bool kvm_auth_eretax(struct kvm_vcpu *vcpu, u64 *elr);
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kvm/hyp/vhe/sysreg-sr.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
__sysreg32_restore_state(vcpu);
__sysreg_restore_user_state(guest_ctxt);

if (unlikely(__is_hyp_ctxt(guest_ctxt))) {
if (unlikely(is_hyp_ctxt(vcpu))) {
__sysreg_restore_vel2_state(vcpu);
} else {
if (vcpu_has_nv(vcpu)) {
Expand Down Expand Up @@ -260,7 +260,7 @@ void __vcpu_put_switch_sysregs(struct kvm_vcpu *vcpu)

host_ctxt = host_data_ptr(host_ctxt);

if (unlikely(__is_hyp_ctxt(guest_ctxt)))
if (unlikely(is_hyp_ctxt(vcpu)))
__sysreg_save_vel2_state(vcpu);
else
__sysreg_save_el1_state(guest_ctxt);
Expand Down
9 changes: 7 additions & 2 deletions arch/arm64/kvm/nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,14 +963,15 @@ static __always_inline void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0,
kvm->arch.sysreg_masks->mask[i].res1 = res1;
}

int kvm_init_nv_sysregs(struct kvm *kvm)
int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
u64 res0, res1;

lockdep_assert_held(&kvm->arch.config_lock);

if (kvm->arch.sysreg_masks)
return 0;
goto out;

kvm->arch.sysreg_masks = kzalloc(sizeof(*(kvm->arch.sysreg_masks)),
GFP_KERNEL_ACCOUNT);
Expand Down Expand Up @@ -1286,6 +1287,10 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
res0 |= GENMASK(11, 8);
set_sysreg_masks(kvm, CNTHCTL_EL2, res0, res1);

out:
for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++)
(void)__vcpu_sys_reg(vcpu, sr);

return 0;
}

Expand Down
5 changes: 4 additions & 1 deletion arch/arm64/kvm/sys_regs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4450,6 +4450,9 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
reset_vcpu_ftr_id_reg(vcpu, r);
else
r->reset(vcpu, r);

if (r->reg >= __SANITISED_REG_START__ && r->reg < NR_SYS_REGS)
(void)__vcpu_sys_reg(vcpu, r->reg);
}

set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
Expand Down Expand Up @@ -5053,7 +5056,7 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
}

if (vcpu_has_nv(vcpu)) {
int ret = kvm_init_nv_sysregs(kvm);
int ret = kvm_init_nv_sysregs(vcpu);
if (ret)
return ret;
}
Expand Down

0 comments on commit 3643b33

Please sign in to comment.