summaryrefslogtreecommitdiff
path: root/arch/mips/kvm/mips.c
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2017-03-14 13:15:39 +0300
committerJames Hogan <james.hogan@imgtec.com>2017-03-28 16:53:59 +0300
commitf4474d50c7d483dd4432d5b0891b0bb9ad0eefc9 (patch)
tree0ae9b270aac75d2c7d3504cacf9c136fa9725096 /arch/mips/kvm/mips.c
parentd42a008f86ba3d715d31788fc5143a4de5685d33 (diff)
downloadlinux-f4474d50c7d483dd4432d5b0891b0bb9ad0eefc9.tar.xz
KVM: MIPS/VZ: Support hardware guest timer
Transfer timer state to the VZ guest context (CP0_GTOffset & guest CP0_Count) when entering guest mode, enabling direct guest access to it, and transfer back to soft timer when saving guest register state. This usually allows guest code to directly read CP0_Count (via MFC0 and RDHWR) and read/write CP0_Compare, without trapping to the hypervisor for it to emulate the guest timer. Writing to CP0_Count or CP0_Cause.DC is much less common and still triggers a hypervisor GPSI exception, in which case the timer state is transferred back to an hrtimer before emulating the write. We are careful to prevent small amounts of drift from building up due to undeterministic time intervals between reading of the ktime and reading of CP0_Count. Some drift is expected however, since the system clocksource may use a different timer to the local CP0_Count timer used by VZ. This is permitted to prevent guest CP0_Count from appearing to go backwards. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář" <rkrcmar@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org
Diffstat (limited to 'arch/mips/kvm/mips.c')
-rw-r--r--arch/mips/kvm/mips.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index 1bb5d01d5dec..e8ddb128b8ad 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -1094,7 +1094,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
- return kvm_mips_pending_timer(vcpu);
+ return kvm_mips_pending_timer(vcpu) ||
+ kvm_read_c0_guest_cause(vcpu->arch.cop0) & C_TI;
}
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
@@ -1382,6 +1383,9 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
skip_emul:
local_irq_disable();
+ if (ret == RESUME_GUEST)
+ kvm_vz_acquire_htimer(vcpu);
+
if (er == EMULATE_DONE && !(ret & RESUME_HOST))
kvm_mips_deliver_interrupts(vcpu, cause);