ANDROID: KVM: arm64: Introduce per-EC entry/exit handlers

Introduce per-EC entry/exit handlers at EL2 and provide initial
implementations to manage the 'flags' and fault information registers.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Will Deacon <willdeacon@google.com>
Bug: 233587962
Change-Id: I402a48c77602da969fc04c393d0624d3b2f837df
This commit is contained in:
Marc Zyngier
2022-06-11 11:49:37 +01:00
committed by Will Deacon
parent 328c1d4e6e
commit 2edbb246c2
2 changed files with 82 additions and 6 deletions

View File

@@ -26,6 +26,9 @@ struct pkvm_hyp_vcpu {
* per-cpu pointer tracking us. Otherwise, NULL if not loaded.
*/
struct pkvm_hyp_vcpu **loaded_hyp_vcpu;
/* Tracks exit code for the protected guest. */
u32 exit_code;
};
/*

View File

@@ -24,6 +24,43 @@ DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
typedef void (*hyp_entry_exit_handler_fn)(struct pkvm_hyp_vcpu *);
static void handle_vm_entry_generic(struct pkvm_hyp_vcpu *hyp_vcpu)
{
vcpu_copy_flag(&hyp_vcpu->vcpu, hyp_vcpu->host_vcpu, PC_UPDATE_REQ);
}
static void handle_vm_exit_generic(struct pkvm_hyp_vcpu *hyp_vcpu)
{
WRITE_ONCE(hyp_vcpu->host_vcpu->arch.fault.esr_el2,
hyp_vcpu->vcpu.arch.fault.esr_el2);
}
static void handle_vm_exit_abt(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
WRITE_ONCE(host_vcpu->arch.fault.esr_el2,
hyp_vcpu->vcpu.arch.fault.esr_el2);
WRITE_ONCE(host_vcpu->arch.fault.far_el2,
hyp_vcpu->vcpu.arch.fault.far_el2);
WRITE_ONCE(host_vcpu->arch.fault.hpfar_el2,
hyp_vcpu->vcpu.arch.fault.hpfar_el2);
WRITE_ONCE(host_vcpu->arch.fault.disr_el1,
hyp_vcpu->vcpu.arch.fault.disr_el1);
}
static const hyp_entry_exit_handler_fn entry_hyp_vm_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = handle_vm_entry_generic,
};
static const hyp_entry_exit_handler_fn exit_hyp_vm_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = handle_vm_exit_generic,
[ESR_ELx_EC_IABT_LOW] = handle_vm_exit_abt,
[ESR_ELx_EC_DABT_LOW] = handle_vm_exit_abt,
};
static void flush_hyp_vgic_state(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
@@ -98,6 +135,8 @@ static void sync_hyp_timer_state(struct pkvm_hyp_vcpu *hyp_vcpu)
static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
hyp_entry_exit_handler_fn ec_handler;
u8 esr_ec;
hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
@@ -108,7 +147,6 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2;
hyp_vcpu->vcpu.arch.cptr_el2 = host_vcpu->arch.cptr_el2;
hyp_vcpu->vcpu.arch.iflags = host_vcpu->arch.iflags;
hyp_vcpu->vcpu.arch.fp_state = host_vcpu->arch.fp_state;
hyp_vcpu->vcpu.arch.debug_ptr = kern_hyp_va(host_vcpu->arch.debug_ptr);
@@ -118,24 +156,59 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
flush_hyp_vgic_state(hyp_vcpu);
flush_hyp_timer_state(hyp_vcpu);
switch (ARM_EXCEPTION_CODE(hyp_vcpu->exit_code)) {
case ARM_EXCEPTION_IRQ:
case ARM_EXCEPTION_EL1_SERROR:
case ARM_EXCEPTION_IL:
break;
case ARM_EXCEPTION_TRAP:
esr_ec = ESR_ELx_EC(kvm_vcpu_get_esr(&hyp_vcpu->vcpu));
ec_handler = entry_hyp_vm_handlers[esr_ec];
if (ec_handler)
ec_handler(hyp_vcpu);
break;
default:
BUG();
}
hyp_vcpu->exit_code = 0;
}
static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
{
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
hyp_entry_exit_handler_fn ec_handler;
u8 esr_ec;
host_vcpu->arch.ctxt = hyp_vcpu->vcpu.arch.ctxt;
host_vcpu->arch.hcr_el2 = hyp_vcpu->vcpu.arch.hcr_el2;
host_vcpu->arch.cptr_el2 = hyp_vcpu->vcpu.arch.cptr_el2;
host_vcpu->arch.fault = hyp_vcpu->vcpu.arch.fault;
host_vcpu->arch.iflags = hyp_vcpu->vcpu.arch.iflags;
host_vcpu->arch.fp_state = hyp_vcpu->vcpu.arch.fp_state;
sync_hyp_vgic_state(hyp_vcpu);
sync_hyp_timer_state(hyp_vcpu);
switch (ARM_EXCEPTION_CODE(exit_reason)) {
case ARM_EXCEPTION_IRQ:
break;
case ARM_EXCEPTION_TRAP:
esr_ec = ESR_ELx_EC(kvm_vcpu_get_esr(&hyp_vcpu->vcpu));
ec_handler = exit_hyp_vm_handlers[esr_ec];
if (ec_handler)
ec_handler(hyp_vcpu);
break;
case ARM_EXCEPTION_EL1_SERROR:
case ARM_EXCEPTION_IL:
break;
default:
BUG();
}
vcpu_clear_flag(host_vcpu, PC_UPDATE_REQ);
hyp_vcpu->exit_code = exit_reason;
}
static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
@@ -226,7 +299,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);
sync_hyp_vcpu(hyp_vcpu, ret);
} else {
/* The host is fully trusted, run its vCPU directly. */
ret = __kvm_vcpu_run(host_vcpu);