]>
Commit | Line | Data |
---|---|---|
8dd3dca3 AJ |
1 | #include "hw/hw.h" |
2 | #include "hw/boards.h" | |
ff047453 PM |
3 | #include "sysemu/kvm.h" |
4 | #include "kvm_arm.h" | |
8dd3dca3 | 5 | |
3cc1d208 | 6 | static bool vfp_needed(void *opaque) |
8dd3dca3 | 7 | { |
3cc1d208 JQ |
8 | ARMCPU *cpu = opaque; |
9 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 10 | |
3cc1d208 JQ |
11 | return arm_feature(env, ARM_FEATURE_VFP); |
12 | } | |
8dd3dca3 | 13 | |
e91f229a PM |
14 | static 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 | ||
24 | static 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 | ||
32 | static const VMStateInfo vmstate_fpscr = { | |
33 | .name = "fpscr", | |
34 | .get = get_fpscr, | |
35 | .put = put_fpscr, | |
36 | }; | |
37 | ||
3cc1d208 JQ |
38 | static const VMStateDescription vmstate_vfp = { |
39 | .name = "cpu/vfp", | |
3926cc84 AG |
40 | .version_id = 3, |
41 | .minimum_version_id = 3, | |
3cc1d208 | 42 | .fields = (VMStateField[]) { |
3926cc84 | 43 | VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64), |
e91f229a PM |
44 | /* The xregs array is a little awkward because element 1 (FPSCR) |
45 | * requires a specific accessor, so we have to split it up in | |
46 | * the vmstate: | |
47 | */ | |
48 | VMSTATE_UINT32(env.vfp.xregs[0], ARMCPU), | |
49 | VMSTATE_UINT32_SUB_ARRAY(env.vfp.xregs, ARMCPU, 2, 14), | |
50 | { | |
51 | .name = "fpscr", | |
52 | .version_id = 0, | |
53 | .size = sizeof(uint32_t), | |
54 | .info = &vmstate_fpscr, | |
55 | .flags = VMS_SINGLE, | |
56 | .offset = 0, | |
57 | }, | |
3cc1d208 | 58 | VMSTATE_END_OF_LIST() |
8dd3dca3 | 59 | } |
3cc1d208 | 60 | }; |
8dd3dca3 | 61 | |
3cc1d208 JQ |
62 | static bool iwmmxt_needed(void *opaque) |
63 | { | |
64 | ARMCPU *cpu = opaque; | |
65 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 66 | |
3cc1d208 JQ |
67 | return arm_feature(env, ARM_FEATURE_IWMMXT); |
68 | } | |
ffe47d33 | 69 | |
3cc1d208 JQ |
70 | static const VMStateDescription vmstate_iwmmxt = { |
71 | .name = "cpu/iwmmxt", | |
72 | .version_id = 1, | |
73 | .minimum_version_id = 1, | |
3cc1d208 JQ |
74 | .fields = (VMStateField[]) { |
75 | VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16), | |
76 | VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16), | |
77 | VMSTATE_END_OF_LIST() | |
ffe47d33 | 78 | } |
3cc1d208 JQ |
79 | }; |
80 | ||
81 | static bool m_needed(void *opaque) | |
82 | { | |
83 | ARMCPU *cpu = opaque; | |
84 | CPUARMState *env = &cpu->env; | |
85 | ||
86 | return arm_feature(env, ARM_FEATURE_M); | |
8dd3dca3 AJ |
87 | } |
88 | ||
6df05bdd | 89 | static const VMStateDescription vmstate_m = { |
3cc1d208 JQ |
90 | .name = "cpu/m", |
91 | .version_id = 1, | |
92 | .minimum_version_id = 1, | |
3cc1d208 JQ |
93 | .fields = (VMStateField[]) { |
94 | VMSTATE_UINT32(env.v7m.other_sp, ARMCPU), | |
95 | VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), | |
96 | VMSTATE_UINT32(env.v7m.basepri, ARMCPU), | |
97 | VMSTATE_UINT32(env.v7m.control, ARMCPU), | |
98 | VMSTATE_INT32(env.v7m.current_sp, ARMCPU), | |
99 | VMSTATE_INT32(env.v7m.exception, ARMCPU), | |
100 | VMSTATE_END_OF_LIST() | |
101 | } | |
102 | }; | |
103 | ||
104 | static bool thumb2ee_needed(void *opaque) | |
8dd3dca3 | 105 | { |
3cc1d208 JQ |
106 | ARMCPU *cpu = opaque; |
107 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 108 | |
3cc1d208 JQ |
109 | return arm_feature(env, ARM_FEATURE_THUMB2EE); |
110 | } | |
8dd3dca3 | 111 | |
3cc1d208 JQ |
112 | static const VMStateDescription vmstate_thumb2ee = { |
113 | .name = "cpu/thumb2ee", | |
114 | .version_id = 1, | |
115 | .minimum_version_id = 1, | |
3cc1d208 JQ |
116 | .fields = (VMStateField[]) { |
117 | VMSTATE_UINT32(env.teecr, ARMCPU), | |
118 | VMSTATE_UINT32(env.teehbr, ARMCPU), | |
119 | VMSTATE_END_OF_LIST() | |
8dd3dca3 | 120 | } |
3cc1d208 JQ |
121 | }; |
122 | ||
123 | static int get_cpsr(QEMUFile *f, void *opaque, size_t size) | |
124 | { | |
125 | ARMCPU *cpu = opaque; | |
126 | CPUARMState *env = &cpu->env; | |
127 | uint32_t val = qemu_get_be32(f); | |
128 | ||
129 | /* Avoid mode switch when restoring CPSR */ | |
ffe47d33 PB |
130 | env->uncached_cpsr = val & CPSR_M; |
131 | cpsr_write(env, val, 0xffffffff); | |
3cc1d208 JQ |
132 | return 0; |
133 | } | |
8dd3dca3 | 134 | |
3cc1d208 JQ |
135 | static void put_cpsr(QEMUFile *f, void *opaque, size_t size) |
136 | { | |
137 | ARMCPU *cpu = opaque; | |
138 | CPUARMState *env = &cpu->env; | |
8dd3dca3 | 139 | |
3cc1d208 JQ |
140 | qemu_put_be32(f, cpsr_read(env)); |
141 | } | |
8dd3dca3 | 142 | |
3cc1d208 JQ |
143 | static const VMStateInfo vmstate_cpsr = { |
144 | .name = "cpsr", | |
145 | .get = get_cpsr, | |
146 | .put = put_cpsr, | |
147 | }; | |
148 | ||
721fae12 PM |
149 | static void cpu_pre_save(void *opaque) |
150 | { | |
151 | ARMCPU *cpu = opaque; | |
152 | ||
ff047453 PM |
153 | if (kvm_enabled()) { |
154 | if (!write_kvmstate_to_list(cpu)) { | |
155 | /* This should never fail */ | |
156 | abort(); | |
157 | } | |
158 | } else { | |
159 | if (!write_cpustate_to_list(cpu)) { | |
160 | /* This should never fail. */ | |
161 | abort(); | |
162 | } | |
721fae12 PM |
163 | } |
164 | ||
165 | cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; | |
166 | memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, | |
167 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
168 | memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, | |
169 | cpu->cpreg_array_len * sizeof(uint64_t)); | |
170 | } | |
171 | ||
172 | static int cpu_post_load(void *opaque, int version_id) | |
173 | { | |
174 | ARMCPU *cpu = opaque; | |
175 | int i, v; | |
176 | ||
177 | /* Update the values list from the incoming migration data. | |
178 | * Anything in the incoming data which we don't know about is | |
179 | * a migration failure; anything we know about but the incoming | |
180 | * data doesn't specify retains its current (reset) value. | |
181 | * The indexes list remains untouched -- we only inspect the | |
182 | * incoming migration index list so we can match the values array | |
183 | * entries with the right slots in our own values array. | |
184 | */ | |
185 | ||
186 | for (i = 0, v = 0; i < cpu->cpreg_array_len | |
187 | && v < cpu->cpreg_vmstate_array_len; i++) { | |
188 | if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) { | |
189 | /* register in our list but not incoming : skip it */ | |
190 | continue; | |
191 | } | |
192 | if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { | |
193 | /* register in their list but not ours: fail migration */ | |
194 | return -1; | |
195 | } | |
196 | /* matching register, copy the value over */ | |
197 | cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v]; | |
198 | v++; | |
199 | } | |
200 | ||
ff047453 PM |
201 | if (kvm_enabled()) { |
202 | if (!write_list_to_kvmstate(cpu)) { | |
203 | return -1; | |
204 | } | |
205 | /* Note that it's OK for the TCG side not to know about | |
206 | * every register in the list; KVM is authoritative if | |
207 | * we're using it. | |
208 | */ | |
209 | write_list_to_cpustate(cpu); | |
210 | } else { | |
211 | if (!write_list_to_cpustate(cpu)) { | |
212 | return -1; | |
213 | } | |
721fae12 PM |
214 | } |
215 | ||
216 | return 0; | |
217 | } | |
218 | ||
3cc1d208 JQ |
219 | const VMStateDescription vmstate_arm_cpu = { |
220 | .name = "cpu", | |
28c9457d EI |
221 | .version_id = 20, |
222 | .minimum_version_id = 20, | |
721fae12 PM |
223 | .pre_save = cpu_pre_save, |
224 | .post_load = cpu_post_load, | |
3cc1d208 JQ |
225 | .fields = (VMStateField[]) { |
226 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), | |
227 | { | |
228 | .name = "cpsr", | |
229 | .version_id = 0, | |
230 | .size = sizeof(uint32_t), | |
231 | .info = &vmstate_cpsr, | |
232 | .flags = VMS_SINGLE, | |
233 | .offset = 0, | |
234 | }, | |
235 | VMSTATE_UINT32(env.spsr, ARMCPU), | |
28c9457d | 236 | VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 8), |
3cc1d208 JQ |
237 | VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6), |
238 | VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6), | |
239 | VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), | |
240 | VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), | |
1b174238 | 241 | VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4), |
73fb3b76 | 242 | VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4), |
721fae12 PM |
243 | /* The length-check must come before the arrays to avoid |
244 | * incoming data possibly overflowing the array. | |
245 | */ | |
3476436a | 246 | VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU), |
721fae12 PM |
247 | VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, |
248 | cpreg_vmstate_array_len, | |
249 | 0, vmstate_info_uint64, uint64_t), | |
250 | VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU, | |
251 | cpreg_vmstate_array_len, | |
252 | 0, vmstate_info_uint64, uint64_t), | |
03d05e2d PM |
253 | VMSTATE_UINT64(env.exclusive_addr, ARMCPU), |
254 | VMSTATE_UINT64(env.exclusive_val, ARMCPU), | |
255 | VMSTATE_UINT64(env.exclusive_high, ARMCPU), | |
3cc1d208 | 256 | VMSTATE_UINT64(env.features, ARMCPU), |
abf1172f PM |
257 | VMSTATE_UINT32(env.exception.syndrome, ARMCPU), |
258 | VMSTATE_UINT32(env.exception.fsr, ARMCPU), | |
259 | VMSTATE_UINT64(env.exception.vaddress, ARMCPU), | |
55d284af PM |
260 | VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), |
261 | VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), | |
3cc1d208 JQ |
262 | VMSTATE_END_OF_LIST() |
263 | }, | |
264 | .subsections = (VMStateSubsection[]) { | |
265 | { | |
266 | .vmsd = &vmstate_vfp, | |
267 | .needed = vfp_needed, | |
268 | } , { | |
269 | .vmsd = &vmstate_iwmmxt, | |
270 | .needed = iwmmxt_needed, | |
271 | } , { | |
272 | .vmsd = &vmstate_m, | |
273 | .needed = m_needed, | |
274 | } , { | |
275 | .vmsd = &vmstate_thumb2ee, | |
276 | .needed = thumb2ee_needed, | |
277 | } , { | |
278 | /* empty */ | |
279 | } | |
ffe47d33 | 280 | } |
3cc1d208 | 281 | }; |