aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@linaro.org>2013-12-13 08:23:26 -0500
committerChristoffer Dall <christoffer.dall@linaro.org>2013-12-21 13:00:15 -0500
commit39735a3a390431bcf60f9174b7d64f787fd6afa9 (patch)
treefcae2ccc844be34f24043b7d14b4a373ecfd5e4a
parenta1a64387adeeba7a34ce06f2774e81f496ee803b (diff)
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>
-rw-r--r--arch/arm/include/asm/kvm_host.h3
-rw-r--r--arch/arm/include/uapi/asm/kvm.h20
-rw-r--r--arch/arm/kvm/guest.c92
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h18
-rw-r--r--virt/kvm/arm/arch_timer.c34
5 files changed, 166 insertions, 1 deletions
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 8a6f6db14ee4..098f7dd6d564 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext)
225int kvm_perf_init(void); 225int kvm_perf_init(void);
226int kvm_perf_teardown(void); 226int kvm_perf_teardown(void);
227 227
228u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
229int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
230
228#endif /* __ARM_KVM_HOST_H__ */ 231#endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index c498b60c0505..835b8678de03 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
119#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 119#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
120#define KVM_REG_ARM_32_CRN_SHIFT 11 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/* Normal registers are mapped as coprocessor 16. */ 142/* Normal registers are mapped as coprocessor 16. */
123#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) 143#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
124#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) 144#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 20f8d97904af..2786eae10c0d 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
109 return -EINVAL; 109 return -EINVAL;
110} 110}
111 111
112#ifndef CONFIG_KVM_ARM_TIMER
113
114#define NUM_TIMER_REGS 0
115
116static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
117{
118 return 0;
119}
120
121static bool is_timer_reg(u64 index)
122{
123 return false;
124}
125
126int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
127{
128 return 0;
129}
130
131u64 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
140static 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
151static 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
167static 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
180static 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
112static unsigned long num_core_regs(void) 189static unsigned long num_core_regs(void)
113{ 190{
114 return sizeof(struct kvm_regs) / sizeof(u32); 191 return sizeof(struct kvm_regs) / sizeof(u32);
@@ -121,7 +198,8 @@ static unsigned long num_core_regs(void)
121 */ 198 */
122unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 199unsigned 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 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
133{ 211{
134 unsigned int i; 212 unsigned int i;
135 const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE; 213 const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE;
214 int ret;
136 215
137 for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) { 216 for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) {
138 if (put_user(core_reg | i, uindices)) 217 if (put_user(core_reg | i, uindices))
@@ -140,6 +219,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
140 uindices++; 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 return kvm_arm_copy_coproc_indices(vcpu, uindices); 227 return kvm_arm_copy_coproc_indices(vcpu, uindices);
144} 228}
145 229
@@ -153,6 +237,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
153 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 237 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
154 return get_core_reg(vcpu, reg); 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 return kvm_arm_coproc_get_reg(vcpu, reg); 243 return kvm_arm_coproc_get_reg(vcpu, reg);
157} 244}
158 245
@@ -166,6 +253,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
166 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 253 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
167 return set_core_reg(vcpu, reg); 254 return set_core_reg(vcpu, reg);
168 255
256 if (is_timer_reg(reg->id))
257 return set_timer_reg(vcpu, reg);
258
169 return kvm_arm_coproc_set_reg(vcpu, reg); 259 return kvm_arm_coproc_set_reg(vcpu, reg);
170} 260}
171 261
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 5031f4263937..7c25ca8b02b3 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -129,6 +129,24 @@ struct kvm_arch_memory_slot {
129#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007 129#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
130#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0 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/* KVM_IRQ_LINE irq field index values */ 150/* KVM_IRQ_LINE irq field index values */
133#define KVM_ARM_IRQ_TYPE_SHIFT 24 151#define KVM_ARM_IRQ_TYPE_SHIFT 24
134#define KVM_ARM_IRQ_TYPE_MASK 0xff 152#define KVM_ARM_IRQ_TYPE_MASK 0xff
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index c2e1ef4604e8..5081e809821f 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -182,6 +182,40 @@ static void kvm_timer_init_interrupt(void *info)
182 enable_percpu_irq(host_vtimer_irq, 0); 182 enable_percpu_irq(host_vtimer_irq, 0);
183} 183}
184 184
185int 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
205u64 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
186static int kvm_timer_cpu_notify(struct notifier_block *self, 220static int kvm_timer_cpu_notify(struct notifier_block *self,
187 unsigned long action, void *cpu) 221 unsigned long action, void *cpu)