KVM: arm/arm64: Support EL1 phys timer register access in set/get reg
authorChristoffer Dall <cdall@linaro.org>
Sat, 17 Jun 2017 06:08:57 +0000 (23:08 -0700)
committerChristoffer Dall <christoffer.dall@linaro.org>
Mon, 6 Nov 2017 15:23:14 +0000 (16:23 +0100)
Add suport for the physical timer registers in kvm_arm_timer_set_reg and
kvm_arm_timer_get_reg so that these functions can be reused to interact
with the rest of the system.

Note that this paves part of the way for the physical timer state
save/restore, but we still need to add those registers to
KVM_GET_REG_LIST before we support migrating the physical timer state.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <cdall@linaro.org>
arch/arm/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/kvm.h
virt/kvm/arm/arch_timer.c

index 5db2d4c..665c454 100644 (file)
@@ -151,6 +151,12 @@ struct kvm_arch_memory_slot {
        (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
 #define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
 
+/* PL1 Physical Timer Registers */
+#define KVM_REG_ARM_PTIMER_CTL         ARM_CP15_REG32(0, 14, 2, 1)
+#define KVM_REG_ARM_PTIMER_CNT         ARM_CP15_REG64(0, 14)
+#define KVM_REG_ARM_PTIMER_CVAL                ARM_CP15_REG64(2, 14)
+
+/* Virtual Timer Registers */
 #define KVM_REG_ARM_TIMER_CTL          ARM_CP15_REG32(0, 14, 3, 1)
 #define KVM_REG_ARM_TIMER_CNT          ARM_CP15_REG64(1, 14)
 #define KVM_REG_ARM_TIMER_CVAL         ARM_CP15_REG64(3, 14)
index 9f3ca24..0004fee 100644 (file)
@@ -195,6 +195,12 @@ struct kvm_arch_memory_slot {
 
 #define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64)
 
+/* Physical Timer EL0 Registers */
+#define KVM_REG_ARM_PTIMER_CTL         ARM64_SYS_REG(3, 3, 14, 2, 1)
+#define KVM_REG_ARM_PTIMER_CVAL                ARM64_SYS_REG(3, 3, 14, 2, 2)
+#define KVM_REG_ARM_PTIMER_CNT         ARM64_SYS_REG(3, 3, 14, 0, 1)
+
+/* EL0 Virtual Timer Registers */
 #define KVM_REG_ARM_TIMER_CTL          ARM64_SYS_REG(3, 3, 14, 3, 1)
 #define KVM_REG_ARM_TIMER_CNT          ARM64_SYS_REG(3, 3, 14, 3, 2)
 #define KVM_REG_ARM_TIMER_CVAL         ARM64_SYS_REG(3, 3, 14, 0, 2)
index ec685c1..d1a6fb1 100644 (file)
@@ -628,10 +628,11 @@ static void kvm_timer_init_interrupt(void *info)
 int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 {
        struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+       struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
        switch (regid) {
        case KVM_REG_ARM_TIMER_CTL:
-               vtimer->cnt_ctl = value;
+               vtimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
                break;
        case KVM_REG_ARM_TIMER_CNT:
                update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value);
@@ -639,6 +640,13 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
        case KVM_REG_ARM_TIMER_CVAL:
                vtimer->cnt_cval = value;
                break;
+       case KVM_REG_ARM_PTIMER_CTL:
+               ptimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
+               break;
+       case KVM_REG_ARM_PTIMER_CVAL:
+               ptimer->cnt_cval = value;
+               break;
+
        default:
                return -1;
        }
@@ -647,17 +655,38 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
        return 0;
 }
 
+static u64 read_timer_ctl(struct arch_timer_context *timer)
+{
+       /*
+        * Set ISTATUS bit if it's expired.
+        * Note that according to ARMv8 ARM Issue A.k, ISTATUS bit is
+        * UNKNOWN when ENABLE bit is 0, so we chose to set ISTATUS bit
+        * regardless of ENABLE bit for our implementation convenience.
+        */
+       if (!kvm_timer_compute_delta(timer))
+               return timer->cnt_ctl | ARCH_TIMER_CTRL_IT_STAT;
+       else
+               return timer->cnt_ctl;
+}
+
 u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
 {
+       struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
        struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
        switch (regid) {
        case KVM_REG_ARM_TIMER_CTL:
-               return vtimer->cnt_ctl;
+               return read_timer_ctl(vtimer);
        case KVM_REG_ARM_TIMER_CNT:
                return kvm_phys_timer_read() - vtimer->cntvoff;
        case KVM_REG_ARM_TIMER_CVAL:
                return vtimer->cnt_cval;
+       case KVM_REG_ARM_PTIMER_CTL:
+               return read_timer_ctl(ptimer);
+       case KVM_REG_ARM_PTIMER_CVAL:
+               return ptimer->cnt_cval;
+       case KVM_REG_ARM_PTIMER_CNT:
+               return kvm_phys_timer_read();
        }
        return (u64)-1;
 }