#include "cpu.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
#include "kvm_arm.h"
#include "internals.h"
+#include "cpu-features.h"
#include "migration/cpu.h"
+#include "target/arm/gtimer.h"
static bool vfp_needed(void *opaque)
{
ARMCPU *cpu = opaque;
- CPUARMState *env = &cpu->env;
- return arm_feature(env, ARM_FEATURE_VFP);
+ return (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
+ ? cpu_isar_feature(aa64_fp_simd, cpu)
+ : cpu_isar_feature(aa32_vfp_simd, cpu));
}
static int get_fpscr(QEMUFile *f, void *opaque, size_t size,
}
static int put_fpscr(QEMUFile *f, void *opaque, size_t size,
- const VMStateField *field, QJSON *vmdesc)
+ const VMStateField *field, JSONWriter *vmdesc)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
.version_id = 3,
.minimum_version_id = 3,
.needed = vfp_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
/* For compatibility, store Qn out of Zn here. */
VMSTATE_UINT64_SUB_ARRAY(env.vfp.zregs[0].d, ARMCPU, 0, 2),
VMSTATE_UINT64_SUB_ARRAY(env.vfp.zregs[1].d, ARMCPU, 0, 2),
.version_id = 1,
.minimum_version_id = 1,
.needed = iwmmxt_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16),
VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16),
VMSTATE_END_OF_LIST()
.name = "cpu/sve/zreg_hi",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT64_SUB_ARRAY(d, ARMVectorReg, 2, ARM_MAX_VQ - 2),
VMSTATE_END_OF_LIST()
}
.name = "cpu/sve/preg",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT64_ARRAY(p, ARMPredicateReg, 2 * ARM_MAX_VQ / 8),
VMSTATE_END_OF_LIST()
}
.version_id = 1,
.minimum_version_id = 1,
.needed = sve_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_STRUCT_ARRAY(env.vfp.zregs, ARMCPU, 32, 0,
vmstate_zreg_hi_reg, ARMVectorReg),
VMSTATE_STRUCT_ARRAY(env.vfp.pregs, ARMCPU, 17, 0,
VMSTATE_END_OF_LIST()
}
};
+
+static const VMStateDescription vmstate_vreg = {
+ .name = "vreg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64_ARRAY(d, ARMVectorReg, ARM_MAX_VQ * 2),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool za_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ /*
+ * When ZA storage is disabled, its contents are discarded.
+ * It will be zeroed when ZA storage is re-enabled.
+ */
+ return FIELD_EX64(cpu->env.svcr, SVCR, ZA);
+}
+
+static const VMStateDescription vmstate_za = {
+ .name = "cpu/sme",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = za_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(env.zarray, ARMCPU, ARM_MAX_VQ * 16, 0,
+ vmstate_vreg, ARMVectorReg),
+ VMSTATE_END_OF_LIST()
+ }
+};
#endif /* AARCH64 */
static bool serror_needed(void *opaque)
.version_id = 1,
.minimum_version_id = 1,
.needed = serror_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8(env.serror.pending, ARMCPU),
VMSTATE_UINT8(env.serror.has_esr, ARMCPU),
VMSTATE_UINT64(env.serror.esr, ARMCPU),
.version_id = 1,
.minimum_version_id = 1,
.needed = irq_line_state_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.irq_line_state, ARMCPU),
VMSTATE_END_OF_LIST()
}
.version_id = 1,
.minimum_version_id = 1,
.needed = m_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.v7m.faultmask[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.primask[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
.version_id = 1,
.minimum_version_id = 1,
.needed = m_csselr_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.v7m.csselr, ARMCPU, M_REG_NUM_BANKS),
VMSTATE_VALIDATE("CSSELR is valid", csselr_vmstate_validate),
VMSTATE_END_OF_LIST()
.version_id = 1,
.minimum_version_id = 1,
.needed = m_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.v7m.scr[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
}
.version_id = 1,
.minimum_version_id = 1,
.needed = m_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.v7m.other_sp, ARMCPU),
VMSTATE_END_OF_LIST()
}
.version_id = 1,
.minimum_version_id = 1,
.needed = m_v8m_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.v7m.msplim, ARMCPU, M_REG_NUM_BANKS),
VMSTATE_UINT32_ARRAY(env.v7m.psplim, ARMCPU, M_REG_NUM_BANKS),
VMSTATE_END_OF_LIST()
.version_id = 1,
.minimum_version_id = 1,
.needed = vfp_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.v7m.fpcar, ARMCPU, M_REG_NUM_BANKS),
VMSTATE_UINT32_ARRAY(env.v7m.fpccr, ARMCPU, M_REG_NUM_BANKS),
VMSTATE_UINT32_ARRAY(env.v7m.fpdscr, ARMCPU, M_REG_NUM_BANKS),
}
};
+static bool mve_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ return cpu_isar_feature(aa32_mve, cpu);
+}
+
+static const VMStateDescription vmstate_m_mve = {
+ .name = "cpu/m/mve",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = mve_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(env.v7m.vpr, ARMCPU),
+ VMSTATE_UINT32(env.v7m.ltpsize, ARMCPU),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_m = {
.name = "cpu/m",
.version_id = 4,
.minimum_version_id = 4,
.needed = m_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.v7m.vecbase[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.basepri[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.control[M_REG_NS], ARMCPU),
VMSTATE_INT32(env.v7m.exception, ARMCPU),
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription*[]) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_m_faultmask_primask,
&vmstate_m_csselr,
&vmstate_m_scr,
&vmstate_m_other_sp,
&vmstate_m_v8m,
&vmstate_m_fp,
+ &vmstate_m_mve,
NULL
}
};
.version_id = 1,
.minimum_version_id = 1,
.needed = thumb2ee_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.teecr, ARMCPU),
VMSTATE_UINT32(env.teehbr, ARMCPU),
VMSTATE_END_OF_LIST()
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav7_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0,
vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0,
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav7_rnr_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.pmsav7.rnr[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
}
arm_feature(env, ARM_FEATURE_V8);
}
+static bool pmsav8r_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+
+ return arm_feature(env, ARM_FEATURE_PMSA) &&
+ arm_feature(env, ARM_FEATURE_V8) &&
+ !arm_feature(env, ARM_FEATURE_M);
+}
+
+static const VMStateDescription vmstate_pmsav8r = {
+ .name = "cpu/pmsav8/pmsav8r",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pmsav8r_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(env.pmsav8.hprbar, ARMCPU,
+ pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(env.pmsav8.hprlar, ARMCPU,
+ pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_pmsav8 = {
.name = "cpu/pmsav8",
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav8_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_NS], ARMCPU, pmsav7_dregion,
0, vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_NS], ARMCPU, pmsav7_dregion,
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_pmsav8r,
+ NULL
}
};
.version_id = 1,
.minimum_version_id = 1,
.needed = m_security_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(env.v7m.secure, ARMCPU),
VMSTATE_UINT32(env.v7m.other_ss_msp, ARMCPU),
VMSTATE_UINT32(env.v7m.other_ss_psp, ARMCPU),
}
static int put_cpsr(QEMUFile *f, void *opaque, size_t size,
- const VMStateField *field, QJSON *vmdesc)
+ const VMStateField *field, JSONWriter *vmdesc)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
}
static int put_power(QEMUFile *f, void *opaque, size_t size,
- const VMStateField *field, QJSON *vmdesc)
+ const VMStateField *field, JSONWriter *vmdesc)
{
ARMCPU *cpu = opaque;
if (kvm_enabled()) {
if (!write_kvmstate_to_list(cpu)) {
/* This should never fail */
- abort();
+ g_assert_not_reached();
}
/*
} else {
if (!write_cpustate_to_list(cpu, false)) {
/* This should never fail. */
- abort();
+ g_assert_not_reached();
}
}
}
}
- hw_breakpoint_update_all(cpu);
- hw_watchpoint_update_all(cpu);
+ /*
+ * Misaligned thumb pc is architecturally impossible. Fail the
+ * incoming migration. For TCG it would trigger the assert in
+ * thumb_tr_translate_insn().
+ */
+ if (!is_a64(env) && env->thumb && (env->regs[15] & 1)) {
+ return -1;
+ }
+
+ if (tcg_enabled()) {
+ hw_breakpoint_update_all(cpu);
+ hw_watchpoint_update_all(cpu);
+ }
+
+ /*
+ * TCG gen_update_fp_context() relies on the invariant that
+ * FPDSCR.LTPSIZE is constant 4 for M-profile with the LOB extension;
+ * forbid bogus incoming data with some other value.
+ */
+ if (arm_feature(env, ARM_FEATURE_M) && cpu_isar_feature(aa32_lob, cpu)) {
+ if (extract32(env->v7m.fpdscr[M_REG_NS],
+ FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4 ||
+ extract32(env->v7m.fpdscr[M_REG_S],
+ FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4) {
+ return -1;
+ }
+ }
if (!kvm_enabled()) {
pmu_op_finish(&cpu->env);
}
- arm_rebuild_hflags(&cpu->env);
+
+ if (tcg_enabled()) {
+ arm_rebuild_hflags(&cpu->env);
+ }
return 0;
}
.post_save = cpu_post_save,
.pre_load = cpu_pre_load,
.post_load = cpu_post_load,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32),
VMSTATE_UINT64(env.pc, ARMCPU),
VMSTATE_UINT64(env.exclusive_addr, ARMCPU),
VMSTATE_UINT64(env.exclusive_val, ARMCPU),
VMSTATE_UINT64(env.exclusive_high, ARMCPU),
- VMSTATE_UINT64(env.features, ARMCPU),
+ VMSTATE_UNUSED(sizeof(uint64_t)),
VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
},
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription*[]) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_vfp,
&vmstate_iwmmxt,
&vmstate_m,
&vmstate_m_security,
#ifdef TARGET_AARCH64
&vmstate_sve,
+ &vmstate_za,
#endif
&vmstate_serror,
&vmstate_irq_line_state,