aboutsummaryrefslogtreecommitdiff
path: root/target/arm/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/cpu.c')
-rw-r--r--target/arm/cpu.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 7e1f3dd637..3874dc9875 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -40,8 +40,31 @@
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
{
ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
- cpu->env.regs[15] = value;
+ if (is_a64(env)) {
+ env->pc = value;
+ env->thumb = 0;
+ } else {
+ env->regs[15] = value & ~1;
+ env->thumb = value & 1;
+ }
+}
+
+static void arm_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ /*
+ * It's OK to look at env for the current mode here, because it's
+ * never possible for an AArch64 TB to chain to an AArch32 TB.
+ */
+ if (is_a64(env)) {
+ env->pc = tb->pc;
+ } else {
+ env->regs[15] = tb->pc;
+ }
}
static bool arm_cpu_has_work(CPUState *cs)
@@ -162,6 +185,9 @@ static void arm_cpu_reset(CPUState *s)
env->pstate = PSTATE_MODE_EL0t;
/* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */
env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE;
+ /* Enable all PAC keys. */
+ env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB |
+ SCTLR_EnDA | SCTLR_EnDB);
/* Enable all PAC instructions */
env->cp15.hcr_el2 |= HCR_API;
env->cp15.scr_el3 |= SCR_API;
@@ -836,6 +862,13 @@ static void arm_cpu_finalizefn(Object *obj)
QLIST_REMOVE(hook, node);
g_free(hook);
}
+#ifndef CONFIG_USER_ONLY
+ if (cpu->pmu_timer) {
+ timer_del(cpu->pmu_timer);
+ timer_deinit(cpu->pmu_timer);
+ timer_free(cpu->pmu_timer);
+ }
+#endif
}
static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
@@ -1039,13 +1072,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
unset_feature(env, ARM_FEATURE_PMU);
}
if (arm_feature(env, ARM_FEATURE_PMU)) {
- cpu->pmceid0 = get_pmceid(&cpu->env, 0);
- cpu->pmceid1 = get_pmceid(&cpu->env, 1);
+ pmu_init(cpu);
if (!kvm_enabled()) {
arm_register_pre_el_change_hook(cpu, &pmu_pre_el_change, 0);
arm_register_el_change_hook(cpu, &pmu_post_el_change, 0);
}
+
+#ifndef CONFIG_USER_ONLY
+ cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, arm_pmu_timer_cb,
+ cpu);
+#endif
} else {
cpu->id_aa64dfr0 &= ~0xf00;
cpu->pmceid0 = 0;
@@ -2088,6 +2125,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
cc->dump_state = arm_cpu_dump_state;
cc->set_pc = arm_cpu_set_pc;
+ cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
cc->gdb_read_register = arm_cpu_gdb_read_register;
cc->gdb_write_register = arm_cpu_gdb_write_register;
#ifdef CONFIG_USER_ONLY