blob: 09fb34a298039c50d04bf107eb295b685f80964a [file] [log] [blame]
aurel328dd3dca2008-05-04 13:11:44 +00001#include "hw/hw.h"
2#include "hw/boards.h"
Peter Maydellff047452013-06-25 18:16:07 +01003#include "sysemu/kvm.h"
4#include "kvm_arm.h"
aurel328dd3dca2008-05-04 13:11:44 +00005
Juan Quintela3cc1d202013-04-19 12:24:19 +01006static bool vfp_needed(void *opaque)
aurel328dd3dca2008-05-04 13:11:44 +00007{
Juan Quintela3cc1d202013-04-19 12:24:19 +01008 ARMCPU *cpu = opaque;
9 CPUARMState *env = &cpu->env;
aurel328dd3dca2008-05-04 13:11:44 +000010
Juan Quintela3cc1d202013-04-19 12:24:19 +010011 return arm_feature(env, ARM_FEATURE_VFP);
aurel328dd3dca2008-05-04 13:11:44 +000012}
13
Peter Maydelle91f2292013-04-19 12:24:19 +010014static int get_fpscr(QEMUFile *f, void *opaque, size_t size)
15{
16 ARMCPU *cpu = opaque;
17 CPUARMState *env = &cpu->env;
18 uint32_t val = qemu_get_be32(f);
19
20 vfp_set_fpscr(env, val);
21 return 0;
22}
23
24static void put_fpscr(QEMUFile *f, void *opaque, size_t size)
25{
26 ARMCPU *cpu = opaque;
27 CPUARMState *env = &cpu->env;
28
29 qemu_put_be32(f, vfp_get_fpscr(env));
30}
31
32static const VMStateInfo vmstate_fpscr = {
33 .name = "fpscr",
34 .get = get_fpscr,
35 .put = put_fpscr,
36};
37
Juan Quintela3cc1d202013-04-19 12:24:19 +010038static const VMStateDescription vmstate_vfp = {
39 .name = "cpu/vfp",
Alexander Graf3926cc82013-09-03 20:12:09 +010040 .version_id = 3,
41 .minimum_version_id = 3,
42 .minimum_version_id_old = 3,
Juan Quintela3cc1d202013-04-19 12:24:19 +010043 .fields = (VMStateField[]) {
Alexander Graf3926cc82013-09-03 20:12:09 +010044 VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64),
Peter Maydelle91f2292013-04-19 12:24:19 +010045 /* The xregs array is a little awkward because element 1 (FPSCR)
46 * requires a specific accessor, so we have to split it up in
47 * the vmstate:
48 */
49 VMSTATE_UINT32(env.vfp.xregs[0], ARMCPU),
50 VMSTATE_UINT32_SUB_ARRAY(env.vfp.xregs, ARMCPU, 2, 14),
51 {
52 .name = "fpscr",
53 .version_id = 0,
54 .size = sizeof(uint32_t),
55 .info = &vmstate_fpscr,
56 .flags = VMS_SINGLE,
57 .offset = 0,
58 },
Juan Quintela3cc1d202013-04-19 12:24:19 +010059 VMSTATE_END_OF_LIST()
aurel328dd3dca2008-05-04 13:11:44 +000060 }
Juan Quintela3cc1d202013-04-19 12:24:19 +010061};
62
63static bool iwmmxt_needed(void *opaque)
64{
65 ARMCPU *cpu = opaque;
66 CPUARMState *env = &cpu->env;
67
68 return arm_feature(env, ARM_FEATURE_IWMMXT);
69}
70
71static const VMStateDescription vmstate_iwmmxt = {
72 .name = "cpu/iwmmxt",
73 .version_id = 1,
74 .minimum_version_id = 1,
75 .minimum_version_id_old = 1,
76 .fields = (VMStateField[]) {
77 VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16),
78 VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16),
79 VMSTATE_END_OF_LIST()
80 }
81};
82
83static bool m_needed(void *opaque)
84{
85 ARMCPU *cpu = opaque;
86 CPUARMState *env = &cpu->env;
87
88 return arm_feature(env, ARM_FEATURE_M);
89}
90
Stefan Weil6df05bd2014-03-16 19:07:55 +010091static const VMStateDescription vmstate_m = {
Juan Quintela3cc1d202013-04-19 12:24:19 +010092 .name = "cpu/m",
93 .version_id = 1,
94 .minimum_version_id = 1,
95 .minimum_version_id_old = 1,
96 .fields = (VMStateField[]) {
97 VMSTATE_UINT32(env.v7m.other_sp, ARMCPU),
98 VMSTATE_UINT32(env.v7m.vecbase, ARMCPU),
99 VMSTATE_UINT32(env.v7m.basepri, ARMCPU),
100 VMSTATE_UINT32(env.v7m.control, ARMCPU),
101 VMSTATE_INT32(env.v7m.current_sp, ARMCPU),
102 VMSTATE_INT32(env.v7m.exception, ARMCPU),
103 VMSTATE_END_OF_LIST()
104 }
105};
106
107static bool thumb2ee_needed(void *opaque)
108{
109 ARMCPU *cpu = opaque;
110 CPUARMState *env = &cpu->env;
111
112 return arm_feature(env, ARM_FEATURE_THUMB2EE);
113}
114
115static const VMStateDescription vmstate_thumb2ee = {
116 .name = "cpu/thumb2ee",
117 .version_id = 1,
118 .minimum_version_id = 1,
119 .minimum_version_id_old = 1,
120 .fields = (VMStateField[]) {
121 VMSTATE_UINT32(env.teecr, ARMCPU),
122 VMSTATE_UINT32(env.teehbr, ARMCPU),
123 VMSTATE_END_OF_LIST()
124 }
125};
126
127static int get_cpsr(QEMUFile *f, void *opaque, size_t size)
128{
129 ARMCPU *cpu = opaque;
130 CPUARMState *env = &cpu->env;
131 uint32_t val = qemu_get_be32(f);
132
Peter Maydell7a626612014-04-10 15:09:13 +0100133 if (arm_feature(env, ARM_FEATURE_AARCH64)
134 && !(val & PSTATE_nRW)) {
135 pstate_write(env, val);
136 return 0;
137 }
138 env->aarch64 = 0;
Juan Quintela3cc1d202013-04-19 12:24:19 +0100139 /* Avoid mode switch when restoring CPSR */
Paul Brookffe47d32009-07-30 13:33:47 +0100140 env->uncached_cpsr = val & CPSR_M;
141 cpsr_write(env, val, 0xffffffff);
aurel328dd3dca2008-05-04 13:11:44 +0000142 return 0;
143}
Juan Quintela3cc1d202013-04-19 12:24:19 +0100144
145static void put_cpsr(QEMUFile *f, void *opaque, size_t size)
146{
147 ARMCPU *cpu = opaque;
148 CPUARMState *env = &cpu->env;
Peter Maydell7a626612014-04-10 15:09:13 +0100149 uint32_t val;
Juan Quintela3cc1d202013-04-19 12:24:19 +0100150
Peter Maydell7a626612014-04-10 15:09:13 +0100151 if (arm_feature(env, ARM_FEATURE_AARCH64)
152 && is_a64(env)) {
153 val = pstate_read(env);
154 } else {
155 val = cpsr_read(env);
156 }
157
158 qemu_put_be32(f, val);
Juan Quintela3cc1d202013-04-19 12:24:19 +0100159}
160
161static const VMStateInfo vmstate_cpsr = {
162 .name = "cpsr",
163 .get = get_cpsr,
164 .put = put_cpsr,
165};
166
Peter Maydell721fae12013-06-25 18:16:07 +0100167static void cpu_pre_save(void *opaque)
168{
169 ARMCPU *cpu = opaque;
170
Peter Maydellff047452013-06-25 18:16:07 +0100171 if (kvm_enabled()) {
172 if (!write_kvmstate_to_list(cpu)) {
173 /* This should never fail */
174 abort();
175 }
176 } else {
177 if (!write_cpustate_to_list(cpu)) {
178 /* This should never fail. */
179 abort();
180 }
Peter Maydell721fae12013-06-25 18:16:07 +0100181 }
182
183 cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
184 memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
185 cpu->cpreg_array_len * sizeof(uint64_t));
186 memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
187 cpu->cpreg_array_len * sizeof(uint64_t));
188}
189
190static int cpu_post_load(void *opaque, int version_id)
191{
192 ARMCPU *cpu = opaque;
193 int i, v;
194
195 /* Update the values list from the incoming migration data.
196 * Anything in the incoming data which we don't know about is
197 * a migration failure; anything we know about but the incoming
198 * data doesn't specify retains its current (reset) value.
199 * The indexes list remains untouched -- we only inspect the
200 * incoming migration index list so we can match the values array
201 * entries with the right slots in our own values array.
202 */
203
204 for (i = 0, v = 0; i < cpu->cpreg_array_len
205 && v < cpu->cpreg_vmstate_array_len; i++) {
206 if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
207 /* register in our list but not incoming : skip it */
208 continue;
209 }
210 if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
211 /* register in their list but not ours: fail migration */
212 return -1;
213 }
214 /* matching register, copy the value over */
215 cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v];
216 v++;
217 }
218
Peter Maydellff047452013-06-25 18:16:07 +0100219 if (kvm_enabled()) {
220 if (!write_list_to_kvmstate(cpu)) {
221 return -1;
222 }
223 /* Note that it's OK for the TCG side not to know about
224 * every register in the list; KVM is authoritative if
225 * we're using it.
226 */
227 write_list_to_cpustate(cpu);
228 } else {
229 if (!write_list_to_cpustate(cpu)) {
230 return -1;
231 }
Peter Maydell721fae12013-06-25 18:16:07 +0100232 }
233
234 return 0;
235}
236
Juan Quintela3cc1d202013-04-19 12:24:19 +0100237const VMStateDescription vmstate_arm_cpu = {
238 .name = "cpu",
Peter Maydell7a626612014-04-10 15:09:13 +0100239 .version_id = 18,
240 .minimum_version_id = 18,
241 .minimum_version_id_old = 18,
Peter Maydell721fae12013-06-25 18:16:07 +0100242 .pre_save = cpu_pre_save,
243 .post_load = cpu_post_load,
Juan Quintela3cc1d202013-04-19 12:24:19 +0100244 .fields = (VMStateField[]) {
245 VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
Peter Maydell7a626612014-04-10 15:09:13 +0100246 VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32),
247 VMSTATE_UINT64(env.pc, ARMCPU),
Juan Quintela3cc1d202013-04-19 12:24:19 +0100248 {
249 .name = "cpsr",
250 .version_id = 0,
251 .size = sizeof(uint32_t),
252 .info = &vmstate_cpsr,
253 .flags = VMS_SINGLE,
254 .offset = 0,
255 },
256 VMSTATE_UINT32(env.spsr, ARMCPU),
Peter Maydella65f1de2014-04-15 19:18:43 +0100257 VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
Juan Quintela3cc1d202013-04-19 12:24:19 +0100258 VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
259 VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
260 VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
261 VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
Peter Maydella0618a12014-04-15 19:18:42 +0100262 VMSTATE_UINT64(env.elr_el1, ARMCPU),
Peter Maydellf502cfc2014-04-15 19:18:43 +0100263 VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
Peter Maydell721fae12013-06-25 18:16:07 +0100264 /* The length-check must come before the arrays to avoid
265 * incoming data possibly overflowing the array.
266 */
267 VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU),
268 VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
269 cpreg_vmstate_array_len,
270 0, vmstate_info_uint64, uint64_t),
271 VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU,
272 cpreg_vmstate_array_len,
273 0, vmstate_info_uint64, uint64_t),
Peter Maydell03d05e22014-01-04 22:15:47 +0000274 VMSTATE_UINT64(env.exclusive_addr, ARMCPU),
275 VMSTATE_UINT64(env.exclusive_val, ARMCPU),
276 VMSTATE_UINT64(env.exclusive_high, ARMCPU),
Juan Quintela3cc1d202013-04-19 12:24:19 +0100277 VMSTATE_UINT64(env.features, ARMCPU),
Peter Maydellabf11722014-04-15 19:18:38 +0100278 VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
279 VMSTATE_UINT32(env.exception.fsr, ARMCPU),
280 VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
Peter Maydell55d284a2013-08-20 14:54:31 +0100281 VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
282 VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
Juan Quintela3cc1d202013-04-19 12:24:19 +0100283 VMSTATE_END_OF_LIST()
284 },
285 .subsections = (VMStateSubsection[]) {
286 {
287 .vmsd = &vmstate_vfp,
288 .needed = vfp_needed,
289 } , {
290 .vmsd = &vmstate_iwmmxt,
291 .needed = iwmmxt_needed,
292 } , {
293 .vmsd = &vmstate_m,
294 .needed = m_needed,
295 } , {
296 .vmsd = &vmstate_thumb2ee,
297 .needed = thumb2ee_needed,
298 } , {
299 /* empty */
300 }
301 }
302};