mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
KVM: arm64: nv: Handle ERETA[AB] instructions
Now that we have some emulation in place for ERETA[AB], we can plug it into the exception handling machinery. As for a bare ERET, an "easy" ERETAx instruction is processed as a fixup, while something that requires a translation regime transition or an exception delivery is left to the slow path. Reviewed-by: Joey Gouly <joey.gouly@arm.com> Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Link: https://lore.kernel.org/r/20240419102935.1935571-14-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
6ccc971ee2
commit
213b3d1ea1
@ -2172,7 +2172,7 @@ static u64 kvm_check_illegal_exception_return(struct kvm_vcpu *vcpu, u64 spsr)
|
||||
|
||||
void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 spsr, elr;
|
||||
u64 spsr, elr, esr;
|
||||
|
||||
/*
|
||||
* Forward this trap to the virtual EL2 if the virtual
|
||||
@ -2181,12 +2181,30 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)
|
||||
if (forward_traps(vcpu, HCR_NV))
|
||||
return;
|
||||
|
||||
/* Check for an ERETAx */
|
||||
esr = kvm_vcpu_get_esr(vcpu);
|
||||
if (esr_iss_is_eretax(esr) && !kvm_auth_eretax(vcpu, &elr)) {
|
||||
/*
|
||||
* Oh no, ERETAx failed to authenticate. If we have
|
||||
* FPACCOMBINE, deliver an exception right away. If we
|
||||
* don't, then let the mangled ELR value trickle down the
|
||||
* ERET handling, and the guest will have a little surprise.
|
||||
*/
|
||||
if (kvm_has_pauth(vcpu->kvm, FPACCOMBINE)) {
|
||||
esr &= ESR_ELx_ERET_ISS_ERETA;
|
||||
esr |= FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_FPAC);
|
||||
kvm_inject_nested_sync(vcpu, esr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
kvm_arch_vcpu_put(vcpu);
|
||||
|
||||
spsr = __vcpu_sys_reg(vcpu, SPSR_EL2);
|
||||
spsr = kvm_check_illegal_exception_return(vcpu, spsr);
|
||||
elr = __vcpu_sys_reg(vcpu, ELR_EL2);
|
||||
if (!esr_iss_is_eretax(esr))
|
||||
elr = __vcpu_sys_reg(vcpu, ELR_EL2);
|
||||
|
||||
trace_kvm_nested_eret(vcpu, elr, spsr);
|
||||
|
||||
|
@ -248,7 +248,8 @@ static int kvm_handle_ptrauth(struct kvm_vcpu *vcpu)
|
||||
|
||||
static int kvm_handle_eret(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (esr_iss_is_eretax(kvm_vcpu_get_esr(vcpu)))
|
||||
if (esr_iss_is_eretax(kvm_vcpu_get_esr(vcpu)) &&
|
||||
!vcpu_has_ptrauth(vcpu))
|
||||
return kvm_handle_ptrauth(vcpu);
|
||||
|
||||
/*
|
||||
|
@ -208,7 +208,8 @@ void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
|
||||
|
||||
static bool kvm_hyp_handle_eret(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
{
|
||||
u64 spsr, mode;
|
||||
u64 esr = kvm_vcpu_get_esr(vcpu);
|
||||
u64 spsr, elr, mode;
|
||||
|
||||
/*
|
||||
* Going through the whole put/load motions is a waste of time
|
||||
@ -242,10 +243,18 @@ static bool kvm_hyp_handle_eret(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If ERETAx fails, take the slow path */
|
||||
if (esr_iss_is_eretax(esr)) {
|
||||
if (!(vcpu_has_ptrauth(vcpu) && kvm_auth_eretax(vcpu, &elr)))
|
||||
return false;
|
||||
} else {
|
||||
elr = read_sysreg_el1(SYS_ELR);
|
||||
}
|
||||
|
||||
spsr = (spsr & ~(PSR_MODE_MASK | PSR_MODE32_BIT)) | mode;
|
||||
|
||||
write_sysreg_el2(spsr, SYS_SPSR);
|
||||
write_sysreg_el2(read_sysreg_el1(SYS_ELR), SYS_ELR);
|
||||
write_sysreg_el2(elr, SYS_ELR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user