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