Commit 39735a3a390431bcf60f9174b7d64f787fd6afa9

Authored by Andre Przywara
Committed by Christoffer Dall
1 parent a1a64387ad

ARM/KVM: save and restore generic timer registers

For migration to work we need to save (and later restore) the state of
each core's virtual generic timer.
Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
the three needed registers (control, counter, compare value).
Though they live in cp15 space, we don't use the existing list, since
they need special accessor functions and the arch timer is optional.

Acked-by: Marc Zynger <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Showing 5 changed files with 166 additions and 1 deletions Side-by-side Diff

arch/arm/include/asm/kvm_host.h
... ... @@ -225,5 +225,8 @@
225 225 int kvm_perf_init(void);
226 226 int kvm_perf_teardown(void);
227 227  
  228 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
  229 +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
  230 +
228 231 #endif /* __ARM_KVM_HOST_H__ */
arch/arm/include/uapi/asm/kvm.h
... ... @@ -119,6 +119,26 @@
119 119 #define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
120 120 #define KVM_REG_ARM_32_CRN_SHIFT 11
121 121  
  122 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \
  123 + (((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK)
  124 +
  125 +#define __ARM_CP15_REG(op1,crn,crm,op2) \
  126 + (KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \
  127 + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
  128 + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
  129 + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
  130 + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
  131 +
  132 +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
  133 +
  134 +#define __ARM_CP15_REG64(op1,crm) \
  135 + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
  136 +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
  137 +
  138 +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1)
  139 +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14)
  140 +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
  141 +
122 142 /* Normal registers are mapped as coprocessor 16. */
123 143 #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
124 144 #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
arch/arm/kvm/guest.c
... ... @@ -109,6 +109,83 @@
109 109 return -EINVAL;
110 110 }
111 111  
  112 +#ifndef CONFIG_KVM_ARM_TIMER
  113 +
  114 +#define NUM_TIMER_REGS 0
  115 +
  116 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
  117 +{
  118 + return 0;
  119 +}
  120 +
  121 +static bool is_timer_reg(u64 index)
  122 +{
  123 + return false;
  124 +}
  125 +
  126 +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
  127 +{
  128 + return 0;
  129 +}
  130 +
  131 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
  132 +{
  133 + return 0;
  134 +}
  135 +
  136 +#else
  137 +
  138 +#define NUM_TIMER_REGS 3
  139 +
  140 +static bool is_timer_reg(u64 index)
  141 +{
  142 + switch (index) {
  143 + case KVM_REG_ARM_TIMER_CTL:
  144 + case KVM_REG_ARM_TIMER_CNT:
  145 + case KVM_REG_ARM_TIMER_CVAL:
  146 + return true;
  147 + }
  148 + return false;
  149 +}
  150 +
  151 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
  152 +{
  153 + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
  154 + return -EFAULT;
  155 + uindices++;
  156 + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
  157 + return -EFAULT;
  158 + uindices++;
  159 + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
  160 + return -EFAULT;
  161 +
  162 + return 0;
  163 +}
  164 +
  165 +#endif
  166 +
  167 +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  168 +{
  169 + void __user *uaddr = (void __user *)(long)reg->addr;
  170 + u64 val;
  171 + int ret;
  172 +
  173 + ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id));
  174 + if (ret != 0)
  175 + return ret;
  176 +
  177 + return kvm_arm_timer_set_reg(vcpu, reg->id, val);
  178 +}
  179 +
  180 +static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  181 +{
  182 + void __user *uaddr = (void __user *)(long)reg->addr;
  183 + u64 val;
  184 +
  185 + val = kvm_arm_timer_get_reg(vcpu, reg->id);
  186 + return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
  187 +}
  188 +
