]>
Commit | Line | Data |
---|---|---|
74c21bd0 | 1 | #include "qemu/osdep.h" |
33c11879 PB |
2 | #include "qemu-common.h" |
3 | #include "cpu.h" | |
8dd3dca3 AJ |
4 | #include "hw/hw.h" |
5 | #include "hw/boards.h" | |
a7bf3034 | 6 | #include "qemu/error-report.h" |
ff047453 PM |
7 | #include "sysemu/kvm.h" |
8 | #include "kvm_arm.h" | |
9ee98ce8 | 9 | #include "internals.h" |
1e00b8d5 | 10 | #include "migration/cpu.h" |
8dd3dca3 | 11 | |
3cc1d208 | 12 | static bool vfp_needed(void *opaque) |
8dd3dca3 | 13 | { |
3cc1d208 JQ |
14 | ARMCPU *cpu = opaque; |
15 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 16 | |
3cc1d208 JQ |
17 | return arm_feature(env, ARM_FEATURE_VFP); |
18 | } | |
8dd3dca3 | 19 | |
2c21ee76 JD |
20 | static int get_fpscr(QEMUFile *f, void *opaque, size_t size, |
21 | VMStateField *field) | |
e91f229a PM |
22 | { |
23 | ARMCPU *cpu = opaque; | |
24 | CPUARMState *env = &cpu->env; | |
25 | uint32_t val = qemu_get_be32(f); | |
26 | ||
27 | vfp_set_fpscr(env, val); | |
28 | return 0; | |
29 | } | |
30 | ||
2c21ee76 JD |
31 | static int put_fpscr(QEMUFile *f, void *opaque, size_t size, |
32 | VMStateField *field, QJSON *vmdesc) | |
e91f229a PM |
33 | { |
34 | ARMCPU *cpu = opaque; | |
35 | CPUARMState *env = &cpu->env; | |
36 | ||
37 | qemu_put_be32(f, vfp_get_fpscr(env)); | |
2c21ee76 | 38 | return 0; |
e91f229a PM |
39 | } |
40 | ||
41 | static const VMStateInfo vmstate_fpscr = { | |
42 | .name = "fpscr", | |
43 | .get = get_fpscr, | |
44 | .put = put_fpscr, | |
45 | }; | |
46 | ||
3cc1d208 JQ |
47 | static const VMStateDescription vmstate_vfp = { |
48 | .name = "cpu/vfp", | |
3926cc84 AG |
49 | .version_id = 3, |
50 | .minimum_version_id = 3, | |
5cd8cada | 51 | .needed = vfp_needed, |
3cc1d208 | 52 | .fields = (VMStateField[]) { |
3f68b8a5 | 53 | VMSTATE_UINT64_ARRAY(env.vfp.regs, ARMCPU, 64), |
e91f229a PM |
54 | /* The xregs array is a little awkward because element 1 (FPSCR) |
55 | * requires a specific accessor, so we have to split it up in | |
56 | * the vmstate: | |
57 | */ | |
58 | VMSTATE_UINT32(env.vfp.xregs[0], ARMCPU), | |
59 | VMSTATE_UINT32_SUB_ARRAY(env.vfp.xregs, ARMCPU, 2, 14), | |
60 | { | |
61 | .name = "fpscr", | |
62 | .version_id = 0, | |
63 | .size = sizeof(uint32_t), | |
64 | .info = &vmstate_fpscr, | |
65 | .flags = VMS_SINGLE, | |
66 | .offset = 0, | |
67 | }, | |
3cc1d208 | 68 | VMSTATE_END_OF_LIST() |
8dd3dca3 | 69 | } |
3cc1d208 | 70 | }; |
8dd3dca3 | 71 | |
3cc1d208 JQ |
72 | static bool iwmmxt_needed(void *opaque) |
73 | { | |
74 | ARMCPU *cpu = opaque; | |
75 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 76 | |
3cc1d208 JQ |
77 | return arm_feature(env, ARM_FEATURE_IWMMXT); |
78 | } | |
ffe47d33 | 79 | |
3cc1d208 JQ |
80 | static const VMStateDescription vmstate_iwmmxt = { |
81 | .name = "cpu/iwmmxt", | |
82 | .version_id = 1, | |
83 | .minimum_version_id = 1, | |
5cd8cada | 84 | .needed = iwmmxt_needed, |
3cc1d208 JQ |
85 | .fields = (VMStateField[]) { |
86 | VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16), | |
87 | VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16), | |
88 | VMSTATE_END_OF_LIST() | |
ffe47d33 | 89 | } |
3cc1d208 JQ |
90 | }; |
91 | ||
92 | static bool m_needed(void *opaque) | |
93 | { | |
94 | ARMCPU *cpu = opaque; | |
95 | CPUARMState *env = &cpu->env; | |
96 | ||
97 | return arm_feature(env, ARM_FEATURE_M); | |
8dd3dca3 AJ |
98 | } |
99 | ||
e6ae5981 PM |
100 | static const VMStateDescription vmstate_m_faultmask_primask = { |
101 | .name = "cpu/m/faultmask-primask", | |
102 | .version_id = 1, | |
103 | .minimum_version_id = 1, | |
104 | .fields = (VMStateField[]) { | |
42a6686b | 105 | VMSTATE_UINT32(env.v7m.faultmask[M_REG_NS], ARMCPU), |
6d804834 | 106 | VMSTATE_UINT32(env.v7m.primask[M_REG_NS], ARMCPU), |
e6ae5981 PM |
107 | VMSTATE_END_OF_LIST() |
108 | } | |
109 | }; | |
110 | ||
6df05bdd | 111 | static const VMStateDescription vmstate_m = { |
3cc1d208 | 112 | .name = "cpu/m", |
29c483a5 MD |
113 | .version_id = 4, |
114 | .minimum_version_id = 4, | |
5cd8cada | 115 | .needed = m_needed, |
3cc1d208 | 116 | .fields = (VMStateField[]) { |
45db7ba6 | 117 | VMSTATE_UINT32(env.v7m.vecbase[M_REG_NS], ARMCPU), |
acf94941 | 118 | VMSTATE_UINT32(env.v7m.basepri[M_REG_NS], ARMCPU), |
8bfc26ea | 119 | VMSTATE_UINT32(env.v7m.control[M_REG_NS], ARMCPU), |
9d40cd8a | 120 | VMSTATE_UINT32(env.v7m.ccr[M_REG_NS], ARMCPU), |
334e8dad | 121 | VMSTATE_UINT32(env.v7m.cfsr[M_REG_NS], ARMCPU), |
2c4da50d PM |
122 | VMSTATE_UINT32(env.v7m.hfsr, ARMCPU), |
123 | VMSTATE_UINT32(env.v7m.dfsr, ARMCPU), | |
c51a5cfc | 124 | VMSTATE_UINT32(env.v7m.mmfar[M_REG_NS], ARMCPU), |
2c4da50d | 125 | VMSTATE_UINT32(env.v7m.bfar, ARMCPU), |
ecf5e8ea | 126 | VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_NS], ARMCPU), |
3cc1d208 JQ |
127 | VMSTATE_INT32(env.v7m.exception, ARMCPU), |
128 | VMSTATE_END_OF_LIST() | |
e6ae5981 PM |
129 | }, |
130 | .subsections = (const VMStateDescription*[]) { | |
131 | &vmstate_m_faultmask_primask, | |
132 | NULL | |
3cc1d208 JQ |
133 | } |
134 | }; | |
135 | ||
136 | static bool thumb2ee_needed(void *opaque) | |
8dd3dca3 | 137 | { |
3cc1d208 JQ |
138 | ARMCPU *cpu = opaque; |
139 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 140 | |
3cc1d208 JQ |
141 | return arm_feature(env, ARM_FEATURE_THUMB2EE); |
142 | } | |
8dd3dca3 | 143 | |
3cc1d208 JQ |
144 | static const VMStateDescription vmstate_thumb2ee = { |
145 | .name = "cpu/thumb2ee", | |
146 | .version_id = 1, | |
147 | .minimum_version_id = 1, | |
5cd8cada | 148 | .needed = thumb2ee_needed, |
3cc1d208 JQ |
149 | .fields = (VMStateField[]) { |
150 | VMSTATE_UINT32(env.teecr, ARMCPU), | |
151 | VMSTATE_UINT32(env.teehbr, ARMCPU), | |
152 | VMSTATE_END_OF_LIST() | |
8dd3dca3 | 153 | } |
3cc1d208 JQ |
154 | }; |
155 | ||
6cb0b013 PC |
156 | static bool pmsav7_needed(void *opaque) |
157 | { | |
158 | ARMCPU *cpu = opaque; | |
159 | CPUARMState *env = &cpu->env; | |
160 | ||
452a0955 | 161 | return arm_feature(env, ARM_FEATURE_PMSA) && |
0e1a46bb PM |
162 | arm_feature(env, ARM_FEATURE_V7) && |
163 | !arm_feature(env, ARM_FEATURE_V8); | |
6cb0b013 PC |
164 | } |
165 | ||
166 | static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id) | |
167 | { | |
168 | ARMCPU *cpu = opaque; | |
169 | ||
1bc04a88 | 170 | return cpu->env.pmsav7.rnr[M_REG_NS] < cpu->pmsav7_dregion; |
6cb0b013 PC |
171 | } |
172 | ||
173 | static const VMStateDescription vmstate_pmsav7 = { | |
174 | .name = "cpu/pmsav7", | |
175 | .version_id = 1, | |
176 | .minimum_version_id = 1, | |
177 | .needed = pmsav7_needed, | |
178 | .fields = (VMStateField[]) { | |
179 | VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0, | |
180 | vmstate_info_uint32, uint32_t), | |
181 | VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0, | |
182 | vmstate_info_uint32, uint32_t), | |
183 | VMSTATE_VARRAY_UINT32(env.pmsav7.dracr, ARMCPU, pmsav7_dregion, 0, | |
184 | vmstate_info_uint32, uint32_t), | |
185 | VMSTATE_VALIDATE("rgnr is valid", pmsav7_rgnr_vmstate_validate), | |
186 | VMSTATE_END_OF_LIST() | |
187 | } | |
188 | }; | |
189 | ||
f1a46940 PM |
190 | static bool pmsav7_rnr_needed(void *opaque) |
191 | { | |
192 | ARMCPU *cpu = opaque; | |
193 | CPUARMState *env = &cpu->env; | |
194 | ||
195 | /* For R profile cores pmsav7.rnr is migrated via the cpreg | |
196 | * "RGNR" definition in helper.h. For M profile we have to | |
197 | * migrate it separately. | |
198 | */ | |
199 | return arm_feature(env, ARM_FEATURE_M); | |
200 | } | |
201 | ||
202 | static const VMStateDescription vmstate_pmsav7_rnr = { | |
203 | .name = "cpu/pmsav7-rnr", | |
204 | .version_id = 1, | |
205 | .minimum_version_id = 1, | |
206 | .needed = pmsav7_rnr_needed, | |
207 | .fields = (VMStateField[]) { | |
1bc04a88 | 208 | VMSTATE_UINT32(env.pmsav7.rnr[M_REG_NS], ARMCPU), |
f1a46940 PM |
209 | VMSTATE_END_OF_LIST() |
210 | } | |
211 | }; | |
212 | ||
0e1a46bb PM |
213 | static bool pmsav8_needed(void *opaque) |
214 | { | |
215 | ARMCPU *cpu = opaque; | |
216 | CPUARMState *env = &cpu->env; | |
217 | ||
218 | return arm_feature(env, ARM_FEATURE_PMSA) && | |
219 | arm_feature(env, ARM_FEATURE_V8); | |
220 | } | |
221 | ||
222 | static const VMStateDescription vmstate_pmsav8 = { | |
223 | .name = "cpu/pmsav8", | |
224 | .version_id = 1, | |
225 | .minimum_version_id = 1, | |
226 | .needed = pmsav8_needed, | |
227 | .fields = (VMStateField[]) { | |
62c58ee0 PM |
228 | VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_NS], ARMCPU, pmsav7_dregion, |
229 | 0, vmstate_info_uint32, uint32_t), | |
230 | VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_NS], ARMCPU, pmsav7_dregion, | |
231 | 0, vmstate_info_uint32, uint32_t), | |
4125e6fe PM |
232 | VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU), |
233 | VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU), | |
0e1a46bb PM |
234 | VMSTATE_END_OF_LIST() |
235 | } | |
236 | }; | |
237 | ||
1bc04a88 PM |
238 | static bool s_rnr_vmstate_validate(void *opaque, int version_id) |
239 | { | |
240 | ARMCPU *cpu = opaque; | |
241 | ||
242 | return cpu->env.pmsav7.rnr[M_REG_S] < cpu->pmsav7_dregion; | |
243 | } | |
244 | ||
9901c576 PM |
245 | static bool sau_rnr_vmstate_validate(void *opaque, int version_id) |
246 | { | |
247 | ARMCPU *cpu = opaque; | |
248 | ||
249 | return cpu->env.sau.rnr < cpu->sau_sregion; | |
250 | } | |
251 | ||
1e577cc7 PM |
252 | static bool m_security_needed(void *opaque) |
253 | { | |
254 | ARMCPU *cpu = opaque; | |
255 | CPUARMState *env = &cpu->env; | |
256 | ||
257 | return arm_feature(env, ARM_FEATURE_M_SECURITY); | |
258 | } | |
259 | ||
260 | static const VMStateDescription vmstate_m_security = { | |
261 | .name = "cpu/m-security", | |
262 | .version_id = 1, | |
263 | .minimum_version_id = 1, | |
264 | .needed = m_security_needed, | |
265 | .fields = (VMStateField[]) { | |
266 | VMSTATE_UINT32(env.v7m.secure, ARMCPU), | |
fb602cb7 PM |
267 | VMSTATE_UINT32(env.v7m.other_ss_msp, ARMCPU), |
268 | VMSTATE_UINT32(env.v7m.other_ss_psp, ARMCPU), | |
acf94941 | 269 | VMSTATE_UINT32(env.v7m.basepri[M_REG_S], ARMCPU), |
6d804834 | 270 | VMSTATE_UINT32(env.v7m.primask[M_REG_S], ARMCPU), |
42a6686b | 271 | VMSTATE_UINT32(env.v7m.faultmask[M_REG_S], ARMCPU), |
8bfc26ea | 272 | VMSTATE_UINT32(env.v7m.control[M_REG_S], ARMCPU), |
45db7ba6 | 273 | VMSTATE_UINT32(env.v7m.vecbase[M_REG_S], ARMCPU), |
4125e6fe PM |
274 | VMSTATE_UINT32(env.pmsav8.mair0[M_REG_S], ARMCPU), |
275 | VMSTATE_UINT32(env.pmsav8.mair1[M_REG_S], ARMCPU), | |
62c58ee0 PM |
276 | VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_S], ARMCPU, pmsav7_dregion, |
277 | 0, vmstate_info_uint32, uint32_t), | |
278 | VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_S], ARMCPU, pmsav7_dregion, | |
279 | 0, vmstate_info_uint32, uint32_t), | |
1bc04a88 PM |
280 | VMSTATE_UINT32(env.pmsav7.rnr[M_REG_S], ARMCPU), |
281 | VMSTATE_VALIDATE("secure MPU_RNR is valid", s_rnr_vmstate_validate), | |
ecf5e8ea | 282 | VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_S], ARMCPU), |
9d40cd8a | 283 | VMSTATE_UINT32(env.v7m.ccr[M_REG_S], ARMCPU), |
c51a5cfc | 284 | VMSTATE_UINT32(env.v7m.mmfar[M_REG_S], ARMCPU), |
334e8dad | 285 | VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU), |
bed079da PM |
286 | VMSTATE_UINT32(env.v7m.sfsr, ARMCPU), |
287 | VMSTATE_UINT32(env.v7m.sfar, ARMCPU), | |
9901c576 PM |
288 | VMSTATE_VARRAY_UINT32(env.sau.rbar, ARMCPU, sau_sregion, 0, |
289 | vmstate_info_uint32, uint32_t), | |
290 | VMSTATE_VARRAY_UINT32(env.sau.rlar, ARMCPU, sau_sregion, 0, | |
291 | vmstate_info_uint32, uint32_t), | |
292 | VMSTATE_UINT32(env.sau.rnr, ARMCPU), | |
293 | VMSTATE_VALIDATE("SAU_RNR is valid", sau_rnr_vmstate_validate), | |
294 | VMSTATE_UINT32(env.sau.ctrl, ARMCPU), | |
1e577cc7 PM |
295 | VMSTATE_END_OF_LIST() |
296 | } | |
297 | }; | |
298 | ||
2c21ee76 JD |
299 | static int get_cpsr(QEMUFile *f, void *opaque, size_t size, |
300 | VMStateField *field) | |
3cc1d208 JQ |
301 | { |
302 | ARMCPU *cpu = opaque; | |
303 | CPUARMState *env = &cpu->env; | |
304 | uint32_t val = qemu_get_be32(f); | |
305 | ||
e6ae5981 | 306 | if (arm_feature(env, ARM_FEATURE_M)) { |
eeade001 PM |
307 | if (val & XPSR_EXCP) { |
308 | /* This is a CPSR format value from an older QEMU. (We can tell | |
309 | * because values transferred in XPSR format always have zero | |
310 | * for the EXCP field, and CPSR format will always have bit 4 | |
311 | * set in CPSR_M.) Rearrange it into XPSR format. The significant | |
312 | * differences are that the T bit is not in the same place, the | |
313 | * primask/faultmask info may be in the CPSR I and F bits, and | |
314 | * we do not want the mode bits. | |
6d804834 PM |
315 | * We know that this cleanup happened before v8M, so there |
316 | * is no complication with banked primask/faultmask. | |
eeade001 PM |
317 | */ |
318 | uint32_t newval = val; | |
319 | ||
6d804834 PM |
320 | assert(!arm_feature(env, ARM_FEATURE_M_SECURITY)); |
321 | ||
eeade001 PM |
322 | newval &= (CPSR_NZCV | CPSR_Q | CPSR_IT | CPSR_GE); |
323 | if (val & CPSR_T) { | |
324 | newval |= XPSR_T; | |
325 | } | |
326 | /* If the I or F bits are set then this is a migration from | |
327 | * an old QEMU which still stored the M profile FAULTMASK | |
328 | * and PRIMASK in env->daif. For a new QEMU, the data is | |
329 | * transferred using the vmstate_m_faultmask_primask subsection. | |
330 | */ | |
331 | if (val & CPSR_F) { | |
42a6686b | 332 | env->v7m.faultmask[M_REG_NS] = 1; |
eeade001 PM |
333 | } |
334 | if (val & CPSR_I) { | |
6d804834 | 335 | env->v7m.primask[M_REG_NS] = 1; |
eeade001 PM |
336 | } |
337 | val = newval; | |
e6ae5981 | 338 | } |
eeade001 PM |
339 | /* Ignore the low bits, they are handled by vmstate_m. */ |
340 | xpsr_write(env, val, ~XPSR_EXCP); | |
341 | return 0; | |
e6ae5981 PM |
342 | } |
343 | ||
a7130a3e PM |
344 | env->aarch64 = ((val & PSTATE_nRW) == 0); |
345 | ||
346 | if (is_a64(env)) { | |
347 | pstate_write(env, val); | |
348 | return 0; | |
349 | } | |
350 | ||
50866ba5 | 351 | cpsr_write(env, val, 0xffffffff, CPSRWriteRaw); |
3cc1d208 JQ |
352 | return 0; |
353 | } | |
8dd3dca3 | 354 | |
2c21ee76 JD |
355 | static int put_cpsr(QEMUFile *f, void *opaque, size_t size, |
356 | VMStateField *field, QJSON *vmdesc) | |
3cc1d208 JQ |
357 | { |
358 | ARMCPU *cpu = opaque; | |
359 | CPUARMState *env = &cpu->env; | |
a7130a3e PM |
360 | uint32_t val; |
361 | ||
eeade001 PM |
362 | if (arm_feature(env, ARM_FEATURE_M)) { |
363 | /* The low 9 bits are v7m.exception, which is handled by vmstate_m. */ | |
364 | val = xpsr_read(env) & ~XPSR_EXCP; | |
365 | } else if (is_a64(env)) { | |
a7130a3e PM |
366 | val = pstate_read(env); |
367 | } else { | |
368 | val = cpsr_read(env); | |
369 | } | |
8dd3dca3 | 370 | |
a7130a3e | 371 | qemu_put_be32(f, val); |
2c21ee76 | 372 | return 0; |
3cc1d208 | 373 | } |
8dd3dca3 | 374 | |
3cc1d208 JQ |
375 | static const VMStateInfo vmstate_cpsr = { |
376 | .name = "cpsr", | |
377 | .get = get_cpsr, | |
378 | .put = put_cpsr, | |
379 | }; | |
380 | ||
062ba099 AB |
381 | static int get_power(QEMUFile *f, void *opaque, size_t size, |
382 | VMStateField *field) | |
383 | { | |
384 | ARMCPU *cpu = opaque; | |
385 | bool powered_off = qemu_get_byte(f); | |
386 | cpu->power_state = powered_off ? PSCI_OFF : PSCI_ON; | |
387 | return 0; | |
388 | } | |
389 | ||
390 | static int put_power(QEMUFile *f, void *opaque, size_t size, | |
391 | VMStateField *field, QJSON *vmdesc) | |
392 | { | |
393 | ARMCPU *cpu = opaque; | |
394 | ||
395 | /* Migration should never happen while we transition power states */ | |
396 | ||
397 | if (cpu->power_state == PSCI_ON || | |
398 | cpu->power_state == PSCI_OFF) { | |
399 | bool powered_off = (cpu->power_state == PSCI_OFF) ? true : false; | |
400 | qemu_put_byte(f, powered_off); | |
401 | return 0; | |
402 | } else { | |
403 | return 1; | |
404 | } | |
405 | } | |
406 | ||
407 | static const VMStateInfo vmstate_powered_off = { | |
408 | .name = "powered_off", | |
409 | .get = get_power, | |
410 | .put = put_power, | |
411 | }; | |
412 | ||
44b1ff31 | 413 | static int cpu_pre_save(void *opaque) |
721fae12 PM |
414 | { |
415 | ARMCPU *cpu = opaque; | |
416 | ||
ff047453 PM |
417 | if (kvm_enabled()) { |
418 | if (!write_kvmstate_to_list(cpu)) { | |
419 | /* This should never fail */ | |
420 | abort(); | |
421 | } | |
422 | } else { | |
423 | if (!write_cpustate_to_list(cpu)) { | |
424 | /* This should never fail. */ | |
425 | abort(); | |
426 | } | |
721fae12 PM |
427 | } |
428 | ||
429 | cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; | |
430 | memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, | |
431 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
432 | memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, | |
433 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
44b1ff31 DDAG |
434 | |
435 | return 0; | |
721fae12 PM |
436 | } |
437 | ||
438 | static int cpu_post_load(void *opaque, int version_id) | |
439 | { | |
440 | ARMCPU *cpu = opaque; | |
441 | int i, v; | |
442 | ||
443 | /* Update the values list from the incoming migration data. | |
444 | * Anything in the incoming data which we don't know about is | |
445 | * a migration failure; anything we know about but the incoming | |
446 | * data doesn't specify retains its current (reset) value. | |
447 | * The indexes list remains untouched -- we only inspect the | |
448 | * incoming migration index list so we can match the values array | |
449 | * entries with the right slots in our own values array. | |
450 | */ | |
451 | ||
452 | for (i = 0, v = 0; i < cpu->cpreg_array_len | |
453 | && v < cpu->cpreg_vmstate_array_len; i++) { | |
454 | if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) { | |
455 | /* register in our list but not incoming : skip it */ | |
456 | continue; | |
457 | } | |
458 | if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { | |
459 | /* register in their list but not ours: fail migration */ | |
460 | return -1; | |
461 | } | |
462 | /* matching register, copy the value over */ | |
463 | cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v]; | |
464 | v++; | |
465 | } | |
466 | ||
ff047453 | 467 | if (kvm_enabled()) { |
4b7a6bf4 | 468 | if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) { |
ff047453 PM |
469 | return -1; |
470 | } | |
471 | /* Note that it's OK for the TCG side not to know about | |
472 | * every register in the list; KVM is authoritative if | |
473 | * we're using it. | |
474 | */ | |
475 | write_list_to_cpustate(cpu); | |
476 | } else { | |
477 | if (!write_list_to_cpustate(cpu)) { | |
478 | return -1; | |
479 | } | |
721fae12 PM |
480 | } |
481 | ||
46747d15 | 482 | hw_breakpoint_update_all(cpu); |
9ee98ce8 PM |
483 | hw_watchpoint_update_all(cpu); |
484 | ||
721fae12 PM |
485 | return 0; |
486 | } | |
487 | ||
3cc1d208 JQ |
488 | const VMStateDescription vmstate_arm_cpu = { |
489 | .name = "cpu", | |
a7130a3e PM |
490 | .version_id = 22, |
491 | .minimum_version_id = 22, | |
721fae12 PM |
492 | .pre_save = cpu_pre_save, |
493 | .post_load = cpu_post_load, | |
3cc1d208 JQ |
494 | .fields = (VMStateField[]) { |
495 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), | |
a7130a3e PM |
496 | VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), |
497 | VMSTATE_UINT64(env.pc, ARMCPU), | |
3cc1d208 JQ |
498 | { |
499 | .name = "cpsr", | |
500 | .version_id = 0, | |
501 | .size = sizeof(uint32_t), | |
502 | .info = &vmstate_cpsr, | |
503 | .flags = VMS_SINGLE, | |
504 | .offset = 0, | |
505 | }, | |
506 | VMSTATE_UINT32(env.spsr, ARMCPU), | |
28c9457d | 507 | VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 8), |
0b7d409d FA |
508 | VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 8), |
509 | VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 8), | |
3cc1d208 JQ |
510 | VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), |
511 | VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), | |
1b174238 | 512 | VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4), |
73fb3b76 | 513 | VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4), |
721fae12 PM |
514 | /* The length-check must come before the arrays to avoid |
515 | * incoming data possibly overflowing the array. | |
516 | */ | |
3476436a | 517 | VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU), |
721fae12 PM |
518 | VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, |
519 | cpreg_vmstate_array_len, | |
520 | 0, vmstate_info_uint64, uint64_t), | |
521 | VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU, | |
522 | cpreg_vmstate_array_len, | |
523 | 0, vmstate_info_uint64, uint64_t), | |
03d05e2d PM |
524 | VMSTATE_UINT64(env.exclusive_addr, ARMCPU), |
525 | VMSTATE_UINT64(env.exclusive_val, ARMCPU), | |
526 | VMSTATE_UINT64(env.exclusive_high, ARMCPU), | |
3cc1d208 | 527 | VMSTATE_UINT64(env.features, ARMCPU), |
abf1172f PM |
528 | VMSTATE_UINT32(env.exception.syndrome, ARMCPU), |
529 | VMSTATE_UINT32(env.exception.fsr, ARMCPU), | |
530 | VMSTATE_UINT64(env.exception.vaddress, ARMCPU), | |
e720677e PB |
531 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), |
532 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), | |
062ba099 AB |
533 | { |
534 | .name = "power_state", | |
535 | .version_id = 0, | |
536 | .size = sizeof(bool), | |
537 | .info = &vmstate_powered_off, | |
538 | .flags = VMS_SINGLE, | |
539 | .offset = 0, | |
540 | }, | |
3cc1d208 JQ |
541 | VMSTATE_END_OF_LIST() |
542 | }, | |
5cd8cada JQ |
543 | .subsections = (const VMStateDescription*[]) { |
544 | &vmstate_vfp, | |
545 | &vmstate_iwmmxt, | |
546 | &vmstate_m, | |
547 | &vmstate_thumb2ee, | |
f1a46940 PM |
548 | /* pmsav7_rnr must come before pmsav7 so that we have the |
549 | * region number before we test it in the VMSTATE_VALIDATE | |
550 | * in vmstate_pmsav7. | |
551 | */ | |
552 | &vmstate_pmsav7_rnr, | |
6cb0b013 | 553 | &vmstate_pmsav7, |
0e1a46bb | 554 | &vmstate_pmsav8, |
1e577cc7 | 555 | &vmstate_m_security, |
5cd8cada | 556 | NULL |
ffe47d33 | 557 | } |
3cc1d208 | 558 | }; |