arm64: KVM: Plug the arch timer
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 7 Dec 2012 17:52:03 +0000 (17:52 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Wed, 12 Jun 2013 15:40:32 +0000 (16:40 +0100)
Add support for the in-kernel timer emulation.

Reviewed-by: Christopher Covington <cov@codeaurora.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/kvm/hyp.S
arch/arm64/kvm/reset.c

index 8dc27a3..8b51083 100644 (file)
@@ -390,6 +390,60 @@ __kvm_hyp_code_start:
 2:
 .endm
 
+.macro save_timer_state
+       // x0: vcpu pointer
+       ldr     x2, [x0, #VCPU_KVM]
+       kern_hyp_va x2
+       ldr     w3, [x2, #KVM_TIMER_ENABLED]
+       cbz     w3, 1f
+
+       mrs     x3, cntv_ctl_el0
+       and     x3, x3, #3
+       str     w3, [x0, #VCPU_TIMER_CNTV_CTL]
+       bic     x3, x3, #1              // Clear Enable
+       msr     cntv_ctl_el0, x3
+
+       isb
+
+       mrs     x3, cntv_cval_el0
+       str     x3, [x0, #VCPU_TIMER_CNTV_CVAL]
+
+1:
+       // Allow physical timer/counter access for the host
+       mrs     x2, cnthctl_el2
+       orr     x2, x2, #3
+       msr     cnthctl_el2, x2
+
+       // Clear cntvoff for the host
+       msr     cntvoff_el2, xzr
+.endm
+
+.macro restore_timer_state
+       // x0: vcpu pointer
+       // Disallow physical timer access for the guest
+       // Physical counter access is allowed
+       mrs     x2, cnthctl_el2
+       orr     x2, x2, #1
+       bic     x2, x2, #2
+       msr     cnthctl_el2, x2
+
+       ldr     x2, [x0, #VCPU_KVM]
+       kern_hyp_va x2
+       ldr     w3, [x2, #KVM_TIMER_ENABLED]
+       cbz     w3, 1f
+
+       ldr     x3, [x2, #KVM_TIMER_CNTVOFF]
+       msr     cntvoff_el2, x3
+       ldr     x2, [x0, #VCPU_TIMER_CNTV_CVAL]
+       msr     cntv_cval_el0, x2
+       isb
+
+       ldr     w2, [x0, #VCPU_TIMER_CNTV_CTL]
+       and     x2, x2, #3
+       msr     cntv_ctl_el0, x2
+1:
+.endm
+
 __save_sysregs:
        save_sysregs
        ret
@@ -433,6 +487,7 @@ ENTRY(__kvm_vcpu_run)
        activate_vm
 
        restore_vgic_state
+       restore_timer_state
 
        // Guest context
        add     x2, x0, #VCPU_CONTEXT
@@ -455,6 +510,7 @@ __kvm_vcpu_return:
        bl __save_fpsimd
        bl __save_sysregs
 
+       save_timer_state
        save_vgic_state
 
        deactivate_traps
index f6536a0..766150a 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 
+#include <kvm/arm_arch_timer.h>
+
 #include <asm/cputype.h>
 #include <asm/ptrace.h>
 #include <asm/kvm_arm.h>
@@ -36,6 +38,11 @@ static const struct kvm_regs default_regs_reset = {
                        PSR_F_BIT | PSR_D_BIT),
 };
 
+static const struct kvm_irq_level default_vtimer_irq = {
+       .irq    = 27,
+       .level  = 1,
+};
+
 int kvm_arch_dev_ioctl_check_extension(long ext)
 {
        int r;
@@ -58,11 +65,13 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
  */
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
+       const struct kvm_irq_level *cpu_vtimer_irq;
        const struct kvm_regs *cpu_reset;
 
        switch (vcpu->arch.target) {
        default:
                cpu_reset = &default_regs_reset;
+               cpu_vtimer_irq = &default_vtimer_irq;
                break;
        }
 
@@ -72,5 +81,8 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        /* Reset system registers */
        kvm_reset_sys_regs(vcpu);
 
+       /* Reset timer */
+       kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+
        return 0;
 }