]>
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[]) { |
3926cc84 | 53 | VMSTATE_FLOAT64_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 | ||
6df05bdd | 100 | static const VMStateDescription vmstate_m = { |
3cc1d208 | 101 | .name = "cpu/m", |
2c4da50d PM |
102 | .version_id = 3, |
103 | .minimum_version_id = 3, | |
5cd8cada | 104 | .needed = m_needed, |
3cc1d208 | 105 | .fields = (VMStateField[]) { |
3cc1d208 JQ |
106 | VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), |
107 | VMSTATE_UINT32(env.v7m.basepri, ARMCPU), | |
108 | VMSTATE_UINT32(env.v7m.control, ARMCPU), | |
2c4da50d PM |
109 | VMSTATE_UINT32(env.v7m.ccr, ARMCPU), |
110 | VMSTATE_UINT32(env.v7m.cfsr, ARMCPU), | |
111 | VMSTATE_UINT32(env.v7m.hfsr, ARMCPU), | |
112 | VMSTATE_UINT32(env.v7m.dfsr, ARMCPU), | |
113 | VMSTATE_UINT32(env.v7m.mmfar, ARMCPU), | |
114 | VMSTATE_UINT32(env.v7m.bfar, ARMCPU), | |
3cc1d208 JQ |
115 | VMSTATE_INT32(env.v7m.exception, ARMCPU), |
116 | VMSTATE_END_OF_LIST() | |
117 | } | |
118 | }; | |
119 | ||
120 | static bool thumb2ee_needed(void *opaque) | |
8dd3dca3 | 121 | { |
3cc1d208 JQ |
122 | ARMCPU *cpu = opaque; |
123 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 124 | |
3cc1d208 JQ |
125 | return arm_feature(env, ARM_FEATURE_THUMB2EE); |
126 | } | |
8dd3dca3 | 127 | |
3cc1d208 JQ |
128 | static const VMStateDescription vmstate_thumb2ee = { |
129 | .name = "cpu/thumb2ee", | |
130 | .version_id = 1, | |
131 | .minimum_version_id = 1, | |
5cd8cada | 132 | .needed = thumb2ee_needed, |
3cc1d208 JQ |
133 | .fields = (VMStateField[]) { |
134 | VMSTATE_UINT32(env.teecr, ARMCPU), | |
135 | VMSTATE_UINT32(env.teehbr, ARMCPU), | |
136 | VMSTATE_END_OF_LIST() | |
8dd3dca3 | 137 | } |
3cc1d208 JQ |
138 | }; |
139 | ||
6cb0b013 PC |
140 | static bool pmsav7_needed(void *opaque) |
141 | { | |
142 | ARMCPU *cpu = opaque; | |
143 | CPUARMState *env = &cpu->env; | |
144 | ||
145 | return arm_feature(env, ARM_FEATURE_MPU) && | |
146 | arm_feature(env, ARM_FEATURE_V7); | |
147 | } | |
148 | ||
149 | static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id) | |
150 | { | |
151 | ARMCPU *cpu = opaque; | |
152 | ||
153 | return cpu->env.cp15.c6_rgnr < cpu->pmsav7_dregion; | |
154 | } | |
155 | ||
156 | static const VMStateDescription vmstate_pmsav7 = { | |
157 | .name = "cpu/pmsav7", | |
158 | .version_id = 1, | |
159 | .minimum_version_id = 1, | |
160 | .needed = pmsav7_needed, | |
161 | .fields = (VMStateField[]) { | |
162 | VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0, | |
163 | vmstate_info_uint32, uint32_t), | |
164 | VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0, | |
165 | vmstate_info_uint32, uint32_t), | |
166 | VMSTATE_VARRAY_UINT32(env.pmsav7.dracr, ARMCPU, pmsav7_dregion, 0, | |
167 | vmstate_info_uint32, uint32_t), | |
168 | VMSTATE_VALIDATE("rgnr is valid", pmsav7_rgnr_vmstate_validate), | |
169 | VMSTATE_END_OF_LIST() | |
170 | } | |
171 | }; | |
172 | ||
2c21ee76 JD |
173 | static int get_cpsr(QEMUFile *f, void *opaque, size_t size, |
174 | VMStateField *field) | |
3cc1d208 JQ |
175 | { |
176 | ARMCPU *cpu = opaque; | |
177 | CPUARMState *env = &cpu->env; | |
178 | uint32_t val = qemu_get_be32(f); | |
179 | ||
a7130a3e PM |
180 | env->aarch64 = ((val & PSTATE_nRW) == 0); |
181 | ||
182 | if (is_a64(env)) { | |
183 | pstate_write(env, val); | |
184 | return 0; | |
185 | } | |
186 | ||
50866ba5 | 187 | cpsr_write(env, val, 0xffffffff, CPSRWriteRaw); |
3cc1d208 JQ |
188 | return 0; |
189 | } | |
8dd3dca3 | 190 | |
2c21ee76 JD |
191 | static int put_cpsr(QEMUFile *f, void *opaque, size_t size, |
192 | VMStateField *field, QJSON *vmdesc) | |
3cc1d208 JQ |
193 | { |
194 | ARMCPU *cpu = opaque; | |
195 | CPUARMState *env = &cpu->env; | |
a7130a3e PM |
196 | uint32_t val; |
197 | ||
198 | if (is_a64(env)) { | |
199 | val = pstate_read(env); | |
200 | } else { | |
201 | val = cpsr_read(env); | |
202 | } | |
8dd3dca3 | 203 | |
a7130a3e | 204 | qemu_put_be32(f, val); |
2c21ee76 | 205 | return 0; |
3cc1d208 | 206 | } |
8dd3dca3 | 207 | |
3cc1d208 JQ |
208 | static const VMStateInfo vmstate_cpsr = { |
209 | .name = "cpsr", | |
210 | .get = get_cpsr, | |
211 | .put = put_cpsr, | |
212 | }; | |
213 | ||
721fae12 PM |
214 | static void cpu_pre_save(void *opaque) |
215 | { | |
216 | ARMCPU *cpu = opaque; | |
217 | ||
ff047453 PM |
218 | if (kvm_enabled()) { |
219 | if (!write_kvmstate_to_list(cpu)) { | |
220 | /* This should never fail */ | |
221 | abort(); | |
222 | } | |
223 | } else { | |
224 | if (!write_cpustate_to_list(cpu)) { | |
225 | /* This should never fail. */ | |
226 | abort(); | |
227 | } | |
721fae12 PM |
228 | } |
229 | ||
230 | cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; | |
231 | memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, | |
232 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
233 | memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, | |
234 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
235 | } | |
236 | ||
237 | static int cpu_post_load(void *opaque, int version_id) | |
238 | { | |
239 | ARMCPU *cpu = opaque; | |
240 | int i, v; | |
241 | ||
242 | /* Update the values list from the incoming migration data. | |
243 | * Anything in the incoming data which we don't know about is | |
244 | * a migration failure; anything we know about but the incoming | |
245 | * data doesn't specify retains its current (reset) value. | |
246 | * The indexes list remains untouched -- we only inspect the | |
247 | * incoming migration index list so we can match the values array | |
248 | * entries with the right slots in our own values array. | |
249 | */ | |
250 | ||
251 | for (i = 0, v = 0; i < cpu->cpreg_array_len | |
252 | && v < cpu->cpreg_vmstate_array_len; i++) { | |
253 | if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) { | |
254 | /* register in our list but not incoming : skip it */ | |
255 | continue; | |
256 | } | |
257 | if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { | |
258 | /* register in their list but not ours: fail migration */ | |
259 | return -1; | |
260 | } | |
261 | /* matching register, copy the value over */ | |
262 | cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v]; | |
263 | v++; | |
264 | } | |
265 | ||
ff047453 | 266 | if (kvm_enabled()) { |
4b7a6bf4 | 267 | if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) { |
ff047453 PM |
268 | return -1; |
269 | } | |
270 | /* Note that it's OK for the TCG side not to know about | |
271 | * every register in the list; KVM is authoritative if | |
272 | * we're using it. | |
273 | */ | |
274 | write_list_to_cpustate(cpu); | |
275 | } else { | |
276 | if (!write_list_to_cpustate(cpu)) { | |
277 | return -1; | |
278 | } | |
721fae12 PM |
279 | } |
280 | ||
46747d15 | 281 | hw_breakpoint_update_all(cpu); |
9ee98ce8 PM |
282 | hw_watchpoint_update_all(cpu); |
283 | ||
721fae12 PM |
284 | return 0; |
285 | } | |
286 | ||
3cc1d208 JQ |
287 | const VMStateDescription vmstate_arm_cpu = { |
288 | .name = "cpu", | |
a7130a3e PM |
289 | .version_id = 22, |
290 | .minimum_version_id = 22, | |
721fae12 PM |
291 | .pre_save = cpu_pre_save, |
292 | .post_load = cpu_post_load, | |
3cc1d208 JQ |
293 | .fields = (VMStateField[]) { |
294 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), | |
a7130a3e PM |
295 | VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), |
296 | VMSTATE_UINT64(env.pc, ARMCPU), | |
3cc1d208 JQ |
297 | { |
298 | .name = "cpsr", | |
299 | .version_id = 0, | |
300 | .size = sizeof(uint32_t), | |
301 | .info = &vmstate_cpsr, | |
302 | .flags = VMS_SINGLE, | |
303 | .offset = 0, | |
304 | }, | |
305 | VMSTATE_UINT32(env.spsr, ARMCPU), | |
28c9457d | 306 | VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 8), |
0b7d409d FA |
307 | VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 8), |
308 | VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 8), | |
3cc1d208 JQ |
309 | VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), |
310 | VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), | |
1b174238 | 311 | VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4), |
73fb3b76 | 312 | VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4), |
721fae12 PM |
313 | /* The length-check must come before the arrays to avoid |
314 | * incoming data possibly overflowing the array. | |
315 | */ | |
3476436a | 316 | VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU), |
721fae12 PM |
317 | VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, |
318 | cpreg_vmstate_array_len, | |
319 | 0, vmstate_info_uint64, uint64_t), | |
320 | VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU, | |
321 | cpreg_vmstate_array_len, | |
322 | 0, vmstate_info_uint64, uint64_t), | |
03d05e2d PM |
323 | VMSTATE_UINT64(env.exclusive_addr, ARMCPU), |
324 | VMSTATE_UINT64(env.exclusive_val, ARMCPU), | |
325 | VMSTATE_UINT64(env.exclusive_high, ARMCPU), | |
3cc1d208 | 326 | VMSTATE_UINT64(env.features, ARMCPU), |
abf1172f PM |
327 | VMSTATE_UINT32(env.exception.syndrome, ARMCPU), |
328 | VMSTATE_UINT32(env.exception.fsr, ARMCPU), | |
329 | VMSTATE_UINT64(env.exception.vaddress, ARMCPU), | |
e720677e PB |
330 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), |
331 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), | |
543486db | 332 | VMSTATE_BOOL(powered_off, ARMCPU), |
3cc1d208 JQ |
333 | VMSTATE_END_OF_LIST() |
334 | }, | |
5cd8cada JQ |
335 | .subsections = (const VMStateDescription*[]) { |
336 | &vmstate_vfp, | |
337 | &vmstate_iwmmxt, | |
338 | &vmstate_m, | |
339 | &vmstate_thumb2ee, | |
6cb0b013 | 340 | &vmstate_pmsav7, |
5cd8cada | 341 | NULL |
ffe47d33 | 342 | } |
3cc1d208 | 343 | }; |