]>
Commit | Line | Data |
---|---|---|
8dd3dca3 AJ |
1 | #include "hw/hw.h" |
2 | #include "hw/boards.h" | |
a7bf3034 | 3 | #include "qemu/error-report.h" |
ff047453 PM |
4 | #include "sysemu/kvm.h" |
5 | #include "kvm_arm.h" | |
9ee98ce8 | 6 | #include "internals.h" |
8dd3dca3 | 7 | |
3cc1d208 | 8 | static bool vfp_needed(void *opaque) |
8dd3dca3 | 9 | { |
3cc1d208 JQ |
10 | ARMCPU *cpu = opaque; |
11 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 12 | |
3cc1d208 JQ |
13 | return arm_feature(env, ARM_FEATURE_VFP); |
14 | } | |
8dd3dca3 | 15 | |
e91f229a PM |
16 | static int get_fpscr(QEMUFile *f, void *opaque, size_t size) |
17 | { | |
18 | ARMCPU *cpu = opaque; | |
19 | CPUARMState *env = &cpu->env; | |
20 | uint32_t val = qemu_get_be32(f); | |
21 | ||
22 | vfp_set_fpscr(env, val); | |
23 | return 0; | |
24 | } | |
25 | ||
26 | static void put_fpscr(QEMUFile *f, void *opaque, size_t size) | |
27 | { | |
28 | ARMCPU *cpu = opaque; | |
29 | CPUARMState *env = &cpu->env; | |
30 | ||
31 | qemu_put_be32(f, vfp_get_fpscr(env)); | |
32 | } | |
33 | ||
34 | static const VMStateInfo vmstate_fpscr = { | |
35 | .name = "fpscr", | |
36 | .get = get_fpscr, | |
37 | .put = put_fpscr, | |
38 | }; | |
39 | ||
3cc1d208 JQ |
40 | static const VMStateDescription vmstate_vfp = { |
41 | .name = "cpu/vfp", | |
3926cc84 AG |
42 | .version_id = 3, |
43 | .minimum_version_id = 3, | |
5cd8cada | 44 | .needed = vfp_needed, |
3cc1d208 | 45 | .fields = (VMStateField[]) { |
3926cc84 | 46 | VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64), |
e91f229a PM |
47 | /* The xregs array is a little awkward because element 1 (FPSCR) |
48 | * requires a specific accessor, so we have to split it up in | |
49 | * the vmstate: | |
50 | */ | |
51 | VMSTATE_UINT32(env.vfp.xregs[0], ARMCPU), | |
52 | VMSTATE_UINT32_SUB_ARRAY(env.vfp.xregs, ARMCPU, 2, 14), | |
53 | { | |
54 | .name = "fpscr", | |
55 | .version_id = 0, | |
56 | .size = sizeof(uint32_t), | |
57 | .info = &vmstate_fpscr, | |
58 | .flags = VMS_SINGLE, | |
59 | .offset = 0, | |
60 | }, | |
3cc1d208 | 61 | VMSTATE_END_OF_LIST() |
8dd3dca3 | 62 | } |
3cc1d208 | 63 | }; |
8dd3dca3 | 64 | |
3cc1d208 JQ |
65 | static bool iwmmxt_needed(void *opaque) |
66 | { | |
67 | ARMCPU *cpu = opaque; | |
68 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 69 | |
3cc1d208 JQ |
70 | return arm_feature(env, ARM_FEATURE_IWMMXT); |
71 | } | |
ffe47d33 | 72 | |
3cc1d208 JQ |
73 | static const VMStateDescription vmstate_iwmmxt = { |
74 | .name = "cpu/iwmmxt", | |
75 | .version_id = 1, | |
76 | .minimum_version_id = 1, | |
5cd8cada | 77 | .needed = iwmmxt_needed, |
3cc1d208 JQ |
78 | .fields = (VMStateField[]) { |
79 | VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16), | |
80 | VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16), | |
81 | VMSTATE_END_OF_LIST() | |
ffe47d33 | 82 | } |
3cc1d208 JQ |
83 | }; |
84 | ||
85 | static bool m_needed(void *opaque) | |
86 | { | |
87 | ARMCPU *cpu = opaque; | |
88 | CPUARMState *env = &cpu->env; | |
89 | ||
90 | return arm_feature(env, ARM_FEATURE_M); | |
8dd3dca3 AJ |
91 | } |
92 | ||
6df05bdd | 93 | static const VMStateDescription vmstate_m = { |
3cc1d208 JQ |
94 | .name = "cpu/m", |
95 | .version_id = 1, | |
96 | .minimum_version_id = 1, | |
5cd8cada | 97 | .needed = m_needed, |
3cc1d208 JQ |
98 | .fields = (VMStateField[]) { |
99 | VMSTATE_UINT32(env.v7m.other_sp, ARMCPU), | |
100 | VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), | |
101 | VMSTATE_UINT32(env.v7m.basepri, ARMCPU), | |
102 | VMSTATE_UINT32(env.v7m.control, ARMCPU), | |
103 | VMSTATE_INT32(env.v7m.current_sp, ARMCPU), | |
104 | VMSTATE_INT32(env.v7m.exception, ARMCPU), | |
105 | VMSTATE_END_OF_LIST() | |
106 | } | |
107 | }; | |
108 | ||
109 | static bool thumb2ee_needed(void *opaque) | |
8dd3dca3 | 110 | { |
3cc1d208 JQ |
111 | ARMCPU *cpu = opaque; |
112 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 113 | |
3cc1d208 JQ |
114 | return arm_feature(env, ARM_FEATURE_THUMB2EE); |
115 | } | |
8dd3dca3 | 116 | |
3cc1d208 JQ |
117 | static const VMStateDescription vmstate_thumb2ee = { |
118 | .name = "cpu/thumb2ee", | |
119 | .version_id = 1, | |
120 | .minimum_version_id = 1, | |
5cd8cada | 121 | .needed = thumb2ee_needed, |
3cc1d208 JQ |
122 | .fields = (VMStateField[]) { |
123 | VMSTATE_UINT32(env.teecr, ARMCPU), | |
124 | VMSTATE_UINT32(env.teehbr, ARMCPU), | |
125 | VMSTATE_END_OF_LIST() | |
8dd3dca3 | 126 | } |
3cc1d208 JQ |
127 | }; |
128 | ||
6cb0b013 PC |
129 | static bool pmsav7_needed(void *opaque) |
130 | { | |
131 | ARMCPU *cpu = opaque; | |
132 | CPUARMState *env = &cpu->env; | |
133 | ||
134 | return arm_feature(env, ARM_FEATURE_MPU) && | |
135 | arm_feature(env, ARM_FEATURE_V7); | |
136 | } | |
137 | ||
138 | static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id) | |
139 | { | |
140 | ARMCPU *cpu = opaque; | |
141 | ||
142 | return cpu->env.cp15.c6_rgnr < cpu->pmsav7_dregion; | |
143 | } | |
144 | ||
145 | static const VMStateDescription vmstate_pmsav7 = { | |
146 | .name = "cpu/pmsav7", | |
147 | .version_id = 1, | |
148 | .minimum_version_id = 1, | |
149 | .needed = pmsav7_needed, | |
150 | .fields = (VMStateField[]) { | |
151 | VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0, | |
152 | vmstate_info_uint32, uint32_t), | |
153 | VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0, | |
154 | vmstate_info_uint32, uint32_t), | |
155 | VMSTATE_VARRAY_UINT32(env.pmsav7.dracr, ARMCPU, pmsav7_dregion, 0, | |
156 | vmstate_info_uint32, uint32_t), | |
157 | VMSTATE_VALIDATE("rgnr is valid", pmsav7_rgnr_vmstate_validate), | |
158 | VMSTATE_END_OF_LIST() | |
159 | } | |
160 | }; | |
161 | ||
3cc1d208 JQ |
162 | static int get_cpsr(QEMUFile *f, void *opaque, size_t size) |
163 | { | |
164 | ARMCPU *cpu = opaque; | |
165 | CPUARMState *env = &cpu->env; | |
166 | uint32_t val = qemu_get_be32(f); | |
167 | ||
a7130a3e PM |
168 | env->aarch64 = ((val & PSTATE_nRW) == 0); |
169 | ||
170 | if (is_a64(env)) { | |
171 | pstate_write(env, val); | |
172 | return 0; | |
173 | } | |
174 | ||
3cc1d208 | 175 | /* Avoid mode switch when restoring CPSR */ |
ffe47d33 PB |
176 | env->uncached_cpsr = val & CPSR_M; |
177 | cpsr_write(env, val, 0xffffffff); | |
3cc1d208 JQ |
178 | return 0; |
179 | } | |
8dd3dca3 | 180 | |
3cc1d208 JQ |
181 | static void put_cpsr(QEMUFile *f, void *opaque, size_t size) |
182 | { | |
183 | ARMCPU *cpu = opaque; | |
184 | CPUARMState *env = &cpu->env; | |
a7130a3e PM |
185 | uint32_t val; |
186 | ||
187 | if (is_a64(env)) { | |
188 | val = pstate_read(env); | |
189 | } else { | |
190 | val = cpsr_read(env); | |
191 | } | |
8dd3dca3 | 192 | |
a7130a3e | 193 | qemu_put_be32(f, val); |
3cc1d208 | 194 | } |
8dd3dca3 | 195 | |
3cc1d208 JQ |
196 | static const VMStateInfo vmstate_cpsr = { |
197 | .name = "cpsr", | |
198 | .get = get_cpsr, | |
199 | .put = put_cpsr, | |
200 | }; | |
201 | ||
721fae12 PM |
202 | static void cpu_pre_save(void *opaque) |
203 | { | |
204 | ARMCPU *cpu = opaque; | |
205 | ||
ff047453 PM |
206 | if (kvm_enabled()) { |
207 | if (!write_kvmstate_to_list(cpu)) { | |
208 | /* This should never fail */ | |
209 | abort(); | |
210 | } | |
211 | } else { | |
212 | if (!write_cpustate_to_list(cpu)) { | |
213 | /* This should never fail. */ | |
214 | abort(); | |
215 | } | |
721fae12 PM |
216 | } |
217 | ||
218 | cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; | |
219 | memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, | |
220 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
221 | memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, | |
222 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
223 | } | |
224 | ||
225 | static int cpu_post_load(void *opaque, int version_id) | |
226 | { | |
227 | ARMCPU *cpu = opaque; | |
228 | int i, v; | |
229 | ||
230 | /* Update the values list from the incoming migration data. | |
231 | * Anything in the incoming data which we don't know about is | |
232 | * a migration failure; anything we know about but the incoming | |
233 | * data doesn't specify retains its current (reset) value. | |
234 | * The indexes list remains untouched -- we only inspect the | |
235 | * incoming migration index list so we can match the values array | |
236 | * entries with the right slots in our own values array. | |
237 | */ | |
238 | ||
239 | for (i = 0, v = 0; i < cpu->cpreg_array_len | |
240 | && v < cpu->cpreg_vmstate_array_len; i++) { | |
241 | if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) { | |
242 | /* register in our list but not incoming : skip it */ | |
243 | continue; | |
244 | } | |
245 | if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { | |
246 | /* register in their list but not ours: fail migration */ | |
247 | return -1; | |
248 | } | |
249 | /* matching register, copy the value over */ | |
250 | cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v]; | |
251 | v++; | |
252 | } | |
253 | ||
ff047453 | 254 | if (kvm_enabled()) { |
4b7a6bf4 | 255 | if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) { |
ff047453 PM |
256 | return -1; |
257 | } | |
258 | /* Note that it's OK for the TCG side not to know about | |
259 | * every register in the list; KVM is authoritative if | |
260 | * we're using it. | |
261 | */ | |
262 | write_list_to_cpustate(cpu); | |
263 | } else { | |
264 | if (!write_list_to_cpustate(cpu)) { | |
265 | return -1; | |
266 | } | |
721fae12 PM |
267 | } |
268 | ||
46747d15 | 269 | hw_breakpoint_update_all(cpu); |
9ee98ce8 PM |
270 | hw_watchpoint_update_all(cpu); |
271 | ||
721fae12 PM |
272 | return 0; |
273 | } | |
274 | ||
3cc1d208 JQ |
275 | const VMStateDescription vmstate_arm_cpu = { |
276 | .name = "cpu", | |
a7130a3e PM |
277 | .version_id = 22, |
278 | .minimum_version_id = 22, | |
721fae12 PM |
279 | .pre_save = cpu_pre_save, |
280 | .post_load = cpu_post_load, | |
3cc1d208 JQ |
281 | .fields = (VMStateField[]) { |
282 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), | |
a7130a3e PM |
283 | VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), |
284 | VMSTATE_UINT64(env.pc, ARMCPU), | |
3cc1d208 JQ |
285 | { |
286 | .name = "cpsr", | |
287 | .version_id = 0, | |
288 | .size = sizeof(uint32_t), | |
289 | .info = &vmstate_cpsr, | |
290 | .flags = VMS_SINGLE, | |
291 | .offset = 0, | |
292 | }, | |
293 | VMSTATE_UINT32(env.spsr, ARMCPU), | |
28c9457d | 294 | VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 8), |
0b7d409d FA |
295 | VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 8), |
296 | VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 8), | |
3cc1d208 JQ |
297 | VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), |
298 | VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), | |
1b174238 | 299 | VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4), |
73fb3b76 | 300 | VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4), |
721fae12 PM |
301 | /* The length-check must come before the arrays to avoid |
302 | * incoming data possibly overflowing the array. | |
303 | */ | |
3476436a | 304 | VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU), |
721fae12 PM |
305 | VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, |
306 | cpreg_vmstate_array_len, | |
307 | 0, vmstate_info_uint64, uint64_t), | |
308 | VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU, | |
309 | cpreg_vmstate_array_len, | |
310 | 0, vmstate_info_uint64, uint64_t), | |
03d05e2d PM |
311 | VMSTATE_UINT64(env.exclusive_addr, ARMCPU), |
312 | VMSTATE_UINT64(env.exclusive_val, ARMCPU), | |
313 | VMSTATE_UINT64(env.exclusive_high, ARMCPU), | |
3cc1d208 | 314 | VMSTATE_UINT64(env.features, ARMCPU), |
abf1172f PM |
315 | VMSTATE_UINT32(env.exception.syndrome, ARMCPU), |
316 | VMSTATE_UINT32(env.exception.fsr, ARMCPU), | |
317 | VMSTATE_UINT64(env.exception.vaddress, ARMCPU), | |
e720677e PB |
318 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), |
319 | VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), | |
543486db | 320 | VMSTATE_BOOL(powered_off, ARMCPU), |
3cc1d208 JQ |
321 | VMSTATE_END_OF_LIST() |
322 | }, | |
5cd8cada JQ |
323 | .subsections = (const VMStateDescription*[]) { |
324 | &vmstate_vfp, | |
325 | &vmstate_iwmmxt, | |
326 | &vmstate_m, | |
327 | &vmstate_thumb2ee, | |
6cb0b013 | 328 | &vmstate_pmsav7, |
5cd8cada | 329 | NULL |
ffe47d33 | 330 | } |
3cc1d208 | 331 | }; |
a7bf3034 PF |
332 | |
333 | const char *gicv3_class_name(void) | |
334 | { | |
335 | if (kvm_irqchip_in_kernel()) { | |
336 | #ifdef TARGET_AARCH64 | |
337 | return "kvm-arm-gicv3"; | |
338 | #else | |
339 | error_report("KVM GICv3 acceleration is not supported on this " | |
340 | "platform\n"); | |
341 | #endif | |
342 | } else { | |
343 | /* TODO: Software emulation is not implemented yet */ | |
344 | error_report("KVM is currently required for GICv3 emulation\n"); | |
345 | } | |
346 | ||
347 | exit(1); | |
348 | } |