summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2012-12-07 17:52:03 +0000
committerMarc Zyngier <marc.zyngier@arm.com>2013-06-12 16:40:32 +0100
commit003300de6c3e51934fb52eb2677f6f4fb4996cbd (patch)
tree1d214ebdd5cdcc9f86a0a44c6670a55c4da7f53f
parentf61701e0a24a09aa4a44baf24e57dcc5e706afa8 (diff)
downloadlinux-003300de6c3e51934fb52eb2677f6f4fb4996cbd.tar.bz2
arm64: KVM: Plug the arch timer
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>
-rw-r--r--arch/arm64/kvm/hyp.S56
-rw-r--r--arch/arm64/kvm/reset.c12
2 files changed, 68 insertions, 0 deletions
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 8dc27a367d77..8b510835b440 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -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
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f6536a06231a..766150ac76ed 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -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;
}