112 189 static unsigned long num_core_regs(void)
113 190 {
114 191 return sizeof(struct kvm_regs) / sizeof(u32);
... ... @@ -121,7 +198,8 @@
121 198 */
122 199 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
123 200 {
124   - return num_core_regs() + kvm_arm_num_coproc_regs(vcpu);
  201 + return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
  202 + + NUM_TIMER_REGS;
125 203 }
126 204  
127 205 /**
... ... @@ -133,6 +211,7 @@
133 211 {
134 212 unsigned int i;
135 213 const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE;
  214 + int ret;
136 215  
137 216 for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) {
138 217 if (put_user(core_reg | i, uindices))
... ... @@ -140,6 +219,11 @@
140 219 uindices++;
141 220 }
142 221  
  222 + ret = copy_timer_indices(vcpu, uindices);
  223 + if (ret)
  224 + return ret;
  225 + uindices += NUM_TIMER_REGS;
  226 +
143 227 return kvm_arm_copy_coproc_indices(vcpu, uindices);
144 228 }
145 229  
... ... @@ -153,6 +237,9 @@
153 237 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
154 238 return get_core_reg(vcpu, reg);
155 239  
  240 + if (is_timer_reg(reg->id))
  241 + return get_timer_reg(vcpu, reg);
  242 +
156 243 return kvm_arm_coproc_get_reg(vcpu, reg);
157 244 }
158 245  
... ... @@ -165,6 +252,9 @@
165 252 /* Register group 16 means we set a core register. */
166 253 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
167 254 return set_core_reg(vcpu, reg);
  255 +
  256 + if (is_timer_reg(reg->id))
  257 + return set_timer_reg(vcpu, reg);
168 258  
169 259 return kvm_arm_coproc_set_reg(vcpu, reg);
170 260 }
arch/arm64/include/uapi/asm/kvm.h
... ... @@ -129,6 +129,24 @@
129 129 #define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
130 130 #define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
131 131  
  132 +#define ARM64_SYS_REG_SHIFT_MASK(x,n) \
  133 + (((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \
  134 + KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
  135 +
  136 +#define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \
  137 + (KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \
  138 + ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
  139 + ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \
  140 + ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \
  141 + ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \
  142 + ARM64_SYS_REG_SHIFT_MASK(op2, OP2))
  143 +
  144 +#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64)
  145 +
  146 +#define KVM_REG_ARM_TIMER_CTL ARM64_SYS_REG(3, 3, 14, 3, 1)
  147 +#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2)
  148 +#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2)
  149 +
132 150 /* KVM_IRQ_LINE irq field index values */
133 151 #define KVM_ARM_IRQ_TYPE_SHIFT 24
134 152 #define KVM_ARM_IRQ_TYPE_MASK 0xff
virt/kvm/arm/arch_timer.c
... ... @@ -182,6 +182,40 @@
182 182 enable_percpu_irq(host_vtimer_irq, 0);
183 183 }
184 184  
  185 +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
  186 +{
  187 + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
  188 +
  189 + switch (regid) {
  190 + case KVM_REG_ARM_TIMER_CTL:
  191 + timer->cntv_ctl = value;
  192 + break;
  193 + case KVM_REG_ARM_TIMER_CNT:
  194 + vcpu->kvm->arch.timer.cntvoff = kvm_phys_timer_read() - value;
  195 + break;
  196 + case KVM_REG_ARM_TIMER_CVAL:
  197 + timer->cntv_cval = value;
  198 + break;
  199 + default:
  200 + return -1;
  201 + }
  202 + return 0;
  203 +}
  204 +
  205 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
  206 +{
  207 + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
  208 +
  209 + switch (regid) {
  210 + case KVM_REG_ARM_TIMER_CTL:
  211 + return timer->cntv_ctl;
  212 + case KVM_REG_ARM_TIMER_CNT:
  213 + return kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
  214 + case KVM_REG_ARM_TIMER_CVAL:
  215 + return timer->cntv_cval;
  216 + }
  217 + return (u64)-1;
  218 +}
185 219  
186 220 static int kvm_timer_cpu_notify(struct notifier_block *self,
187 221 unsigned long action, void *cpu)