mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
ANDROID: KVM: arm64: Save/restore virtual timer state from the shadow vcpu
Similar to the vgic state, make sure to sync and flush the virtual timer state between the host and the hyp shadow vCPU structs when running in nVHE protected mode. Signed-off-by: Marc Zyngier <maz@kernel.org> Bug: 209580772 Change-Id: Ib90273bb670d9d815dd9f542369dde00753655cf Signed-off-by: Will Deacon <willdeacon@google.com>
This commit is contained in:
committed by
Will Deacon
parent
3784299dce
commit
be1849348b
@@ -88,7 +88,9 @@ static u64 timer_get_offset(struct arch_timer_context *ctxt)
|
||||
|
||||
switch(arch_timer_ctx_index(ctxt)) {
|
||||
case TIMER_VTIMER:
|
||||
return __vcpu_sys_reg(vcpu, CNTVOFF_EL2);
|
||||
if (likely(!kvm_vm_is_protected(vcpu->kvm)))
|
||||
return __vcpu_sys_reg(vcpu, CNTVOFF_EL2);
|
||||
fallthrough;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -754,6 +756,9 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_vcpu *tmp;
|
||||
|
||||
if (unlikely(kvm_vm_is_protected(vcpu->kvm)))
|
||||
cntvoff = 0;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
kvm_for_each_vcpu(i, tmp, kvm)
|
||||
timer_set_offset(vcpu_vtimer(tmp), cntvoff);
|
||||
|
||||
@@ -253,6 +253,28 @@ static void sync_vgic_state(struct kvm_vcpu *host_vcpu,
|
||||
host_cpu_if->vgic_lr[i] = shadow_cpu_if->vgic_lr[i];
|
||||
}
|
||||
|
||||
static void flush_timer_state(struct kvm_vcpu *shadow_vcpu)
|
||||
{
|
||||
/*
|
||||
* A shadow vcpu has no offset, and sees vtime == ptime. The
|
||||
* ptimer is fully emulated by EL1 and cannot be trusted.
|
||||
*/
|
||||
write_sysreg(0, cntvoff_el2);
|
||||
isb();
|
||||
write_sysreg_el0(__vcpu_sys_reg(shadow_vcpu, CNTV_CVAL_EL0), SYS_CNTV_CVAL);
|
||||
write_sysreg_el0(__vcpu_sys_reg(shadow_vcpu, CNTV_CTL_EL0), SYS_CNTV_CTL);
|
||||
}
|
||||
|
||||
static void sync_timer_state(struct kvm_vcpu *shadow_vcpu)
|
||||
{
|
||||
/*
|
||||
* Preserve the vtimer state so that it is always correct,
|
||||
* even if the host tries to make a mess.
|
||||
*/
|
||||
__vcpu_sys_reg(shadow_vcpu, CNTV_CVAL_EL0) = read_sysreg_el0(SYS_CNTV_CVAL);
|
||||
__vcpu_sys_reg(shadow_vcpu, CNTV_CTL_EL0) = read_sysreg_el0(SYS_CNTV_CTL);
|
||||
}
|
||||
|
||||
static bool handle_shadow_entry(struct kvm_vcpu *shadow_vcpu)
|
||||
{
|
||||
struct kvm_vcpu *host_vcpu = shadow_vcpu->arch.pkvm.host_vcpu;
|
||||
@@ -260,6 +282,7 @@ static bool handle_shadow_entry(struct kvm_vcpu *shadow_vcpu)
|
||||
shadow_entry_exit_handler_fn ec_handler;
|
||||
|
||||
flush_vgic_state(host_vcpu, shadow_vcpu);
|
||||
flush_timer_state(shadow_vcpu);
|
||||
|
||||
switch (ARM_EXCEPTION_CODE(shadow_vcpu->arch.pkvm.exit_code)) {
|
||||
case ARM_EXCEPTION_IRQ:
|
||||
@@ -286,6 +309,7 @@ static void handle_shadow_exit(struct kvm_vcpu *shadow_vcpu)
|
||||
shadow_entry_exit_handler_fn ec_handler;
|
||||
|
||||
sync_vgic_state(host_vcpu, shadow_vcpu);
|
||||
sync_timer_state(shadow_vcpu);
|
||||
|
||||
switch (shadow_vcpu->arch.pkvm.exit_code) {
|
||||
case ARM_EXCEPTION_IRQ:
|
||||
|
||||
Reference in New Issue
Block a user