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 | |
| 91 | const VMStateDescription vmstate_m = { |
| 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 | |
| 133 | /* Avoid mode switch when restoring CPSR */ |
Paul Brook | ffe47d3 | 2009-07-30 13:33:47 +0100 | [diff] [blame] | 134 | env->uncached_cpsr = val & CPSR_M; |
| 135 | cpsr_write(env, val, 0xffffffff); |
aurel32 | 8dd3dca | 2008-05-04 13:11:44 +0000 | [diff] [blame] | 136 | return 0; |
| 137 | } |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 138 | |
| 139 | static void put_cpsr(QEMUFile *f, void *opaque, size_t size) |
| 140 | { |
| 141 | ARMCPU *cpu = opaque; |
| 142 | CPUARMState *env = &cpu->env; |
| 143 | |
| 144 | qemu_put_be32(f, cpsr_read(env)); |
| 145 | } |
| 146 | |
| 147 | static const VMStateInfo vmstate_cpsr = { |
| 148 | .name = "cpsr", |
| 149 | .get = get_cpsr, |
| 150 | .put = put_cpsr, |
| 151 | }; |
| 152 | |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 153 | static void cpu_pre_save(void *opaque) |
| 154 | { |
| 155 | ARMCPU *cpu = opaque; |
| 156 | |
Peter Maydell | ff04745 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 157 | if (kvm_enabled()) { |
| 158 | if (!write_kvmstate_to_list(cpu)) { |
| 159 | /* This should never fail */ |
| 160 | abort(); |
| 161 | } |
| 162 | } else { |
| 163 | if (!write_cpustate_to_list(cpu)) { |
| 164 | /* This should never fail. */ |
| 165 | abort(); |
| 166 | } |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; |
| 170 | memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, |
| 171 | cpu->cpreg_array_len * sizeof(uint64_t)); |
| 172 | memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, |
| 173 | cpu->cpreg_array_len * sizeof(uint64_t)); |
| 174 | } |
| 175 | |
| 176 | static int cpu_post_load(void *opaque, int version_id) |
| 177 | { |
| 178 | ARMCPU *cpu = opaque; |
| 179 | int i, v; |
| 180 | |
| 181 | /* Update the values list from the incoming migration data. |
| 182 | * Anything in the incoming data which we don't know about is |
| 183 | * a migration failure; anything we know about but the incoming |
| 184 | * data doesn't specify retains its current (reset) value. |
| 185 | * The indexes list remains untouched -- we only inspect the |
| 186 | * incoming migration index list so we can match the values array |
| 187 | * entries with the right slots in our own values array. |
| 188 | */ |
| 189 | |
| 190 | for (i = 0, v = 0; i < cpu->cpreg_array_len |
| 191 | && v < cpu->cpreg_vmstate_array_len; i++) { |
| 192 | if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) { |
| 193 | /* register in our list but not incoming : skip it */ |
| 194 | continue; |
| 195 | } |
| 196 | if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { |
| 197 | /* register in their list but not ours: fail migration */ |
| 198 | return -1; |
| 199 | } |
| 200 | /* matching register, copy the value over */ |
| 201 | cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v]; |
| 202 | v++; |
| 203 | } |
| 204 | |
Peter Maydell | ff04745 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 205 | if (kvm_enabled()) { |
| 206 | if (!write_list_to_kvmstate(cpu)) { |
| 207 | return -1; |
| 208 | } |
| 209 | /* Note that it's OK for the TCG side not to know about |
| 210 | * every register in the list; KVM is authoritative if |
| 211 | * we're using it. |
| 212 | */ |
| 213 | write_list_to_cpustate(cpu); |
| 214 | } else { |
| 215 | if (!write_list_to_cpustate(cpu)) { |
| 216 | return -1; |
| 217 | } |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | return 0; |
| 221 | } |
| 222 | |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 223 | const VMStateDescription vmstate_arm_cpu = { |
| 224 | .name = "cpu", |
Peter Maydell | 55d284a | 2013-08-20 14:54:31 +0100 | [diff] [blame] | 225 | .version_id = 13, |
| 226 | .minimum_version_id = 13, |
| 227 | .minimum_version_id_old = 13, |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 228 | .pre_save = cpu_pre_save, |
| 229 | .post_load = cpu_post_load, |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 230 | .fields = (VMStateField[]) { |
| 231 | VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), |
| 232 | { |
| 233 | .name = "cpsr", |
| 234 | .version_id = 0, |
| 235 | .size = sizeof(uint32_t), |
| 236 | .info = &vmstate_cpsr, |
| 237 | .flags = VMS_SINGLE, |
| 238 | .offset = 0, |
| 239 | }, |
| 240 | VMSTATE_UINT32(env.spsr, ARMCPU), |
| 241 | VMSTATE_UINT32_ARRAY(env.banked_spsr, ARMCPU, 6), |
| 242 | VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6), |
| 243 | VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6), |
| 244 | VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5), |
| 245 | VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5), |
Peter Maydell | 721fae1 | 2013-06-25 18:16:07 +0100 | [diff] [blame] | 246 | /* The length-check must come before the arrays to avoid |
| 247 | * incoming data possibly overflowing the array. |
| 248 | */ |
| 249 | VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU), |
| 250 | VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, |
| 251 | cpreg_vmstate_array_len, |
| 252 | 0, vmstate_info_uint64, uint64_t), |
| 253 | VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU, |
| 254 | cpreg_vmstate_array_len, |
| 255 | 0, vmstate_info_uint64, uint64_t), |
Peter Maydell | 602131e | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 256 | VMSTATE_UINT32(env.exclusive_addr, ARMCPU), |
| 257 | VMSTATE_UINT32(env.exclusive_val, ARMCPU), |
| 258 | VMSTATE_UINT32(env.exclusive_high, ARMCPU), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 259 | VMSTATE_UINT64(env.features, ARMCPU), |
Peter Maydell | 55d284a | 2013-08-20 14:54:31 +0100 | [diff] [blame] | 260 | VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), |
| 261 | VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), |
Juan Quintela | 3cc1d20 | 2013-04-19 12:24:19 +0100 | [diff] [blame] | 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 | } |
| 280 | } |
| 281 | }; |