From 6e3cf5df01bfa192ca162716670cf368ba1338dd Mon Sep 17 00:00:00 2001 From: Martin Galvan Date: Fri, 12 Sep 2014 14:06:48 +0100 Subject: target-arm: Fix resetting issues on ARMv7-M CPUs When calling qemu_system_reset after startup on a Cortex-M CPU, the initial values of PC, MSP and the Thumb bit weren't being set correctly if the vector table was in ROM. In particular, since Thumb was 0, a Usage Fault would arise immediately after trying to execute any instruction on a Cortex-M. Signed-off-by: Martin Galvan Message-id: CAOKbPbaLt-LJsAKkQdOE0cs9Xx4OWrUfpDhATXPSdtuNw2xu_A@mail.gmail.com [PMM: removed an incorrect comment] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'target-arm') diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 8199f32e32..29f7162b04 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -129,22 +129,34 @@ static void arm_cpu_reset(CPUState *s) 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. */ + * clear at reset. Initial SP and PC are loaded from ROM. + */ if (IS_M(env)) { - uint32_t pc; + uint32_t initial_msp; /* Loaded from 0x0 */ + uint32_t initial_pc; /* Loaded from 0x4 */ uint8_t *rom; + env->daif &= ~PSTATE_I; rom = rom_ptr(0); if (rom) { - /* We should really use ldl_phys here, in case the guest - modified flash and reset itself. However images - loaded via -kernel have not been copied yet, so load the - values directly from there. */ - env->regs[13] = ldl_p(rom) & 0xFFFFFFFC; - pc = ldl_p(rom + 4); - env->thumb = pc & 1; - env->regs[15] = pc & ~1; + /* Address zero is covered by ROM which hasn't yet been + * copied into physical memory. + */ + initial_msp = ldl_p(rom); + initial_pc = ldl_p(rom + 4); + } else { + /* Address zero not covered by a ROM blob, or the ROM blob + * is in non-modifiable memory and this is a second reset after + * it got copied into memory. In the latter case, rom_ptr + * will return a NULL pointer and we should use ldl_phys instead. + */ + initial_msp = ldl_phys(s->as, 0); + initial_pc = ldl_phys(s->as, 4); } + + env->regs[13] = initial_msp & 0xFFFFFFFC; + env->regs[15] = initial_pc & ~1; + env->thumb = initial_pc & 1; } if (env->cp15.c1_sys & SCTLR_V) { -- cgit v1.2.1