ANDROID: KVM: arm64: Mark vcpu as invalid on unhandleable trap
Some trap types cannot be handled for protected VMs, and are not expected ever to occur. If they do, they are punted to Host with no associated context, which ends up trying to use a stale ESR. It is better to fail-stop the affected VCPU in this case, and emit a trace log entry. Bug: 357781595 Change-Id: Ida3dd68f67afe0bd7451a4d4b8b038fd96934b1c Signed-off-by: Keir Fraser <keirf@google.com>
This commit is contained in:
committed by
Treehugger Robot
parent
2846533583
commit
4e88458f66
@@ -324,6 +324,8 @@ extern u64 __kvm_get_mdcr_el2(void);
|
||||
__kvm_at_err; \
|
||||
} )
|
||||
|
||||
void vcpu_illegal_trap(struct kvm_vcpu *vcpu, u64 *exit_code);
|
||||
|
||||
void __noreturn hyp_panic(void);
|
||||
asmlinkage void kvm_unexpected_el2_exception(void);
|
||||
asmlinkage void __noreturn hyp_panic(void);
|
||||
|
||||
@@ -105,6 +105,17 @@ HYP_EVENT(psci_mem_protect,
|
||||
HE_PRINTK("count=%llu was=%llu", __entry->count, __entry->was)
|
||||
);
|
||||
|
||||
HYP_EVENT(vcpu_illegal_trap,
|
||||
HE_PROTO(u64 esr),
|
||||
HE_STRUCT(
|
||||
he_field(u64, esr)
|
||||
),
|
||||
HE_ASSIGN(
|
||||
__entry->esr = esr;
|
||||
),
|
||||
HE_PRINTK("esr_el2=%llx", __entry->esr)
|
||||
);
|
||||
|
||||
#ifdef CONFIG_PROTECTED_NVHE_TESTING
|
||||
HYP_EVENT(selftest,
|
||||
HE_PROTO(void),
|
||||
|
||||
@@ -853,7 +853,7 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
hyp_vcpu->exit_code = 0;
|
||||
}
|
||||
|
||||
static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
|
||||
static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
|
||||
{
|
||||
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
|
||||
hyp_entry_exit_handler_fn ec_handler;
|
||||
@@ -871,7 +871,7 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
|
||||
sync_hyp_vgic_state(hyp_vcpu);
|
||||
sync_hyp_timer_state(hyp_vcpu);
|
||||
|
||||
switch (ARM_EXCEPTION_CODE(exit_reason)) {
|
||||
switch (ARM_EXCEPTION_CODE(*exit_code)) {
|
||||
case ARM_EXCEPTION_IRQ:
|
||||
case ARM_EXCEPTION_HYP_REQ:
|
||||
break;
|
||||
@@ -883,8 +883,16 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
|
||||
else
|
||||
ec_handler = exit_hyp_vm_handlers[esr_ec];
|
||||
|
||||
if (ec_handler)
|
||||
if (ec_handler) {
|
||||
ec_handler(hyp_vcpu);
|
||||
} else {
|
||||
/*
|
||||
* If we have no handler we should not be punting this
|
||||
* trap to Host, as it will have no sync'ed context to
|
||||
* handle (for example: ESR_EL2).
|
||||
*/
|
||||
vcpu_illegal_trap(&hyp_vcpu->vcpu, exit_code);
|
||||
}
|
||||
break;
|
||||
case ARM_EXCEPTION_EL1_SERROR:
|
||||
case ARM_EXCEPTION_IL:
|
||||
@@ -898,7 +906,7 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
|
||||
else
|
||||
host_vcpu->arch.iflags = hyp_vcpu->vcpu.arch.iflags;
|
||||
|
||||
hyp_vcpu->exit_code = exit_reason;
|
||||
hyp_vcpu->exit_code = *exit_code;
|
||||
}
|
||||
|
||||
static void fpsimd_host_restore(void)
|
||||
@@ -1041,7 +1049,7 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu;
|
||||
struct kvm_vcpu *host_vcpu;
|
||||
int ret = ARM_EXCEPTION_IL;
|
||||
u64 ret = ARM_EXCEPTION_IL;
|
||||
|
||||
host_vcpu = get_host_hyp_vcpus(host_ctxt, 1, &hyp_vcpu);
|
||||
|
||||
@@ -1068,7 +1076,7 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
|
||||
|
||||
ret = __kvm_vcpu_run(&hyp_vcpu->vcpu);
|
||||
|
||||
sync_hyp_vcpu(hyp_vcpu, ret);
|
||||
sync_hyp_vcpu(hyp_vcpu, &ret);
|
||||
|
||||
/* Trap host fpsimd/sve if the guest has used fpsimd/sve. */
|
||||
if (guest_owns_fp_regs())
|
||||
|
||||
@@ -345,6 +345,21 @@ static const exit_handler_fn *kvm_get_exit_handler_array(struct kvm_vcpu *vcpu)
|
||||
return hyp_exit_handlers;
|
||||
}
|
||||
|
||||
/*
|
||||
* As we have caught the guest red-handed, decide that it isn't fit for
|
||||
* purpose anymore by making the vcpu invalid. The VMM can try and fix it by
|
||||
* re-initializing the vcpu with KVM_ARM_VCPU_INIT, however, this is likely
|
||||
* not possible for protected VMs.
|
||||
*/
|
||||
void vcpu_illegal_trap(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
{
|
||||
trace_vcpu_illegal_trap(kvm_vcpu_get_esr(vcpu));
|
||||
|
||||
vcpu_clear_flag(vcpu, VCPU_INITIALIZED);
|
||||
*exit_code &= BIT(ARM_EXIT_WITH_SERROR_BIT);
|
||||
*exit_code |= ARM_EXCEPTION_IL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some guests (e.g., protected VMs) are not be allowed to run in AArch32.
|
||||
* The ARMv8 architecture does not give the hypervisor a mechanism to prevent a
|
||||
@@ -352,24 +367,11 @@ static const exit_handler_fn *kvm_get_exit_handler_array(struct kvm_vcpu *vcpu)
|
||||
* hypervisor spots a guest in such a state ensure it is handled, and don't
|
||||
* trust the host to spot or fix it. The check below is based on the one in
|
||||
* kvm_arch_vcpu_ioctl_run().
|
||||
*
|
||||
* Returns false if the guest ran in AArch32 when it shouldn't have, and
|
||||
* thus should exit to the host, or true if a the guest run loop can continue.
|
||||
*/
|
||||
static void early_exit_filter(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
{
|
||||
if (unlikely(vcpu_is_protected(vcpu) && vcpu_mode_is_32bit(vcpu))) {
|
||||
/*
|
||||
* As we have caught the guest red-handed, decide that it isn't
|
||||
* fit for purpose anymore by making the vcpu invalid. The VMM
|
||||
* can try and fix it by re-initializing the vcpu with
|
||||
* KVM_ARM_VCPU_INIT, however, this is likely not possible for
|
||||
* protected VMs.
|
||||
*/
|
||||
vcpu_clear_flag(vcpu, VCPU_INITIALIZED);
|
||||
*exit_code &= BIT(ARM_EXIT_WITH_SERROR_BIT);
|
||||
*exit_code |= ARM_EXCEPTION_IL;
|
||||
}
|
||||
if (unlikely(vcpu_is_protected(vcpu) && vcpu_mode_is_32bit(vcpu)))
|
||||
vcpu_illegal_trap(vcpu, exit_code);
|
||||
}
|
||||
|
||||
/* Switch to the guest for legacy non-VHE systems */
|
||||
|
||||
Reference in New Issue
Block a user