aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 1 | #include "hw/hw.h" |
| 2 | #include "hw/boards.h" |
Peter Maydell | ff04745 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 3 | #include "sysemu/kvm.h" |
| 4 | #include "kvm_arm.h" |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 5 | |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 6 | static bool vfp_needed(void *opaque) |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 7 | { |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 8 | ARMCPU *cpu = opaque; |
| 9 | CPUARMState *env = &cpu->env; |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 10 | |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 11 | return arm_feature(env, ARM_FEATURE_VFP); |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 12 | } |
| 13 | |
Peter Maydell | e91f229 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 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 | |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 38 | static const VMStateDescription vmstate_vfp = { |
| 39 | .name = "cpu/vfp", |
Alexander Graf | 3926cc8 | 2013-09-03 20:12:09 +0100 | [diff] [blame] | 40 | .version_id = 3, |
| 41 | .minimum_version_id = 3, |
| 42 | .minimum_version_id_old = 3, |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 43 | .fields = (VMStateField[]) { |
Alexander Graf | 3926cc8 | 2013-09-03 20:12:09 +0100 | [diff] [blame] | 44 | VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64), |
Peter Maydell | e91f229 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 45 | /* 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 Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 59 | VMSTATE_END_OF_LIST() |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 60 | } |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 61 | }; |
| 62 | |
| 63 | static 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 | |
| 71 | static 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 | |
| 83 | static 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 Weil | 6df05bd | 2014-03-16 19:07:55 +0100 | [diff] [blame] | 91 | static const VMStateDescription vmstate_m = { |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 92 | .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 | |
| 107 | static 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 | |
| 115 | static 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 | |
| 127 | static 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 Maydell | 7a62661 | 2014-04-10 15:09:13 +0100 | [diff] [blame] | 133 | 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 Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 139 | /* Avoid mode switch when restoring CPSR */ |
Paul Brook | ffe47d3 | 2009-07-30 13:33:47 +0100 | [diff] [blame] | 140 | env->uncached_cpsr = val & CPSR_M; |
| 141 | cpsr_write(env, val, 0xffffffff); |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 142 | return 0; |
| 143 | } |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 144 | |
| 145 | static void put_cpsr(QEMUFile *f, void *opaque, size_t size) |
| 146 | { |
| 147 | ARMCPU *cpu = opaque; |
| 148 | CPUARMState *env = &cpu->env; |
Peter Maydell | 7a62661 | 2014-04-10 15:09:13 +0100 | [diff] [blame] | 149 | uint32_t val; |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 150 | |
Peter Maydell | 7a62661 | 2014-04-10 15:09:13 +0100 | [diff] [blame] | 151 | 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 Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | static const VMStateInfo vmstate_cpsr = { |
| 162 | .name = "cpsr", |
| 163 | .get = get_cpsr, |
| 164 | .put = put_cpsr, |
| 165 | }; |
| 166 | |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 167 | static void cpu_pre_save(void *opaque) |
| 168 | { |
| 169 | ARMCPU *cpu = opaque; |
| 170 | |
Peter Maydell | ff04745 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 171 | 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 Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 181 | } |
| 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 | |
| 190 | static 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 Maydell | ff04745 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 219 | 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 Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | return 0; |
| 235 | } |
| 236 | |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 237 | const VMStateDescription vmstate_arm_cpu = { |
| 238 | .name = "cpu", |
Peter Maydell | 7a62661 | 2014-04-10 15:09:13 +0100 | [diff] [blame] | 239 | .version_id = 18, |
| 240 | .minimum_version_id = 18, |
| 241 | .minimum_version_id_old = 18, |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 242 | .pre_save = cpu_pre_save, |
| 243 | .post_load = cpu_post_load, |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 244 | .fields = (VMStateField[]) { |
| 245 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), |
Peter Maydell | 7a62661 | 2014-04-10 15:09:13 +0100 | [diff] [blame] | 246 | VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), |
| 247 | VMSTATE_UINT64(env.pc, ARMCPU), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 248 | { |
| 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 Maydell | a65f1de | 2014-04-15 19:18:43 +0100 | [diff] [blame] | 257 | VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 258 | 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 Maydell | a0618a1 | 2014-04-15 19:18:42 +0100 | [diff] [blame] | 262 | VMSTATE_UINT64(env.elr_el1, ARMCPU), |
Peter Maydell | f502cfc | 2014-04-15 19:18:43 +0100 | [diff] [blame] | 263 | VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2), |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 264 | /* 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 Maydell | 03d05e2 | 2014-01-04 22:15:47 +0000 | [diff] [blame] | 274 | VMSTATE_UINT64(env.exclusive_addr, ARMCPU), |
| 275 | VMSTATE_UINT64(env.exclusive_val, ARMCPU), |
| 276 | VMSTATE_UINT64(env.exclusive_high, ARMCPU), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 277 | VMSTATE_UINT64(env.features, ARMCPU), |
Peter Maydell | abf1172 | 2014-04-15 19:18:38 +0100 | [diff] [blame] | 278 | VMSTATE_UINT32(env.exception.syndrome, ARMCPU), |
| 279 | VMSTATE_UINT32(env.exception.fsr, ARMCPU), |
| 280 | VMSTATE_UINT64(env.exception.vaddress, ARMCPU), |
Peter Maydell | 55d284a | 2013-08-20 14:54:31 +0100 | [diff] [blame] | 281 | VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), |
| 282 | VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 283 | 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 | }; |