*/
#include "cpu.h"
+#include "internals.h"
#include "qemu-common.h"
#include "hw/qdev-properties.h"
+#include "qapi/qmp/qerror.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
#include "hw/arm/arm.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
+#include "kvm_arm.h"
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
{
cpu->env.regs[15] = value;
}
+static bool arm_cpu_has_work(CPUState *cs)
+{
+ return cs->interrupt_request &
+ (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
{
/* Reset a single ARMCPRegInfo register */
return;
}
- if (ri->type & ARM_CP_64BIT) {
+ if (cpreg_field_is_64bit(ri)) {
CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue;
} else {
CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue;
acc->parent_reset(s);
- memset(env, 0, offsetof(CPUARMState, breakpoints));
+ memset(env, 0, offsetof(CPUARMState, features));
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+ env->vfp.xregs[ARM_VFP_MVFR2] = cpu->mvfr2;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
/* 64 bit CPUs always start in 64 bit mode */
env->aarch64 = 1;
+#if defined(CONFIG_USER_ONLY)
+ env->pstate = PSTATE_MODE_EL0t;
+ /* Userspace expects access to CTL_EL0 and the cache ops */
+ env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
+ /* and to the FP/Neon instructions */
+ env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
+#else
+ env->pstate = PSTATE_MODE_EL1h;
+ env->pc = cpu->rvbar;
+#endif
+ } else {
+#if defined(CONFIG_USER_ONLY)
+ /* Userspace expects access to cp10 and cp11 for FP/Neon */
+ env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 4, 0xf);
+#endif
}
#if defined(CONFIG_USER_ONLY)
}
#else
/* SVC mode with interrupts disabled. */
- env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+ env->uncached_cpsr = ARM_CPU_MODE_SVC;
+ env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
/* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
clear at reset. Initial SP and PC are loaded from ROM. */
if (IS_M(env)) {
uint32_t pc;
uint8_t *rom;
- env->uncached_cpsr &= ~CPSR_I;
+ env->daif &= ~PSTATE_I;
rom = rom_ptr(0);
if (rom) {
/* We should really use ldl_phys here, in case the guest
env->regs[15] = pc & ~1;
}
}
+
+ if (env->cp15.c1_sys & SCTLR_V) {
+ env->regs[15] = 0xFFFF0000;
+ }
+
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif
set_flush_to_zero(1, &env->vfp.standard_fp_status);
&env->vfp.fp_status);
set_float_detect_tininess(float_tininess_before_rounding,
&env->vfp.standard_fp_status);
- tlb_flush(env, 1);
+ tlb_flush(s, 1);
/* Reset is a state change for some CPUARMState fields which we
* bake assumptions about into translated code, so we need to
* tb_flush().
*/
tb_flush(env);
+
+#ifndef CONFIG_USER_ONLY
+ if (kvm_enabled()) {
+ kvm_arm_reset_vcpu(cpu);
+ }
+#endif
}
#ifndef CONFIG_USER_ONLY
* picky DTB consumer will also provide a helpful error message.
*/
cpu->dtb_compatible = "qemu,unknown";
+ cpu->psci_version = 1; /* By default assume PSCI v0.1 */
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
if (tcg_enabled() && !inited) {
}
}
+static Property arm_cpu_reset_cbar_property =
+ DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
+
+static Property arm_cpu_reset_hivecs_property =
+ DEFINE_PROP_BOOL("reset-hivecs", ARMCPU, reset_hivecs, false);
+
+static Property arm_cpu_rvbar_property =
+ DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
+
+static void arm_cpu_post_init(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
+ arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property,
+ &error_abort);
+ }
+
+ if (!arm_feature(&cpu->env, ARM_FEATURE_M)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property,
+ &error_abort);
+ }
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property,
+ &error_abort);
+ }
+}
+
static void arm_cpu_finalizefn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(env, ARM_FEATURE_V7);
set_feature(env, ARM_FEATURE_ARM_DIV);
set_feature(env, ARM_FEATURE_LPAE);
- set_feature(env, ARM_FEATURE_V8_AES);
}
if (arm_feature(env, ARM_FEATURE_V7)) {
set_feature(env, ARM_FEATURE_VAPA);
}
if (arm_feature(env, ARM_FEATURE_VFP4)) {
set_feature(env, ARM_FEATURE_VFP3);
+ set_feature(env, ARM_FEATURE_VFP_FP16);
}
if (arm_feature(env, ARM_FEATURE_VFP3)) {
set_feature(env, ARM_FEATURE_VFP);
set_feature(env, ARM_FEATURE_V7MP);
set_feature(env, ARM_FEATURE_PXN);
}
+ if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
+ set_feature(env, ARM_FEATURE_CBAR);
+ }
+
+ if (cpu->reset_hivecs) {
+ cpu->reset_sctlr |= (1 << 13);
+ }
register_cp_regs_for_features(cpu);
arm_cpu_register_gdb_regs_for_features(cpu);
init_cpreg_list(cpu);
- cpu_reset(cs);
qemu_init_vcpu(cs);
+ cpu_reset(cs);
acc->parent_realize(dev, errp);
}
ARMCPRegInfo ifar = {
.name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
.access = PL1_RW,
- .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
.resetvalue = 0
};
define_one_arm_cp_reg(cpu, &ifar);
}
#ifndef CONFIG_USER_ONLY
-static int a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t *value)
+static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Linux wants the number of processors from here.
* Might as well set the interrupt-controller bit too.
*/
- *value = ((smp_cpus - 1) << 24) | (1 << 23);
- return 0;
+ return ((smp_cpus - 1) << 24) | (1 << 23);
}
#endif
cpu->dtb_compatible = "arm,cortex-a15";
set_feature(&cpu->env, ARM_FEATURE_V7);
set_feature(&cpu->env, ARM_FEATURE_VFP4);
- set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
- set_feature(&cpu->env, ARM_FEATURE_CBAR);
+ set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
set_feature(&cpu->env, ARM_FEATURE_LPAE);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
cpu->midr = 0x412fc0f1;
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V8);
set_feature(&cpu->env, ARM_FEATURE_VFP4);
- set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
- set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
- set_feature(&cpu->env, ARM_FEATURE_V7MP);
-#ifdef TARGET_AARCH64
- set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-#endif
+ set_feature(&cpu->env, ARM_FEATURE_V8_AES);
+ set_feature(&cpu->env, ARM_FEATURE_V8_SHA1);
+ set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
+ set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
+ set_feature(&cpu->env, ARM_FEATURE_CRC);
cpu->midr = 0xffffffff;
}
#endif
{ .name = "any", .initfn = arm_any_initfn },
#endif
#endif
+ { .name = NULL }
};
static Property arm_cpu_properties[] = {
DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false),
+ DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0),
DEFINE_PROP_END_OF_LIST()
};
cc->reset = arm_cpu_reset;
cc->class_by_name = arm_cpu_class_by_name;
+ cc->has_work = arm_cpu_has_work;
cc->do_interrupt = arm_cpu_do_interrupt;
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
+#ifdef CONFIG_USER_ONLY
+ cc->handle_mmu_fault = arm_cpu_handle_mmu_fault;
+#else
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_arm_cpu;
#endif
.parent = TYPE_CPU,
.instance_size = sizeof(ARMCPU),
.instance_init = arm_cpu_initfn,
+ .instance_post_init = arm_cpu_post_init,
.instance_finalize = arm_cpu_finalizefn,
.abstract = true,
.class_size = sizeof(ARMCPUClass),
static void arm_cpu_register_types(void)
{
- int i;
+ const ARMCPUInfo *info = arm_cpus;
type_register_static(&arm_cpu_type_info);
- for (i = 0; i < ARRAY_SIZE(arm_cpus); i++) {
- cpu_register(&arm_cpus[i]);
+
+ while (info->name) {
+ cpu_register(info);
+ info++;
}
}