Message ID | 20210309142544.5020-23-cfontana@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm cleanup experiment for kvm-only build | expand |
On 3/9/21 3:25 PM, Claudio Fontana wrote: > just like we have cpu64.c for the 64bit cpu models, > spawn a cpu32.c from cpu.c. > > cpu.c will continue to contain the common parts. > > Note that we need to build cpu32 also for TARGET_AARCH64, > because qemu-system-aarch64 is supposed to be able to run > non-aarch64 cpus too. > > Signed-off-by: Claudio Fontana <cfontana@suse.de> > --- > target/arm/cpu-qom.h | 3 - > target/arm/cpu.h | 4 +- > target/arm/cpu32.h | 27 ++ > target/arm/cpu.c | 612 +---------------------------------------- > target/arm/cpu32.c | 516 ++++++++++++++++++++++++++++++++++ > target/arm/cpu64.c | 131 ++++++++- > target/arm/cpu_tcg.c | 3 +- > target/arm/gdbstub.c | 4 +- > target/arm/meson.build | 5 + > 9 files changed, 688 insertions(+), 617 deletions(-) > create mode 100644 target/arm/cpu32.h > create mode 100644 target/arm/cpu32.c > > diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h > index a22bd506d0..0d41a346b9 100644 > --- a/target/arm/cpu-qom.h > +++ b/target/arm/cpu-qom.h > @@ -38,9 +38,6 @@ typedef struct ARMCPUInfo { > void (*class_init)(ObjectClass *oc, void *data); > } ARMCPUInfo; > > -void arm_cpu_register(const ARMCPUInfo *info); > -void aarch64_cpu_register(const ARMCPUInfo *info); > - > /** > * ARMCPUClass: > * @parent_realize: The parent class' realize handler. > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > index 9293d90ffb..ea1e63f7f6 100644 > --- a/target/arm/cpu.h > +++ b/target/arm/cpu.h > @@ -1026,8 +1026,8 @@ void arm_cpu_do_interrupt(CPUState *cpu); > void arm_v7m_cpu_do_interrupt(CPUState *cpu); > bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req); > > -int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > -int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > +int arm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > +int arm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > > /* > * Helpers to dynamically generates XML descriptions of the sysregs > diff --git a/target/arm/cpu32.h b/target/arm/cpu32.h > new file mode 100644 > index 0000000000..9cc6b710aa > --- /dev/null > +++ b/target/arm/cpu32.h > @@ -0,0 +1,27 @@ > +/* > + * QEMU ARM CPU models (32bit) > + * > + * Copyright (c) 2012 SUSE LINUX Products GmbH > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see > + * <http://www.gnu.org/licenses/gpl-2.0.html> > + */ > + > +#ifndef ARM_CPU32_H > +#define ARM_CPU32_H > + > +void arm32_cpu_class_init(ObjectClass *oc, void *data); > +void arm32_cpu_register(const ARMCPUInfo *info); > + > +#endif /* ARM_CPU32_H */ > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > index 88e866cc8f..0f640a8b4e 100644 > --- a/target/arm/cpu.c > +++ b/target/arm/cpu.c > @@ -30,6 +30,7 @@ > #ifdef CONFIG_TCG > #include "hw/core/tcg-cpu-ops.h" > #endif /* CONFIG_TCG */ > +#include "cpu32.h" > #include "internals.h" > #include "exec/exec-all.h" > #include "hw/qdev-properties.h" > @@ -716,230 +717,6 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) > #endif > } > > -#ifdef TARGET_AARCH64 > - > -static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) > -{ > - ARMCPU *cpu = ARM_CPU(cs); > - CPUARMState *env = &cpu->env; > - uint32_t psr = pstate_read(env); > - int i; > - int el = arm_current_el(env); > - const char *ns_status; > - > - qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); > - for (i = 0; i < 32; i++) { > - if (i == 31) { > - qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); > - } else { > - qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], > - (i + 2) % 3 ? " " : "\n"); > - } > - } > - > - if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) { > - ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; > - } else { > - ns_status = ""; > - } > - qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", > - psr, > - psr & PSTATE_N ? 'N' : '-', > - psr & PSTATE_Z ? 'Z' : '-', > - psr & PSTATE_C ? 'C' : '-', > - psr & PSTATE_V ? 'V' : '-', > - ns_status, > - el, > - psr & PSTATE_SP ? 'h' : 't'); > - > - if (cpu_isar_feature(aa64_bti, cpu)) { > - qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); > - } > - if (!(flags & CPU_DUMP_FPU)) { > - qemu_fprintf(f, "\n"); > - return; > - } > - if (fp_exception_el(env, el) != 0) { > - qemu_fprintf(f, " FPU disabled\n"); > - return; > - } > - qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", > - vfp_get_fpcr(env), vfp_get_fpsr(env)); > - > - if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { > - int j, zcr_len = sve_zcr_len_for_el(env, el); > - > - for (i = 0; i <= FFR_PRED_NUM; i++) { > - bool eol; > - if (i == FFR_PRED_NUM) { > - qemu_fprintf(f, "FFR="); > - /* It's last, so end the line. */ > - eol = true; > - } else { > - qemu_fprintf(f, "P%02d=", i); > - switch (zcr_len) { > - case 0: > - eol = i % 8 == 7; > - break; > - case 1: > - eol = i % 6 == 5; > - break; > - case 2: > - case 3: > - eol = i % 3 == 2; > - break; > - default: > - /* More than one quadword per predicate. */ > - eol = true; > - break; > - } > - } > - for (j = zcr_len / 4; j >= 0; j--) { > - int digits; > - if (j * 4 + 4 <= zcr_len + 1) { > - digits = 16; > - } else { > - digits = (zcr_len % 4 + 1) * 4; > - } > - qemu_fprintf(f, "%0*" PRIx64 "%s", digits, > - env->vfp.pregs[i].p[j], > - j ? ":" : eol ? "\n" : " "); > - } > - } > - > - for (i = 0; i < 32; i++) { > - if (zcr_len == 0) { > - qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", > - i, env->vfp.zregs[i].d[1], > - env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); > - } else if (zcr_len == 1) { > - qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 > - ":%016" PRIx64 ":%016" PRIx64 "\n", > - i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], > - env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); > - } else { > - for (j = zcr_len; j >= 0; j--) { > - bool odd = (zcr_len - j) % 2 != 0; > - if (j == zcr_len) { > - qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); > - } else if (!odd) { > - if (j > 0) { > - qemu_fprintf(f, " [%x-%x]=", j, j - 1); > - } else { > - qemu_fprintf(f, " [%x]=", j); > - } > - } > - qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", > - env->vfp.zregs[i].d[j * 2 + 1], > - env->vfp.zregs[i].d[j * 2], > - odd || j == 0 ? "\n" : ":"); > - } > - } > - } > - } else { > - for (i = 0; i < 32; i++) { > - uint64_t *q = aa64_vfp_qreg(env, i); > - qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", > - i, q[1], q[0], (i & 1 ? "\n" : " ")); > - } > - } > -} > - > -#else > - > -static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) > -{ > - g_assert_not_reached(); > -} > - > -#endif > - > -static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) > -{ > - ARMCPU *cpu = ARM_CPU(cs); > - CPUARMState *env = &cpu->env; > - int i; > - > - if (is_a64(env)) { > - aarch64_cpu_dump_state(cs, f, flags); > - return; > - } > - > - for (i = 0; i < 16; i++) { > - qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); > - if ((i % 4) == 3) { > - qemu_fprintf(f, "\n"); > - } else { > - qemu_fprintf(f, " "); > - } > - } > - > - if (arm_feature(env, ARM_FEATURE_M)) { > - uint32_t xpsr = xpsr_read(env); > - const char *mode; > - const char *ns_status = ""; > - > - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { > - ns_status = env->v7m.secure ? "S " : "NS "; > - } > - > - if (xpsr & XPSR_EXCP) { > - mode = "handler"; > - } else { > - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) { > - mode = "unpriv-thread"; > - } else { > - mode = "priv-thread"; > - } > - } > - > - qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", > - xpsr, > - xpsr & XPSR_N ? 'N' : '-', > - xpsr & XPSR_Z ? 'Z' : '-', > - xpsr & XPSR_C ? 'C' : '-', > - xpsr & XPSR_V ? 'V' : '-', > - xpsr & XPSR_T ? 'T' : 'A', > - ns_status, > - mode); > - } else { > - uint32_t psr = cpsr_read(env); > - const char *ns_status = ""; > - > - if (arm_feature(env, ARM_FEATURE_EL3) && > - (psr & CPSR_M) != ARM_CPU_MODE_MON) { > - ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; > - } > - > - qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", > - psr, > - psr & CPSR_N ? 'N' : '-', > - psr & CPSR_Z ? 'Z' : '-', > - psr & CPSR_C ? 'C' : '-', > - psr & CPSR_V ? 'V' : '-', > - psr & CPSR_T ? 'T' : 'A', > - ns_status, > - aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); > - } > - > - if (flags & CPU_DUMP_FPU) { > - int numvfpregs = 0; > - if (cpu_isar_feature(aa32_simd_r32, cpu)) { > - numvfpregs = 32; > - } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { > - numvfpregs = 16; > - } > - for (i = 0; i < numvfpregs; i++) { > - uint64_t v = *aa32_vfp_dreg(env, i); > - qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", > - i * 2, (uint32_t)v, > - i * 2 + 1, (uint32_t)(v >> 32), > - i, v); > - } > - qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); > - } > -} > - > uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz) > { > uint32_t Aff1 = idx / clustersz; > @@ -1845,331 +1622,6 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) > return oc; > } > > -/* CPU models. These are not needed for the AArch64 linux-user build. */ > -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) > - > -static const ARMCPRegInfo cortexa8_cp_reginfo[] = { > - { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, > - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > - { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, > - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > - REGINFO_SENTINEL > -}; > - > -static void cortex_a8_initfn(Object *obj) > -{ > - ARMCPU *cpu = ARM_CPU(obj); > - > - cpu->dtb_compatible = "arm,cortex-a8"; > - set_feature(&cpu->env, ARM_FEATURE_V7); > - set_feature(&cpu->env, ARM_FEATURE_NEON); > - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > - set_feature(&cpu->env, ARM_FEATURE_EL3); > - cpu->midr = 0x410fc080; > - cpu->reset_fpsid = 0x410330c0; > - cpu->isar.mvfr0 = 0x11110222; > - cpu->isar.mvfr1 = 0x00011111; > - cpu->ctr = 0x82048004; > - cpu->reset_sctlr = 0x00c50078; > - cpu->isar.id_pfr0 = 0x1031; > - cpu->isar.id_pfr1 = 0x11; > - cpu->isar.id_dfr0 = 0x400; > - cpu->id_afr0 = 0; > - cpu->isar.id_mmfr0 = 0x31100003; > - cpu->isar.id_mmfr1 = 0x20000000; > - cpu->isar.id_mmfr2 = 0x01202000; > - cpu->isar.id_mmfr3 = 0x11; > - cpu->isar.id_isar0 = 0x00101111; > - cpu->isar.id_isar1 = 0x12112111; > - cpu->isar.id_isar2 = 0x21232031; > - cpu->isar.id_isar3 = 0x11112131; > - cpu->isar.id_isar4 = 0x00111142; > - cpu->isar.dbgdidr = 0x15141000; > - cpu->clidr = (1 << 27) | (2 << 24) | 3; > - cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ > - cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ > - cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ > - cpu->reset_auxcr = 2; > - define_arm_cp_regs(cpu, cortexa8_cp_reginfo); > -} > - > -static const ARMCPRegInfo cortexa9_cp_reginfo[] = { > - /* > - * power_control should be set to maximum latency. Again, > - * default to 0 and set by private hook > - */ > - { .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, > - .access = PL1_RW, .resetvalue = 0, > - .fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) }, > - { .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1, > - .access = PL1_RW, .resetvalue = 0, > - .fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) }, > - { .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2, > - .access = PL1_RW, .resetvalue = 0, > - .fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) }, > - { .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, > - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > - /* TLB lockdown control */ > - { .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2, > - .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, > - { .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4, > - .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, > - { .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2, > - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > - { .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2, > - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > - { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, > - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > - REGINFO_SENTINEL > -}; > - > -static void cortex_a9_initfn(Object *obj) > -{ > - ARMCPU *cpu = ARM_CPU(obj); > - > - cpu->dtb_compatible = "arm,cortex-a9"; > - set_feature(&cpu->env, ARM_FEATURE_V7); > - set_feature(&cpu->env, ARM_FEATURE_NEON); > - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > - set_feature(&cpu->env, ARM_FEATURE_EL3); > - /* > - * Note that A9 supports the MP extensions even for > - * A9UP and single-core A9MP (which are both different > - * and valid configurations; we don't model A9UP). > - */ > - set_feature(&cpu->env, ARM_FEATURE_V7MP); > - set_feature(&cpu->env, ARM_FEATURE_CBAR); > - cpu->midr = 0x410fc090; > - cpu->reset_fpsid = 0x41033090; > - cpu->isar.mvfr0 = 0x11110222; > - cpu->isar.mvfr1 = 0x01111111; > - cpu->ctr = 0x80038003; > - cpu->reset_sctlr = 0x00c50078; > - cpu->isar.id_pfr0 = 0x1031; > - cpu->isar.id_pfr1 = 0x11; > - cpu->isar.id_dfr0 = 0x000; > - cpu->id_afr0 = 0; > - cpu->isar.id_mmfr0 = 0x00100103; > - cpu->isar.id_mmfr1 = 0x20000000; > - cpu->isar.id_mmfr2 = 0x01230000; > - cpu->isar.id_mmfr3 = 0x00002111; > - cpu->isar.id_isar0 = 0x00101111; > - cpu->isar.id_isar1 = 0x13112111; > - cpu->isar.id_isar2 = 0x21232041; > - cpu->isar.id_isar3 = 0x11112131; > - cpu->isar.id_isar4 = 0x00111142; > - cpu->isar.dbgdidr = 0x35141000; > - cpu->clidr = (1 << 27) | (1 << 24) | 3; > - cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ > - cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ > - define_arm_cp_regs(cpu, cortexa9_cp_reginfo); > -} > - > -#ifndef CONFIG_USER_ONLY > -static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) > -{ > - MachineState *ms = MACHINE(qdev_get_machine()); > - > - /* > - * Linux wants the number of processors from here. > - * Might as well set the interrupt-controller bit too. > - */ > - return ((ms->smp.cpus - 1) << 24) | (1 << 23); > -} > -#endif > - > -static const ARMCPRegInfo cortexa15_cp_reginfo[] = { > -#ifndef CONFIG_USER_ONLY > - { .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, > - .access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read, > - .writefn = arm_cp_write_ignore, }, > -#endif > - { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, > - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > - REGINFO_SENTINEL > -}; > - > -static void cortex_a7_initfn(Object *obj) > -{ > - ARMCPU *cpu = ARM_CPU(obj); > - > - cpu->dtb_compatible = "arm,cortex-a7"; > - set_feature(&cpu->env, ARM_FEATURE_V7VE); > - set_feature(&cpu->env, ARM_FEATURE_NEON); > - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); > - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); > - set_feature(&cpu->env, ARM_FEATURE_EL2); > - set_feature(&cpu->env, ARM_FEATURE_EL3); > - set_feature(&cpu->env, ARM_FEATURE_PMU); > - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; > - cpu->midr = 0x410fc075; > - cpu->reset_fpsid = 0x41023075; > - cpu->isar.mvfr0 = 0x10110222; > - cpu->isar.mvfr1 = 0x11111111; > - cpu->ctr = 0x84448003; > - cpu->reset_sctlr = 0x00c50078; > - cpu->isar.id_pfr0 = 0x00001131; > - cpu->isar.id_pfr1 = 0x00011011; > - cpu->isar.id_dfr0 = 0x02010555; > - cpu->id_afr0 = 0x00000000; > - cpu->isar.id_mmfr0 = 0x10101105; > - cpu->isar.id_mmfr1 = 0x40000000; > - cpu->isar.id_mmfr2 = 0x01240000; > - cpu->isar.id_mmfr3 = 0x02102211; > - /* > - * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but > - * table 4-41 gives 0x02101110, which includes the arm div insns. > - */ > - cpu->isar.id_isar0 = 0x02101110; > - cpu->isar.id_isar1 = 0x13112111; > - cpu->isar.id_isar2 = 0x21232041; > - cpu->isar.id_isar3 = 0x11112131; > - cpu->isar.id_isar4 = 0x10011142; > - cpu->isar.dbgdidr = 0x3515f005; > - cpu->clidr = 0x0a200023; > - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ > - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ > - cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ > - define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ > -} > - > -static void cortex_a15_initfn(Object *obj) > -{ > - ARMCPU *cpu = ARM_CPU(obj); > - > - cpu->dtb_compatible = "arm,cortex-a15"; > - set_feature(&cpu->env, ARM_FEATURE_V7VE); > - set_feature(&cpu->env, ARM_FEATURE_NEON); > - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); > - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); > - set_feature(&cpu->env, ARM_FEATURE_EL2); > - set_feature(&cpu->env, ARM_FEATURE_EL3); > - set_feature(&cpu->env, ARM_FEATURE_PMU); > - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; > - cpu->midr = 0x412fc0f1; > - cpu->reset_fpsid = 0x410430f0; > - cpu->isar.mvfr0 = 0x10110222; > - cpu->isar.mvfr1 = 0x11111111; > - cpu->ctr = 0x8444c004; > - cpu->reset_sctlr = 0x00c50078; > - cpu->isar.id_pfr0 = 0x00001131; > - cpu->isar.id_pfr1 = 0x00011011; > - cpu->isar.id_dfr0 = 0x02010555; > - cpu->id_afr0 = 0x00000000; > - cpu->isar.id_mmfr0 = 0x10201105; > - cpu->isar.id_mmfr1 = 0x20000000; > - cpu->isar.id_mmfr2 = 0x01240000; > - cpu->isar.id_mmfr3 = 0x02102211; > - cpu->isar.id_isar0 = 0x02101110; > - cpu->isar.id_isar1 = 0x13112111; > - cpu->isar.id_isar2 = 0x21232041; > - cpu->isar.id_isar3 = 0x11112131; > - cpu->isar.id_isar4 = 0x10011142; > - cpu->isar.dbgdidr = 0x3515f021; > - cpu->clidr = 0x0a200023; > - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ > - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ > - cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ > - define_arm_cp_regs(cpu, cortexa15_cp_reginfo); > -} > - > -#ifndef TARGET_AARCH64 > -/* > - * -cpu max: a CPU with as many features enabled as our emulation supports. > - * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c; > - * this only needs to handle 32 bits, and need not care about KVM. > - */ > -static void arm_max_initfn(Object *obj) > -{ > - ARMCPU *cpu = ARM_CPU(obj); > - > - cortex_a15_initfn(obj); > - > - /* old-style VFP short-vector support */ > - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); > - > -#ifdef CONFIG_USER_ONLY > - /* > - * We don't set these in system emulation mode for the moment, > - * since we don't correctly set (all of) the ID registers to > - * advertise them. > - */ > - set_feature(&cpu->env, ARM_FEATURE_V8); > - { > - uint32_t t; > - > - t = cpu->isar.id_isar5; > - t = FIELD_DP32(t, ID_ISAR5, AES, 2); > - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); > - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); > - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); > - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); > - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); > - cpu->isar.id_isar5 = t; > - > - t = cpu->isar.id_isar6; > - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); > - t = FIELD_DP32(t, ID_ISAR6, DP, 1); > - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); > - t = FIELD_DP32(t, ID_ISAR6, SB, 1); > - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); > - cpu->isar.id_isar6 = t; > - > - t = cpu->isar.mvfr1; > - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ > - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ > - cpu->isar.mvfr1 = t; > - > - t = cpu->isar.mvfr2; > - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ > - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ > - cpu->isar.mvfr2 = t; > - > - t = cpu->isar.id_mmfr3; > - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ > - cpu->isar.id_mmfr3 = t; > - > - t = cpu->isar.id_mmfr4; > - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ > - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ > - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ > - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ > - cpu->isar.id_mmfr4 = t; > - > - t = cpu->isar.id_pfr0; > - t = FIELD_DP32(t, ID_PFR0, DIT, 1); > - cpu->isar.id_pfr0 = t; > - > - t = cpu->isar.id_pfr2; > - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); > - cpu->isar.id_pfr2 = t; > - } > -#endif > -} > -#endif > - > -#endif /* !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) */ > - > -static const ARMCPUInfo arm_cpus[] = { > -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) > - { .name = "cortex-a7", .initfn = cortex_a7_initfn }, > - { .name = "cortex-a8", .initfn = cortex_a8_initfn }, > - { .name = "cortex-a9", .initfn = cortex_a9_initfn }, > - { .name = "cortex-a15", .initfn = cortex_a15_initfn }, > -#ifndef TARGET_AARCH64 > - { .name = "max", .initfn = arm_max_initfn }, > -#endif > -#ifdef CONFIG_USER_ONLY > - { .name = "any", .initfn = arm_max_initfn }, > -#endif > -#endif > -}; > - > static Property arm_cpu_properties[] = { > DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0), > DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0), > @@ -2180,17 +1632,6 @@ static Property arm_cpu_properties[] = { > DEFINE_PROP_END_OF_LIST() > }; > > -static gchar *arm_gdb_arch_name(CPUState *cs) > -{ > - ARMCPU *cpu = ARM_CPU(cs); > - CPUARMState *env = &cpu->env; > - > - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { > - return g_strdup("iwmmxt"); > - } > - return g_strdup("arm"); > -} > - > #ifdef CONFIG_TCG > static struct TCGCPUOps arm_tcg_ops = { > .initialize = arm_translate_init, > @@ -2223,10 +1664,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) > > cc->class_by_name = arm_cpu_class_by_name; > cc->has_work = arm_cpu_has_work; > - cc->dump_state = arm_cpu_dump_state; > cc->set_pc = arm_cpu_set_pc; > - cc->gdb_read_register = arm_cpu_gdb_read_register; > - cc->gdb_write_register = arm_cpu_gdb_write_register; > #ifndef CONFIG_USER_ONLY > cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug; > cc->asidx_from_attrs = arm_asidx_from_attrs; > @@ -2235,9 +1673,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) > cc->write_elf64_note = arm_cpu_write_elf64_note; > cc->write_elf32_note = arm_cpu_write_elf32_note; > #endif > - cc->gdb_num_core_regs = 26; > - cc->gdb_core_xml_file = "arm-core.xml"; > - cc->gdb_arch_name = arm_gdb_arch_name; > + > cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml; > cc->gdb_stop_before_watchpoint = true; > cc->disas_set_info = arm_disas_set_info; > @@ -2245,6 +1681,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) > #ifdef CONFIG_TCG > cc->tcg_ops = &arm_tcg_ops; > #endif /* CONFIG_TCG */ > + > + arm32_cpu_class_init(oc, data); > } > > #ifdef CONFIG_KVM > @@ -2267,38 +1705,6 @@ static const TypeInfo host_arm_cpu_type_info = { > > #endif > > -static void arm_cpu_instance_init(Object *obj) > -{ > - ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); > - > - acc->info->initfn(obj); > - arm_cpu_post_init(obj); > -} > - > -static void cpu_register_class_init(ObjectClass *oc, void *data) > -{ > - ARMCPUClass *acc = ARM_CPU_CLASS(oc); > - > - acc->info = data; > -} > - > -void arm_cpu_register(const ARMCPUInfo *info) > -{ > - TypeInfo type_info = { > - .parent = TYPE_ARM_CPU, > - .instance_size = sizeof(ARMCPU), > - .instance_align = __alignof__(ARMCPU), > - .instance_init = arm_cpu_instance_init, > - .class_size = sizeof(ARMCPUClass), > - .class_init = info->class_init ?: cpu_register_class_init, > - .class_data = (void *)info, > - }; > - > - type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); > - type_register(&type_info); > - g_free((void *)type_info.name); > -} > - > static const TypeInfo arm_cpu_type_info = { > .name = TYPE_ARM_CPU, > .parent = TYPE_CPU, > @@ -2313,21 +1719,11 @@ static const TypeInfo arm_cpu_type_info = { > > static void arm_cpu_register_types(void) > { > - const size_t cpu_count = ARRAY_SIZE(arm_cpus); > - > type_register_static(&arm_cpu_type_info); > > #ifdef CONFIG_KVM > type_register_static(&host_arm_cpu_type_info); > #endif > - > - if (cpu_count) { > - size_t i; > - > - for (i = 0; i < cpu_count; ++i) { > - arm_cpu_register(&arm_cpus[i]); > - } > - } > } > > type_init(arm_cpu_register_types) > diff --git a/target/arm/cpu32.c b/target/arm/cpu32.c > new file mode 100644 > index 0000000000..cb5b033b27 > --- /dev/null > +++ b/target/arm/cpu32.c > @@ -0,0 +1,516 @@ > +/* > + * QEMU ARM CPU models (32bit) > + * > + * Copyright (c) 2012 SUSE LINUX Products GmbH > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see > + * <http://www.gnu.org/licenses/gpl-2.0.html> > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/qemu-print.h" > +#include "qemu-common.h" > +#include "target/arm/idau.h" > +#include "qemu/module.h" > +#include "qapi/error.h" > +#include "qapi/visitor.h" > +#include "cpu.h" > +#include "cpregs.h" > +#include "internals.h" > +#include "exec/exec-all.h" > +#include "hw/qdev-properties.h" > +#if !defined(CONFIG_USER_ONLY) > +#include "hw/loader.h" > +#include "hw/boards.h" > +#endif > +#include "sysemu/sysemu.h" > +#include "sysemu/tcg.h" > +#include "sysemu/hw_accel.h" > +#include "kvm_arm.h" > +#include "disas/capstone.h" > +#include "fpu/softfloat.h" > +#include "get-phys-addr.h" this should be "cpu-mmu.h" > +#include "cpu32.h" > + > +#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) > + > +static const ARMCPRegInfo cortexa8_cp_reginfo[] = { > + { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, > + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > + { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, > + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > + REGINFO_SENTINEL > +}; > + > +static void cortex_a8_initfn(Object *obj) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + > + cpu->dtb_compatible = "arm,cortex-a8"; > + set_feature(&cpu->env, ARM_FEATURE_V7); > + set_feature(&cpu->env, ARM_FEATURE_NEON); > + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > + set_feature(&cpu->env, ARM_FEATURE_EL3); > + cpu->midr = 0x410fc080; > + cpu->reset_fpsid = 0x410330c0; > + cpu->isar.mvfr0 = 0x11110222; > + cpu->isar.mvfr1 = 0x00011111; > + cpu->ctr = 0x82048004; > + cpu->reset_sctlr = 0x00c50078; > + cpu->isar.id_pfr0 = 0x1031; > + cpu->isar.id_pfr1 = 0x11; > + cpu->isar.id_dfr0 = 0x400; > + cpu->id_afr0 = 0; > + cpu->isar.id_mmfr0 = 0x31100003; > + cpu->isar.id_mmfr1 = 0x20000000; > + cpu->isar.id_mmfr2 = 0x01202000; > + cpu->isar.id_mmfr3 = 0x11; > + cpu->isar.id_isar0 = 0x00101111; > + cpu->isar.id_isar1 = 0x12112111; > + cpu->isar.id_isar2 = 0x21232031; > + cpu->isar.id_isar3 = 0x11112131; > + cpu->isar.id_isar4 = 0x00111142; > + cpu->isar.dbgdidr = 0x15141000; > + cpu->clidr = (1 << 27) | (2 << 24) | 3; > + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ > + cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ > + cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ > + cpu->reset_auxcr = 2; > + define_arm_cp_regs(cpu, cortexa8_cp_reginfo); > +} > + > +static const ARMCPRegInfo cortexa9_cp_reginfo[] = { > + /* > + * power_control should be set to maximum latency. Again, > + * default to 0 and set by private hook > + */ > + { .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, > + .access = PL1_RW, .resetvalue = 0, > + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) }, > + { .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1, > + .access = PL1_RW, .resetvalue = 0, > + .fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) }, > + { .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2, > + .access = PL1_RW, .resetvalue = 0, > + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) }, > + { .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, > + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > + /* TLB lockdown control */ > + { .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2, > + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, > + { .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4, > + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, > + { .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2, > + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > + { .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2, > + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > + { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, > + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, > + REGINFO_SENTINEL > +}; > + > +static void cortex_a9_initfn(Object *obj) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + > + cpu->dtb_compatible = "arm,cortex-a9"; > + set_feature(&cpu->env, ARM_FEATURE_V7); > + set_feature(&cpu->env, ARM_FEATURE_NEON); > + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > + set_feature(&cpu->env, ARM_FEATURE_EL3); > + /* > + * Note that A9 supports the MP extensions even for > + * A9UP and single-core A9MP (which are both different > + * and valid configurations; we don't model A9UP). > + */ > + set_feature(&cpu->env, ARM_FEATURE_V7MP); > + set_feature(&cpu->env, ARM_FEATURE_CBAR); > + cpu->midr = 0x410fc090; > + cpu->reset_fpsid = 0x41033090; > + cpu->isar.mvfr0 = 0x11110222; > + cpu->isar.mvfr1 = 0x01111111; > + cpu->ctr = 0x80038003; > + cpu->reset_sctlr = 0x00c50078; > + cpu->isar.id_pfr0 = 0x1031; > + cpu->isar.id_pfr1 = 0x11; > + cpu->isar.id_dfr0 = 0x000; > + cpu->id_afr0 = 0; > + cpu->isar.id_mmfr0 = 0x00100103; > + cpu->isar.id_mmfr1 = 0x20000000; > + cpu->isar.id_mmfr2 = 0x01230000; > + cpu->isar.id_mmfr3 = 0x00002111; > + cpu->isar.id_isar0 = 0x00101111; > + cpu->isar.id_isar1 = 0x13112111; > + cpu->isar.id_isar2 = 0x21232041; > + cpu->isar.id_isar3 = 0x11112131; > + cpu->isar.id_isar4 = 0x00111142; > + cpu->isar.dbgdidr = 0x35141000; > + cpu->clidr = (1 << 27) | (1 << 24) | 3; > + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ > + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ > + define_arm_cp_regs(cpu, cortexa9_cp_reginfo); > +} > + > +#ifndef CONFIG_USER_ONLY > +static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + MachineState *ms = MACHINE(qdev_get_machine()); > + > + /* > + * Linux wants the number of processors from here. > + * Might as well set the interrupt-controller bit too. > + */ > + return ((ms->smp.cpus - 1) << 24) | (1 << 23); > +} > +#endif > + > +static const ARMCPRegInfo cortexa15_cp_reginfo[] = { > +#ifndef CONFIG_USER_ONLY > + { .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, > + .access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read, > + .writefn = arm_cp_write_ignore, }, > +#endif > + { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, > + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, > + REGINFO_SENTINEL > +}; > + > +static void cortex_a7_initfn(Object *obj) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + > + cpu->dtb_compatible = "arm,cortex-a7"; > + set_feature(&cpu->env, ARM_FEATURE_V7VE); > + set_feature(&cpu->env, ARM_FEATURE_NEON); > + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); > + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); > + set_feature(&cpu->env, ARM_FEATURE_EL2); > + set_feature(&cpu->env, ARM_FEATURE_EL3); > + set_feature(&cpu->env, ARM_FEATURE_PMU); > + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; > + cpu->midr = 0x410fc075; > + cpu->reset_fpsid = 0x41023075; > + cpu->isar.mvfr0 = 0x10110222; > + cpu->isar.mvfr1 = 0x11111111; > + cpu->ctr = 0x84448003; > + cpu->reset_sctlr = 0x00c50078; > + cpu->isar.id_pfr0 = 0x00001131; > + cpu->isar.id_pfr1 = 0x00011011; > + cpu->isar.id_dfr0 = 0x02010555; > + cpu->id_afr0 = 0x00000000; > + cpu->isar.id_mmfr0 = 0x10101105; > + cpu->isar.id_mmfr1 = 0x40000000; > + cpu->isar.id_mmfr2 = 0x01240000; > + cpu->isar.id_mmfr3 = 0x02102211; > + /* > + * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but > + * table 4-41 gives 0x02101110, which includes the arm div insns. > + */ > + cpu->isar.id_isar0 = 0x02101110; > + cpu->isar.id_isar1 = 0x13112111; > + cpu->isar.id_isar2 = 0x21232041; > + cpu->isar.id_isar3 = 0x11112131; > + cpu->isar.id_isar4 = 0x10011142; > + cpu->isar.dbgdidr = 0x3515f005; > + cpu->clidr = 0x0a200023; > + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ > + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ > + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ > + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ > +} > + > +static void cortex_a15_initfn(Object *obj) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + > + cpu->dtb_compatible = "arm,cortex-a15"; > + set_feature(&cpu->env, ARM_FEATURE_V7VE); > + set_feature(&cpu->env, ARM_FEATURE_NEON); > + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); > + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); > + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); > + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); > + set_feature(&cpu->env, ARM_FEATURE_EL2); > + set_feature(&cpu->env, ARM_FEATURE_EL3); > + set_feature(&cpu->env, ARM_FEATURE_PMU); > + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; > + cpu->midr = 0x412fc0f1; > + cpu->reset_fpsid = 0x410430f0; > + cpu->isar.mvfr0 = 0x10110222; > + cpu->isar.mvfr1 = 0x11111111; > + cpu->ctr = 0x8444c004; > + cpu->reset_sctlr = 0x00c50078; > + cpu->isar.id_pfr0 = 0x00001131; > + cpu->isar.id_pfr1 = 0x00011011; > + cpu->isar.id_dfr0 = 0x02010555; > + cpu->id_afr0 = 0x00000000; > + cpu->isar.id_mmfr0 = 0x10201105; > + cpu->isar.id_mmfr1 = 0x20000000; > + cpu->isar.id_mmfr2 = 0x01240000; > + cpu->isar.id_mmfr3 = 0x02102211; > + cpu->isar.id_isar0 = 0x02101110; > + cpu->isar.id_isar1 = 0x13112111; > + cpu->isar.id_isar2 = 0x21232041; > + cpu->isar.id_isar3 = 0x11112131; > + cpu->isar.id_isar4 = 0x10011142; > + cpu->isar.dbgdidr = 0x3515f021; > + cpu->clidr = 0x0a200023; > + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ > + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ > + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ > + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); > +} > + > +#ifndef TARGET_AARCH64 > +/* > + * -cpu max: a CPU with as many features enabled as our emulation supports. > + * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c; > + * this only needs to handle 32 bits, and need not care about KVM. > + */ > +static void arm32_max_initfn(Object *obj) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + > + cortex_a15_initfn(obj); > + > + /* old-style VFP short-vector support */ > + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); > + > +#ifdef CONFIG_USER_ONLY > + /* > + * We don't set these in system emulation mode for the moment, > + * since we don't correctly set (all of) the ID registers to > + * advertise them. > + */ > + set_feature(&cpu->env, ARM_FEATURE_V8); > + { > + uint32_t t; > + > + t = cpu->isar.id_isar5; > + t = FIELD_DP32(t, ID_ISAR5, AES, 2); > + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); > + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); > + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); > + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); > + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); > + cpu->isar.id_isar5 = t; > + > + t = cpu->isar.id_isar6; > + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); > + t = FIELD_DP32(t, ID_ISAR6, DP, 1); > + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); > + t = FIELD_DP32(t, ID_ISAR6, SB, 1); > + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); > + cpu->isar.id_isar6 = t; > + > + t = cpu->isar.mvfr1; > + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ > + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ > + cpu->isar.mvfr1 = t; > + > + t = cpu->isar.mvfr2; > + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ > + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ > + cpu->isar.mvfr2 = t; > + > + t = cpu->isar.id_mmfr3; > + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ > + cpu->isar.id_mmfr3 = t; > + > + t = cpu->isar.id_mmfr4; > + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ > + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ > + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ > + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ > + cpu->isar.id_mmfr4 = t; > + > + t = cpu->isar.id_pfr0; > + t = FIELD_DP32(t, ID_PFR0, DIT, 1); > + cpu->isar.id_pfr0 = t; > + } > +#endif > +} > +#endif /* !TARGET_AARCH64 */ > +#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ > + > +static const ARMCPUInfo arm32_cpus[] = { > +#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) > + { .name = "cortex-a7", .initfn = cortex_a7_initfn }, > + { .name = "cortex-a8", .initfn = cortex_a8_initfn }, > + { .name = "cortex-a9", .initfn = cortex_a9_initfn }, > + { .name = "cortex-a15", .initfn = cortex_a15_initfn }, > +#ifndef TARGET_AARCH64 > + { .name = "max", .initfn = arm32_max_initfn }, > +#endif > +#ifdef CONFIG_USER_ONLY > + { .name = "any", .initfn = arm32_max_initfn }, > +#endif > +#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ > +}; > + > +static gchar *arm32_gdb_arch_name(CPUState *cs) > +{ > + ARMCPU *cpu = ARM_CPU(cs); > + CPUARMState *env = &cpu->env; > + > + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { > + return g_strdup("iwmmxt"); > + } > + return g_strdup("arm"); > +} > + > +static void arm32_cpu_dump_state(CPUState *cs, FILE *f, int flags) > +{ > + ARMCPU *cpu = ARM_CPU(cs); > + CPUARMState *env = &cpu->env; > + int i; > + > + assert(!is_a64(env)); > + > + for (i = 0; i < 16; i++) { > + qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); > + if ((i % 4) == 3) { > + qemu_fprintf(f, "\n"); > + } else { > + qemu_fprintf(f, " "); > + } > + } > + > + if (arm_feature(env, ARM_FEATURE_M)) { > + uint32_t xpsr = xpsr_read(env); > + const char *mode; > + const char *ns_status = ""; > + > + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { > + ns_status = env->v7m.secure ? "S " : "NS "; > + } > + > + if (xpsr & XPSR_EXCP) { > + mode = "handler"; > + } else { > + if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) { > + mode = "unpriv-thread"; > + } else { > + mode = "priv-thread"; > + } > + } > + > + qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", > + xpsr, > + xpsr & XPSR_N ? 'N' : '-', > + xpsr & XPSR_Z ? 'Z' : '-', > + xpsr & XPSR_C ? 'C' : '-', > + xpsr & XPSR_V ? 'V' : '-', > + xpsr & XPSR_T ? 'T' : 'A', > + ns_status, > + mode); > + } else { > + uint32_t psr = cpsr_read(env); > + const char *ns_status = ""; > + > + if (arm_feature(env, ARM_FEATURE_EL3) && > + (psr & CPSR_M) != ARM_CPU_MODE_MON) { > + ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; > + } > + > + qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", > + psr, > + psr & CPSR_N ? 'N' : '-', > + psr & CPSR_Z ? 'Z' : '-', > + psr & CPSR_C ? 'C' : '-', > + psr & CPSR_V ? 'V' : '-', > + psr & CPSR_T ? 'T' : 'A', > + ns_status, > + aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); > + } > + > + if (flags & CPU_DUMP_FPU) { > + int numvfpregs = 0; > + if (cpu_isar_feature(aa32_simd_r32, cpu)) { > + numvfpregs = 32; > + } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { > + numvfpregs = 16; > + } > + for (i = 0; i < numvfpregs; i++) { > + uint64_t v = *aa32_vfp_dreg(env, i); > + qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", > + i * 2, (uint32_t)v, > + i * 2 + 1, (uint32_t)(v >> 32), > + i, v); > + } > + qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); > + } > +} > + > +void arm32_cpu_class_init(ObjectClass *oc, void *data) > +{ > + CPUClass *cc = CPU_CLASS(oc); > + > + cc->gdb_read_register = arm32_cpu_gdb_read_register; > + cc->gdb_write_register = arm32_cpu_gdb_write_register; > + cc->gdb_num_core_regs = 26; > + cc->gdb_core_xml_file = "arm-core.xml"; > + cc->gdb_arch_name = arm32_gdb_arch_name; > + cc->dump_state = arm32_cpu_dump_state; > +} > + > +static void arm32_cpu_instance_init(Object *obj) > +{ > + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); > + > + acc->info->initfn(obj); > + arm_cpu_post_init(obj); > +} > + > +static void arm32_cpu_register_class_init(ObjectClass *oc, void *data) > +{ > + ARMCPUClass *acc = ARM_CPU_CLASS(oc); > + > + acc->info = data; > +} > + > +void arm32_cpu_register(const ARMCPUInfo *info) > +{ > + TypeInfo type_info = { > + .parent = TYPE_ARM_CPU, > + .instance_size = sizeof(ARMCPU), > + .instance_align = __alignof__(ARMCPU), > + .instance_init = arm32_cpu_instance_init, > + .class_size = sizeof(ARMCPUClass), > + .class_init = info->class_init ?: arm32_cpu_register_class_init, > + .class_data = (void *)info, > + }; > + > + type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); > + type_register(&type_info); > + g_free((void *)type_info.name); > +} > + > +static void arm32_cpu_register_types(void) > +{ > + const size_t cpu_count = ARRAY_SIZE(arm32_cpus); > + > + if (cpu_count) { > + size_t i; > + > + for (i = 0; i < cpu_count; ++i) { > + arm32_cpu_register(&arm32_cpus[i]); > + } > + } > +} > + > +type_init(arm32_cpu_register_types) > diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c > index 0728f1a431..0a14cca194 100644 > --- a/target/arm/cpu64.c > +++ b/target/arm/cpu64.c > @@ -20,6 +20,7 @@ > > #include "qemu/osdep.h" > #include "qapi/error.h" > +#include "qemu/qemu-print.h" > #include "cpu.h" > #ifdef CONFIG_TCG > #include "hw/core/tcg-cpu-ops.h" > @@ -814,6 +815,133 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) > return g_strdup("aarch64"); > } > > +static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) > +{ > + ARMCPU *cpu = ARM_CPU(cs); > + CPUARMState *env = &cpu->env; > + uint32_t psr = pstate_read(env); > + int i; > + int el = arm_current_el(env); > + const char *ns_status; > + > + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); > + for (i = 0; i < 32; i++) { > + if (i == 31) { > + qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); > + } else { > + qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], > + (i + 2) % 3 ? " " : "\n"); > + } > + } > + > + if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) { > + ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; > + } else { > + ns_status = ""; > + } > + qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", > + psr, > + psr & PSTATE_N ? 'N' : '-', > + psr & PSTATE_Z ? 'Z' : '-', > + psr & PSTATE_C ? 'C' : '-', > + psr & PSTATE_V ? 'V' : '-', > + ns_status, > + el, > + psr & PSTATE_SP ? 'h' : 't'); > + > + if (cpu_isar_feature(aa64_bti, cpu)) { > + qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); > + } > + if (!(flags & CPU_DUMP_FPU)) { > + qemu_fprintf(f, "\n"); > + return; > + } > + if (fp_exception_el(env, el) != 0) { > + qemu_fprintf(f, " FPU disabled\n"); > + return; > + } > + qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", > + vfp_get_fpcr(env), vfp_get_fpsr(env)); > + > + if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { > + int j, zcr_len = sve_zcr_len_for_el(env, el); > + > + for (i = 0; i <= FFR_PRED_NUM; i++) { > + bool eol; > + if (i == FFR_PRED_NUM) { > + qemu_fprintf(f, "FFR="); > + /* It's last, so end the line. */ > + eol = true; > + } else { > + qemu_fprintf(f, "P%02d=", i); > + switch (zcr_len) { > + case 0: > + eol = i % 8 == 7; > + break; > + case 1: > + eol = i % 6 == 5; > + break; > + case 2: > + case 3: > + eol = i % 3 == 2; > + break; > + default: > + /* More than one quadword per predicate. */ > + eol = true; > + break; > + } > + } > + for (j = zcr_len / 4; j >= 0; j--) { > + int digits; > + if (j * 4 + 4 <= zcr_len + 1) { > + digits = 16; > + } else { > + digits = (zcr_len % 4 + 1) * 4; > + } > + qemu_fprintf(f, "%0*" PRIx64 "%s", digits, > + env->vfp.pregs[i].p[j], > + j ? ":" : eol ? "\n" : " "); > + } > + } > + > + for (i = 0; i < 32; i++) { > + if (zcr_len == 0) { > + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", > + i, env->vfp.zregs[i].d[1], > + env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); > + } else if (zcr_len == 1) { > + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 > + ":%016" PRIx64 ":%016" PRIx64 "\n", > + i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], > + env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); > + } else { > + for (j = zcr_len; j >= 0; j--) { > + bool odd = (zcr_len - j) % 2 != 0; > + if (j == zcr_len) { > + qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); > + } else if (!odd) { > + if (j > 0) { > + qemu_fprintf(f, " [%x-%x]=", j, j - 1); > + } else { > + qemu_fprintf(f, " [%x]=", j); > + } > + } > + qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", > + env->vfp.zregs[i].d[j * 2 + 1], > + env->vfp.zregs[i].d[j * 2], > + odd || j == 0 ? "\n" : ":"); > + } > + } > + } > + } else { > + for (i = 0; i < 32; i++) { > + uint64_t *q = aa64_vfp_qreg(env, i); > + qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", > + i, q[1], q[0], (i & 1 ? "\n" : " ")); > + } > + } > +} > + > static void aarch64_cpu_class_init(ObjectClass *oc, void *data) > { > CPUClass *cc = CPU_CLASS(oc); > @@ -823,6 +951,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) > cc->gdb_num_core_regs = 34; > cc->gdb_core_xml_file = "aarch64-core.xml"; > cc->gdb_arch_name = aarch64_gdb_arch_name; > + cc->dump_state = aarch64_cpu_dump_state; > > object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, > aarch64_cpu_set_aarch64); > @@ -846,7 +975,7 @@ static void cpu_register_class_init(ObjectClass *oc, void *data) > acc->info = data; > } > > -void aarch64_cpu_register(const ARMCPUInfo *info) > +static void aarch64_cpu_register(const ARMCPUInfo *info) > { > TypeInfo type_info = { > .parent = TYPE_AARCH64_CPU, > diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c > index b7189491de..77d08645e5 100644 > --- a/target/arm/cpu_tcg.c > +++ b/target/arm/cpu_tcg.c > @@ -16,6 +16,7 @@ > #include "internals.h" > #include "target/arm/idau.h" > #include "cpregs.h" > +#include "cpu32.h" > > /* CPU models. These are not needed for the AArch64 linux-user build. */ > #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) > @@ -753,7 +754,7 @@ static void arm_tcg_cpu_register_types(void) > > type_register_static(&idau_interface_type_info); > for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) { > - arm_cpu_register(&arm_tcg_cpus[i]); > + arm32_cpu_register(&arm_tcg_cpus[i]); > } > } > > diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c > index 0645415f44..93c668c5a1 100644 > --- a/target/arm/gdbstub.c > +++ b/target/arm/gdbstub.c > @@ -34,7 +34,7 @@ typedef struct RegisterSysregXmlParam { > We hack round this by giving the FPA regs zero size when talking to a > newer gdb. */ > > -int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) > +int arm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) > { > ARMCPU *cpu = ARM_CPU(cs); > CPUARMState *env = &cpu->env; > @@ -69,7 +69,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) > return 0; > } > > -int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) > +int arm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) > { > ARMCPU *cpu = ARM_CPU(cs); > CPUARMState *env = &cpu->env; > diff --git a/target/arm/meson.build b/target/arm/meson.build > index 8fa0b12510..e4ff9a0534 100644 > --- a/target/arm/meson.build > +++ b/target/arm/meson.build > @@ -1,6 +1,7 @@ > arm_ss = ss.source_set() > arm_ss.add(files( > 'cpu.c', > + 'cpu32.c', > 'gdbstub.c', > 'cpu_tcg.c', > 'cpu-mmu.c', > @@ -18,6 +19,10 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( > 'gdbstub64.c', > )) > > +arm_ss.add(when: 'CONFIG_TCG', if_true: files( > + 'cpu_tcg.c', > +)) > + > arm_softmmu_ss = ss.source_set() > arm_softmmu_ss.add(files( > 'arch_dump.c', >
diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index a22bd506d0..0d41a346b9 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -38,9 +38,6 @@ typedef struct ARMCPUInfo { void (*class_init)(ObjectClass *oc, void *data); } ARMCPUInfo; -void arm_cpu_register(const ARMCPUInfo *info); -void aarch64_cpu_register(const ARMCPUInfo *info); - /** * ARMCPUClass: * @parent_realize: The parent class' realize handler. diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9293d90ffb..ea1e63f7f6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1026,8 +1026,8 @@ void arm_cpu_do_interrupt(CPUState *cpu); void arm_v7m_cpu_do_interrupt(CPUState *cpu); bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req); -int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); -int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +int arm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); +int arm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); /* * Helpers to dynamically generates XML descriptions of the sysregs diff --git a/target/arm/cpu32.h b/target/arm/cpu32.h new file mode 100644 index 0000000000..9cc6b710aa --- /dev/null +++ b/target/arm/cpu32.h @@ -0,0 +1,27 @@ +/* + * QEMU ARM CPU models (32bit) + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * <http://www.gnu.org/licenses/gpl-2.0.html> + */ + +#ifndef ARM_CPU32_H +#define ARM_CPU32_H + +void arm32_cpu_class_init(ObjectClass *oc, void *data); +void arm32_cpu_register(const ARMCPUInfo *info); + +#endif /* ARM_CPU32_H */ diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 88e866cc8f..0f640a8b4e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -30,6 +30,7 @@ #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" #endif /* CONFIG_TCG */ +#include "cpu32.h" #include "internals.h" #include "exec/exec-all.h" #include "hw/qdev-properties.h" @@ -716,230 +717,6 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) #endif } -#ifdef TARGET_AARCH64 - -static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - uint32_t psr = pstate_read(env); - int i; - int el = arm_current_el(env); - const char *ns_status; - - qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); - for (i = 0; i < 32; i++) { - if (i == 31) { - qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); - } else { - qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], - (i + 2) % 3 ? " " : "\n"); - } - } - - if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) { - ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; - } else { - ns_status = ""; - } - qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", - psr, - psr & PSTATE_N ? 'N' : '-', - psr & PSTATE_Z ? 'Z' : '-', - psr & PSTATE_C ? 'C' : '-', - psr & PSTATE_V ? 'V' : '-', - ns_status, - el, - psr & PSTATE_SP ? 'h' : 't'); - - if (cpu_isar_feature(aa64_bti, cpu)) { - qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); - } - if (!(flags & CPU_DUMP_FPU)) { - qemu_fprintf(f, "\n"); - return; - } - if (fp_exception_el(env, el) != 0) { - qemu_fprintf(f, " FPU disabled\n"); - return; - } - qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", - vfp_get_fpcr(env), vfp_get_fpsr(env)); - - if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { - int j, zcr_len = sve_zcr_len_for_el(env, el); - - for (i = 0; i <= FFR_PRED_NUM; i++) { - bool eol; - if (i == FFR_PRED_NUM) { - qemu_fprintf(f, "FFR="); - /* It's last, so end the line. */ - eol = true; - } else { - qemu_fprintf(f, "P%02d=", i); - switch (zcr_len) { - case 0: - eol = i % 8 == 7; - break; - case 1: - eol = i % 6 == 5; - break; - case 2: - case 3: - eol = i % 3 == 2; - break; - default: - /* More than one quadword per predicate. */ - eol = true; - break; - } - } - for (j = zcr_len / 4; j >= 0; j--) { - int digits; - if (j * 4 + 4 <= zcr_len + 1) { - digits = 16; - } else { - digits = (zcr_len % 4 + 1) * 4; - } - qemu_fprintf(f, "%0*" PRIx64 "%s", digits, - env->vfp.pregs[i].p[j], - j ? ":" : eol ? "\n" : " "); - } - } - - for (i = 0; i < 32; i++) { - if (zcr_len == 0) { - qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", - i, env->vfp.zregs[i].d[1], - env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); - } else if (zcr_len == 1) { - qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 - ":%016" PRIx64 ":%016" PRIx64 "\n", - i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], - env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); - } else { - for (j = zcr_len; j >= 0; j--) { - bool odd = (zcr_len - j) % 2 != 0; - if (j == zcr_len) { - qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); - } else if (!odd) { - if (j > 0) { - qemu_fprintf(f, " [%x-%x]=", j, j - 1); - } else { - qemu_fprintf(f, " [%x]=", j); - } - } - qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", - env->vfp.zregs[i].d[j * 2 + 1], - env->vfp.zregs[i].d[j * 2], - odd || j == 0 ? "\n" : ":"); - } - } - } - } else { - for (i = 0; i < 32; i++) { - uint64_t *q = aa64_vfp_qreg(env, i); - qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", - i, q[1], q[0], (i & 1 ? "\n" : " ")); - } - } -} - -#else - -static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - g_assert_not_reached(); -} - -#endif - -static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - int i; - - if (is_a64(env)) { - aarch64_cpu_dump_state(cs, f, flags); - return; - } - - for (i = 0; i < 16; i++) { - qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); - if ((i % 4) == 3) { - qemu_fprintf(f, "\n"); - } else { - qemu_fprintf(f, " "); - } - } - - if (arm_feature(env, ARM_FEATURE_M)) { - uint32_t xpsr = xpsr_read(env); - const char *mode; - const char *ns_status = ""; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - ns_status = env->v7m.secure ? "S " : "NS "; - } - - if (xpsr & XPSR_EXCP) { - mode = "handler"; - } else { - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) { - mode = "unpriv-thread"; - } else { - mode = "priv-thread"; - } - } - - qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", - xpsr, - xpsr & XPSR_N ? 'N' : '-', - xpsr & XPSR_Z ? 'Z' : '-', - xpsr & XPSR_C ? 'C' : '-', - xpsr & XPSR_V ? 'V' : '-', - xpsr & XPSR_T ? 'T' : 'A', - ns_status, - mode); - } else { - uint32_t psr = cpsr_read(env); - const char *ns_status = ""; - - if (arm_feature(env, ARM_FEATURE_EL3) && - (psr & CPSR_M) != ARM_CPU_MODE_MON) { - ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; - } - - qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", - psr, - psr & CPSR_N ? 'N' : '-', - psr & CPSR_Z ? 'Z' : '-', - psr & CPSR_C ? 'C' : '-', - psr & CPSR_V ? 'V' : '-', - psr & CPSR_T ? 'T' : 'A', - ns_status, - aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); - } - - if (flags & CPU_DUMP_FPU) { - int numvfpregs = 0; - if (cpu_isar_feature(aa32_simd_r32, cpu)) { - numvfpregs = 32; - } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { - numvfpregs = 16; - } - for (i = 0; i < numvfpregs; i++) { - uint64_t v = *aa32_vfp_dreg(env, i); - qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", - i * 2, (uint32_t)v, - i * 2 + 1, (uint32_t)(v >> 32), - i, v); - } - qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); - } -} - uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz) { uint32_t Aff1 = idx / clustersz; @@ -1845,331 +1622,6 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) return oc; } -/* CPU models. These are not needed for the AArch64 linux-user build. */ -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) - -static const ARMCPRegInfo cortexa8_cp_reginfo[] = { - { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL -}; - -static void cortex_a8_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a8"; - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_EL3); - cpu->midr = 0x410fc080; - cpu->reset_fpsid = 0x410330c0; - cpu->isar.mvfr0 = 0x11110222; - cpu->isar.mvfr1 = 0x00011111; - cpu->ctr = 0x82048004; - cpu->reset_sctlr = 0x00c50078; - cpu->isar.id_pfr0 = 0x1031; - cpu->isar.id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x400; - cpu->id_afr0 = 0; - cpu->isar.id_mmfr0 = 0x31100003; - cpu->isar.id_mmfr1 = 0x20000000; - cpu->isar.id_mmfr2 = 0x01202000; - cpu->isar.id_mmfr3 = 0x11; - cpu->isar.id_isar0 = 0x00101111; - cpu->isar.id_isar1 = 0x12112111; - cpu->isar.id_isar2 = 0x21232031; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x00111142; - cpu->isar.dbgdidr = 0x15141000; - cpu->clidr = (1 << 27) | (2 << 24) | 3; - cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ - cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ - cpu->reset_auxcr = 2; - define_arm_cp_regs(cpu, cortexa8_cp_reginfo); -} - -static const ARMCPRegInfo cortexa9_cp_reginfo[] = { - /* - * power_control should be set to maximum latency. Again, - * default to 0 and set by private hook - */ - { .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .resetvalue = 0, - .fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) }, - { .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .resetvalue = 0, - .fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) }, - { .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, .resetvalue = 0, - .fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) }, - { .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - /* TLB lockdown control */ - { .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2, - .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, - { .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4, - .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, - { .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2, - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - { .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2, - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, - .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - REGINFO_SENTINEL -}; - -static void cortex_a9_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a9"; - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); - set_feature(&cpu->env, ARM_FEATURE_EL3); - /* - * Note that A9 supports the MP extensions even for - * A9UP and single-core A9MP (which are both different - * and valid configurations; we don't model A9UP). - */ - set_feature(&cpu->env, ARM_FEATURE_V7MP); - set_feature(&cpu->env, ARM_FEATURE_CBAR); - cpu->midr = 0x410fc090; - cpu->reset_fpsid = 0x41033090; - cpu->isar.mvfr0 = 0x11110222; - cpu->isar.mvfr1 = 0x01111111; - cpu->ctr = 0x80038003; - cpu->reset_sctlr = 0x00c50078; - cpu->isar.id_pfr0 = 0x1031; - cpu->isar.id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x000; - cpu->id_afr0 = 0; - cpu->isar.id_mmfr0 = 0x00100103; - cpu->isar.id_mmfr1 = 0x20000000; - cpu->isar.id_mmfr2 = 0x01230000; - cpu->isar.id_mmfr3 = 0x00002111; - cpu->isar.id_isar0 = 0x00101111; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x00111142; - cpu->isar.dbgdidr = 0x35141000; - cpu->clidr = (1 << 27) | (1 << 24) | 3; - cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ - cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ - define_arm_cp_regs(cpu, cortexa9_cp_reginfo); -} - -#ifndef CONFIG_USER_ONLY -static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - MachineState *ms = MACHINE(qdev_get_machine()); - - /* - * Linux wants the number of processors from here. - * Might as well set the interrupt-controller bit too. - */ - return ((ms->smp.cpus - 1) << 24) | (1 << 23); -} -#endif - -static const ARMCPRegInfo cortexa15_cp_reginfo[] = { -#ifndef CONFIG_USER_ONLY - { .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, - .access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read, - .writefn = arm_cp_write_ignore, }, -#endif - { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL -}; - -static void cortex_a7_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a7"; - set_feature(&cpu->env, ARM_FEATURE_V7VE); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; - cpu->midr = 0x410fc075; - cpu->reset_fpsid = 0x41023075; - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x11111111; - cpu->ctr = 0x84448003; - cpu->reset_sctlr = 0x00c50078; - cpu->isar.id_pfr0 = 0x00001131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10101105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01240000; - cpu->isar.id_mmfr3 = 0x02102211; - /* - * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but - * table 4-41 gives 0x02101110, which includes the arm div insns. - */ - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x10011142; - cpu->isar.dbgdidr = 0x3515f005; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ - cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ - define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ -} - -static void cortex_a15_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a15"; - set_feature(&cpu->env, ARM_FEATURE_V7VE); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; - cpu->midr = 0x412fc0f1; - cpu->reset_fpsid = 0x410430f0; - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x11111111; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50078; - cpu->isar.id_pfr0 = 0x00001131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x02010555; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x20000000; - cpu->isar.id_mmfr2 = 0x01240000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232041; - cpu->isar.id_isar3 = 0x11112131; - cpu->isar.id_isar4 = 0x10011142; - cpu->isar.dbgdidr = 0x3515f021; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ - cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ - cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ - define_arm_cp_regs(cpu, cortexa15_cp_reginfo); -} - -#ifndef TARGET_AARCH64 -/* - * -cpu max: a CPU with as many features enabled as our emulation supports. - * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c; - * this only needs to handle 32 bits, and need not care about KVM. - */ -static void arm_max_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cortex_a15_initfn(obj); - - /* old-style VFP short-vector support */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); - -#ifdef CONFIG_USER_ONLY - /* - * We don't set these in system emulation mode for the moment, - * since we don't correctly set (all of) the ID registers to - * advertise them. - */ - set_feature(&cpu->env, ARM_FEATURE_V8); - { - uint32_t t; - - t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = t; - - t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - cpu->isar.id_isar6 = t; - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = t; - - t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - - t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = t; - - t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = t; - - t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = t; - - t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = t; - } -#endif -} -#endif - -#endif /* !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) */ - -static const ARMCPUInfo arm_cpus[] = { -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) - { .name = "cortex-a7", .initfn = cortex_a7_initfn }, - { .name = "cortex-a8", .initfn = cortex_a8_initfn }, - { .name = "cortex-a9", .initfn = cortex_a9_initfn }, - { .name = "cortex-a15", .initfn = cortex_a15_initfn }, -#ifndef TARGET_AARCH64 - { .name = "max", .initfn = arm_max_initfn }, -#endif -#ifdef CONFIG_USER_ONLY - { .name = "any", .initfn = arm_max_initfn }, -#endif -#endif -}; - static Property arm_cpu_properties[] = { DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0), DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0), @@ -2180,17 +1632,6 @@ static Property arm_cpu_properties[] = { DEFINE_PROP_END_OF_LIST() }; -static gchar *arm_gdb_arch_name(CPUState *cs) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - return g_strdup("iwmmxt"); - } - return g_strdup("arm"); -} - #ifdef CONFIG_TCG static struct TCGCPUOps arm_tcg_ops = { .initialize = arm_translate_init, @@ -2223,10 +1664,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = arm_cpu_class_by_name; cc->has_work = arm_cpu_has_work; - cc->dump_state = arm_cpu_dump_state; cc->set_pc = arm_cpu_set_pc; - cc->gdb_read_register = arm_cpu_gdb_read_register; - cc->gdb_write_register = arm_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug; cc->asidx_from_attrs = arm_asidx_from_attrs; @@ -2235,9 +1673,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->write_elf64_note = arm_cpu_write_elf64_note; cc->write_elf32_note = arm_cpu_write_elf32_note; #endif - cc->gdb_num_core_regs = 26; - cc->gdb_core_xml_file = "arm-core.xml"; - cc->gdb_arch_name = arm_gdb_arch_name; + cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml; cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = arm_disas_set_info; @@ -2245,6 +1681,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) #ifdef CONFIG_TCG cc->tcg_ops = &arm_tcg_ops; #endif /* CONFIG_TCG */ + + arm32_cpu_class_init(oc, data); } #ifdef CONFIG_KVM @@ -2267,38 +1705,6 @@ static const TypeInfo host_arm_cpu_type_info = { #endif -static void arm_cpu_instance_init(Object *obj) -{ - ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); - - acc->info->initfn(obj); - arm_cpu_post_init(obj); -} - -static void cpu_register_class_init(ObjectClass *oc, void *data) -{ - ARMCPUClass *acc = ARM_CPU_CLASS(oc); - - acc->info = data; -} - -void arm_cpu_register(const ARMCPUInfo *info) -{ - TypeInfo type_info = { - .parent = TYPE_ARM_CPU, - .instance_size = sizeof(ARMCPU), - .instance_align = __alignof__(ARMCPU), - .instance_init = arm_cpu_instance_init, - .class_size = sizeof(ARMCPUClass), - .class_init = info->class_init ?: cpu_register_class_init, - .class_data = (void *)info, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); - type_register(&type_info); - g_free((void *)type_info.name); -} - static const TypeInfo arm_cpu_type_info = { .name = TYPE_ARM_CPU, .parent = TYPE_CPU, @@ -2313,21 +1719,11 @@ static const TypeInfo arm_cpu_type_info = { static void arm_cpu_register_types(void) { - const size_t cpu_count = ARRAY_SIZE(arm_cpus); - type_register_static(&arm_cpu_type_info); #ifdef CONFIG_KVM type_register_static(&host_arm_cpu_type_info); #endif - - if (cpu_count) { - size_t i; - - for (i = 0; i < cpu_count; ++i) { - arm_cpu_register(&arm_cpus[i]); - } - } } type_init(arm_cpu_register_types) diff --git a/target/arm/cpu32.c b/target/arm/cpu32.c new file mode 100644 index 0000000000..cb5b033b27 --- /dev/null +++ b/target/arm/cpu32.c @@ -0,0 +1,516 @@ +/* + * QEMU ARM CPU models (32bit) + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * <http://www.gnu.org/licenses/gpl-2.0.html> + */ + +#include "qemu/osdep.h" +#include "qemu/qemu-print.h" +#include "qemu-common.h" +#include "target/arm/idau.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "cpu.h" +#include "cpregs.h" +#include "internals.h" +#include "exec/exec-all.h" +#include "hw/qdev-properties.h" +#if !defined(CONFIG_USER_ONLY) +#include "hw/loader.h" +#include "hw/boards.h" +#endif +#include "sysemu/sysemu.h" +#include "sysemu/tcg.h" +#include "sysemu/hw_accel.h" +#include "kvm_arm.h" +#include "disas/capstone.h" +#include "fpu/softfloat.h" +#include "get-phys-addr.h" +#include "cpu32.h" + +#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) + +static const ARMCPRegInfo cortexa8_cp_reginfo[] = { + { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static void cortex_a8_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a8"; + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fc080; + cpu->reset_fpsid = 0x410330c0; + cpu->isar.mvfr0 = 0x11110222; + cpu->isar.mvfr1 = 0x00011111; + cpu->ctr = 0x82048004; + cpu->reset_sctlr = 0x00c50078; + cpu->isar.id_pfr0 = 0x1031; + cpu->isar.id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x400; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x31100003; + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01202000; + cpu->isar.id_mmfr3 = 0x11; + cpu->isar.id_isar0 = 0x00101111; + cpu->isar.id_isar1 = 0x12112111; + cpu->isar.id_isar2 = 0x21232031; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x00111142; + cpu->isar.dbgdidr = 0x15141000; + cpu->clidr = (1 << 27) | (2 << 24) | 3; + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ + cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ + cpu->reset_auxcr = 2; + define_arm_cp_regs(cpu, cortexa8_cp_reginfo); +} + +static const ARMCPRegInfo cortexa9_cp_reginfo[] = { + /* + * power_control should be set to maximum latency. Again, + * default to 0 and set by private hook + */ + { .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) }, + { .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) }, + { .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) }, + { .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + /* TLB lockdown control */ + { .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2, + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, + { .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4, + .access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP }, + { .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + { .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, + REGINFO_SENTINEL +}; + +static void cortex_a9_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a9"; + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_EL3); + /* + * Note that A9 supports the MP extensions even for + * A9UP and single-core A9MP (which are both different + * and valid configurations; we don't model A9UP). + */ + set_feature(&cpu->env, ARM_FEATURE_V7MP); + set_feature(&cpu->env, ARM_FEATURE_CBAR); + cpu->midr = 0x410fc090; + cpu->reset_fpsid = 0x41033090; + cpu->isar.mvfr0 = 0x11110222; + cpu->isar.mvfr1 = 0x01111111; + cpu->ctr = 0x80038003; + cpu->reset_sctlr = 0x00c50078; + cpu->isar.id_pfr0 = 0x1031; + cpu->isar.id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x000; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x00100103; + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01230000; + cpu->isar.id_mmfr3 = 0x00002111; + cpu->isar.id_isar0 = 0x00101111; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x00111142; + cpu->isar.dbgdidr = 0x35141000; + cpu->clidr = (1 << 27) | (1 << 24) | 3; + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ + define_arm_cp_regs(cpu, cortexa9_cp_reginfo); +} + +#ifndef CONFIG_USER_ONLY +static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + + /* + * Linux wants the number of processors from here. + * Might as well set the interrupt-controller bit too. + */ + return ((ms->smp.cpus - 1) << 24) | (1 << 23); +} +#endif + +static const ARMCPRegInfo cortexa15_cp_reginfo[] = { +#ifndef CONFIG_USER_ONLY + { .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, + .access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read, + .writefn = arm_cp_write_ignore, }, +#endif + { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static void cortex_a7_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a7"; + set_feature(&cpu->env, ARM_FEATURE_V7VE); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; + cpu->midr = 0x410fc075; + cpu->reset_fpsid = 0x41023075; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; + cpu->isar.id_pfr0 = 0x00001131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01240000; + cpu->isar.id_mmfr3 = 0x02102211; + /* + * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x10011142; + cpu->isar.dbgdidr = 0x3515f005; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ +} + +static void cortex_a15_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a15"; + set_feature(&cpu->env, ARM_FEATURE_V7VE); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; + cpu->midr = 0x412fc0f1; + cpu->reset_fpsid = 0x410430f0; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x11111111; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50078; + cpu->isar.id_pfr0 = 0x00001131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01240000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x10011142; + cpu->isar.dbgdidr = 0x3515f021; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); +} + +#ifndef TARGET_AARCH64 +/* + * -cpu max: a CPU with as many features enabled as our emulation supports. + * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c; + * this only needs to handle 32 bits, and need not care about KVM. + */ +static void arm32_max_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cortex_a15_initfn(obj); + + /* old-style VFP short-vector support */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + +#ifdef CONFIG_USER_ONLY + /* + * We don't set these in system emulation mode for the moment, + * since we don't correctly set (all of) the ID registers to + * advertise them. + */ + set_feature(&cpu->env, ARM_FEATURE_V8); + { + uint32_t t; + + t = cpu->isar.id_isar5; + t = FIELD_DP32(t, ID_ISAR5, AES, 2); + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); + cpu->isar.id_isar5 = t; + + t = cpu->isar.id_isar6; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); + t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); + t = FIELD_DP32(t, ID_ISAR6, SB, 1); + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); + cpu->isar.id_isar6 = t; + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ + cpu->isar.mvfr1 = t; + + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + + t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ + cpu->isar.id_mmfr3 = t; + + t = cpu->isar.id_mmfr4; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ + cpu->isar.id_mmfr4 = t; + + t = cpu->isar.id_pfr0; + t = FIELD_DP32(t, ID_PFR0, DIT, 1); + cpu->isar.id_pfr0 = t; + } +#endif +} +#endif /* !TARGET_AARCH64 */ +#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ + +static const ARMCPUInfo arm32_cpus[] = { +#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) + { .name = "cortex-a7", .initfn = cortex_a7_initfn }, + { .name = "cortex-a8", .initfn = cortex_a8_initfn }, + { .name = "cortex-a9", .initfn = cortex_a9_initfn }, + { .name = "cortex-a15", .initfn = cortex_a15_initfn }, +#ifndef TARGET_AARCH64 + { .name = "max", .initfn = arm32_max_initfn }, +#endif +#ifdef CONFIG_USER_ONLY + { .name = "any", .initfn = arm32_max_initfn }, +#endif +#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ +}; + +static gchar *arm32_gdb_arch_name(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + return g_strdup("iwmmxt"); + } + return g_strdup("arm"); +} + +static void arm32_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + int i; + + assert(!is_a64(env)); + + for (i = 0; i < 16; i++) { + qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) { + qemu_fprintf(f, "\n"); + } else { + qemu_fprintf(f, " "); + } + } + + if (arm_feature(env, ARM_FEATURE_M)) { + uint32_t xpsr = xpsr_read(env); + const char *mode; + const char *ns_status = ""; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + ns_status = env->v7m.secure ? "S " : "NS "; + } + + if (xpsr & XPSR_EXCP) { + mode = "handler"; + } else { + if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) { + mode = "unpriv-thread"; + } else { + mode = "priv-thread"; + } + } + + qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", + xpsr, + xpsr & XPSR_N ? 'N' : '-', + xpsr & XPSR_Z ? 'Z' : '-', + xpsr & XPSR_C ? 'C' : '-', + xpsr & XPSR_V ? 'V' : '-', + xpsr & XPSR_T ? 'T' : 'A', + ns_status, + mode); + } else { + uint32_t psr = cpsr_read(env); + const char *ns_status = ""; + + if (arm_feature(env, ARM_FEATURE_EL3) && + (psr & CPSR_M) != ARM_CPU_MODE_MON) { + ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; + } + + qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", + psr, + psr & CPSR_N ? 'N' : '-', + psr & CPSR_Z ? 'Z' : '-', + psr & CPSR_C ? 'C' : '-', + psr & CPSR_V ? 'V' : '-', + psr & CPSR_T ? 'T' : 'A', + ns_status, + aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); + } + + if (flags & CPU_DUMP_FPU) { + int numvfpregs = 0; + if (cpu_isar_feature(aa32_simd_r32, cpu)) { + numvfpregs = 32; + } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { + numvfpregs = 16; + } + for (i = 0; i < numvfpregs; i++) { + uint64_t v = *aa32_vfp_dreg(env, i); + qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", + i * 2, (uint32_t)v, + i * 2 + 1, (uint32_t)(v >> 32), + i, v); + } + qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); + } +} + +void arm32_cpu_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + + cc->gdb_read_register = arm32_cpu_gdb_read_register; + cc->gdb_write_register = arm32_cpu_gdb_write_register; + cc->gdb_num_core_regs = 26; + cc->gdb_core_xml_file = "arm-core.xml"; + cc->gdb_arch_name = arm32_gdb_arch_name; + cc->dump_state = arm32_cpu_dump_state; +} + +static void arm32_cpu_instance_init(Object *obj) +{ + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); + + acc->info->initfn(obj); + arm_cpu_post_init(obj); +} + +static void arm32_cpu_register_class_init(ObjectClass *oc, void *data) +{ + ARMCPUClass *acc = ARM_CPU_CLASS(oc); + + acc->info = data; +} + +void arm32_cpu_register(const ARMCPUInfo *info) +{ + TypeInfo type_info = { + .parent = TYPE_ARM_CPU, + .instance_size = sizeof(ARMCPU), + .instance_align = __alignof__(ARMCPU), + .instance_init = arm32_cpu_instance_init, + .class_size = sizeof(ARMCPUClass), + .class_init = info->class_init ?: arm32_cpu_register_class_init, + .class_data = (void *)info, + }; + + type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); + type_register(&type_info); + g_free((void *)type_info.name); +} + +static void arm32_cpu_register_types(void) +{ + const size_t cpu_count = ARRAY_SIZE(arm32_cpus); + + if (cpu_count) { + size_t i; + + for (i = 0; i < cpu_count; ++i) { + arm32_cpu_register(&arm32_cpus[i]); + } + } +} + +type_init(arm32_cpu_register_types) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 0728f1a431..0a14cca194 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" @@ -814,6 +815,133 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) return g_strdup("aarch64"); } +static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + uint32_t psr = pstate_read(env); + int i; + int el = arm_current_el(env); + const char *ns_status; + + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); + for (i = 0; i < 32; i++) { + if (i == 31) { + qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); + } else { + qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], + (i + 2) % 3 ? " " : "\n"); + } + } + + if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) { + ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; + } else { + ns_status = ""; + } + qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", + psr, + psr & PSTATE_N ? 'N' : '-', + psr & PSTATE_Z ? 'Z' : '-', + psr & PSTATE_C ? 'C' : '-', + psr & PSTATE_V ? 'V' : '-', + ns_status, + el, + psr & PSTATE_SP ? 'h' : 't'); + + if (cpu_isar_feature(aa64_bti, cpu)) { + qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); + } + if (!(flags & CPU_DUMP_FPU)) { + qemu_fprintf(f, "\n"); + return; + } + if (fp_exception_el(env, el) != 0) { + qemu_fprintf(f, " FPU disabled\n"); + return; + } + qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", + vfp_get_fpcr(env), vfp_get_fpsr(env)); + + if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { + int j, zcr_len = sve_zcr_len_for_el(env, el); + + for (i = 0; i <= FFR_PRED_NUM; i++) { + bool eol; + if (i == FFR_PRED_NUM) { + qemu_fprintf(f, "FFR="); + /* It's last, so end the line. */ + eol = true; + } else { + qemu_fprintf(f, "P%02d=", i); + switch (zcr_len) { + case 0: + eol = i % 8 == 7; + break; + case 1: + eol = i % 6 == 5; + break; + case 2: + case 3: + eol = i % 3 == 2; + break; + default: + /* More than one quadword per predicate. */ + eol = true; + break; + } + } + for (j = zcr_len / 4; j >= 0; j--) { + int digits; + if (j * 4 + 4 <= zcr_len + 1) { + digits = 16; + } else { + digits = (zcr_len % 4 + 1) * 4; + } + qemu_fprintf(f, "%0*" PRIx64 "%s", digits, + env->vfp.pregs[i].p[j], + j ? ":" : eol ? "\n" : " "); + } + } + + for (i = 0; i < 32; i++) { + if (zcr_len == 0) { + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", + i, env->vfp.zregs[i].d[1], + env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); + } else if (zcr_len == 1) { + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 + ":%016" PRIx64 ":%016" PRIx64 "\n", + i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], + env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); + } else { + for (j = zcr_len; j >= 0; j--) { + bool odd = (zcr_len - j) % 2 != 0; + if (j == zcr_len) { + qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); + } else if (!odd) { + if (j > 0) { + qemu_fprintf(f, " [%x-%x]=", j, j - 1); + } else { + qemu_fprintf(f, " [%x]=", j); + } + } + qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", + env->vfp.zregs[i].d[j * 2 + 1], + env->vfp.zregs[i].d[j * 2], + odd || j == 0 ? "\n" : ":"); + } + } + } + } else { + for (i = 0; i < 32; i++) { + uint64_t *q = aa64_vfp_qreg(env, i); + qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", + i, q[1], q[0], (i & 1 ? "\n" : " ")); + } + } +} + static void aarch64_cpu_class_init(ObjectClass *oc, void *data) { CPUClass *cc = CPU_CLASS(oc); @@ -823,6 +951,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = 34; cc->gdb_core_xml_file = "aarch64-core.xml"; cc->gdb_arch_name = aarch64_gdb_arch_name; + cc->dump_state = aarch64_cpu_dump_state; object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, aarch64_cpu_set_aarch64); @@ -846,7 +975,7 @@ static void cpu_register_class_init(ObjectClass *oc, void *data) acc->info = data; } -void aarch64_cpu_register(const ARMCPUInfo *info) +static void aarch64_cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { .parent = TYPE_AARCH64_CPU, diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index b7189491de..77d08645e5 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -16,6 +16,7 @@ #include "internals.h" #include "target/arm/idau.h" #include "cpregs.h" +#include "cpu32.h" /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) @@ -753,7 +754,7 @@ static void arm_tcg_cpu_register_types(void) type_register_static(&idau_interface_type_info); for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) { - arm_cpu_register(&arm_tcg_cpus[i]); + arm32_cpu_register(&arm_tcg_cpus[i]); } } diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 0645415f44..93c668c5a1 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -34,7 +34,7 @@ typedef struct RegisterSysregXmlParam { We hack round this by giving the FPA regs zero size when talking to a newer gdb. */ -int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +int arm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -69,7 +69,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return 0; } -int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +int arm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; diff --git a/target/arm/meson.build b/target/arm/meson.build index 8fa0b12510..e4ff9a0534 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,6 +1,7 @@ arm_ss = ss.source_set() arm_ss.add(files( 'cpu.c', + 'cpu32.c', 'gdbstub.c', 'cpu_tcg.c', 'cpu-mmu.c', @@ -18,6 +19,10 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'gdbstub64.c', )) +arm_ss.add(when: 'CONFIG_TCG', if_true: files( + 'cpu_tcg.c', +)) + arm_softmmu_ss = ss.source_set() arm_softmmu_ss.add(files( 'arch_dump.c',
just like we have cpu64.c for the 64bit cpu models, spawn a cpu32.c from cpu.c. cpu.c will continue to contain the common parts. Note that we need to build cpu32 also for TARGET_AARCH64, because qemu-system-aarch64 is supposed to be able to run non-aarch64 cpus too. Signed-off-by: Claudio Fontana <cfontana@suse.de> --- target/arm/cpu-qom.h | 3 - target/arm/cpu.h | 4 +- target/arm/cpu32.h | 27 ++ target/arm/cpu.c | 612 +---------------------------------------- target/arm/cpu32.c | 516 ++++++++++++++++++++++++++++++++++ target/arm/cpu64.c | 131 ++++++++- target/arm/cpu_tcg.c | 3 +- target/arm/gdbstub.c | 4 +- target/arm/meson.build | 5 + 9 files changed, 688 insertions(+), 617 deletions(-) create mode 100644 target/arm/cpu32.h create mode 100644 target/arm/cpu32.c