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