mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
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 Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
committed by
Quentin Perret
parent
df7acc62d4
commit
2413304588
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user