diff options
author | Paul Brook <paul@codesourcery.com> | 2010-04-05 19:34:51 +0100 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2010-04-05 19:43:12 +0100 |
commit | 983fe82611b87a1198d32f58636f6f38b88ad337 (patch) | |
tree | 5736751719ff68c4da6729108b1d1d524710a2a7 | |
parent | 116348def2bb446d972bdc2f44bd77ff631f85de (diff) |
ARMv7-M reset fixes
Move ARMv7-M PC/SP initialization to the CPU reset routine. Add a board
reset routine to call this. Also load values directly from ROM as
images have not been copied yet.
Avoid clearing the NVIC pointer on cpu reset.
Signed-off-by: Paul Brook <paul@codesourcery.com>
-rw-r--r-- | hw/armv7m.c | 22 | ||||
-rw-r--r-- | target-arm/cpu.h | 2 | ||||
-rw-r--r-- | target-arm/helper.c | 33 |
3 files changed, 33 insertions, 24 deletions
diff --git a/hw/armv7m.c b/hw/armv7m.c index 35f75735b9..854261d940 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -151,6 +151,12 @@ static void armv7m_bitband_init(void) } /* Board init. */ + +static void armv7m_reset(void *opaque) +{ + cpu_reset((CPUState *)opaque); +} + /* Init CPU and memory for a v7-M based board. flash_size and sram_size are in kb. Returns the NVIC array. */ @@ -163,7 +169,6 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, /* FIXME: make this local state. */ static qemu_irq pic[64]; qemu_irq *cpu_pic; - uint32_t pc; int image_size; uint64_t entry; uint64_t lowaddr; @@ -201,7 +206,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, armv7m_bitband_init(); nvic = qdev_create(NULL, "armv7m_nvic"); - env->v7m.nvic = nvic; + env->nvic = nvic; qdev_init_nofail(nvic); cpu_pic = arm_pic_init_cpu(env); sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); @@ -227,24 +232,13 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, exit(1); } - /* If the image was loaded at address zero then assume it is a - regular ROM image and perform the normal CPU reset sequence. - Otherwise jump directly to the entry point. */ - if (lowaddr == 0) { - env->regs[13] = ldl_phys(0); - pc = ldl_phys(4); - } else { - pc = entry; - } - env->thumb = pc & 1; - env->regs[15] = pc & ~1; - /* Hack to map an additional page of ram at the top of the address space. This stops qemu complaining about executing code outside RAM when returning from an exception. */ cpu_register_physical_memory(0xfffff000, 0x1000, qemu_ram_alloc(0x1000) | IO_MEM_RAM); + qemu_register_reset(armv7m_reset, env); return pic; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 3892db44e0..1e34541733 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -146,7 +146,6 @@ typedef struct CPUARMState { int current_sp; int exception; int pending_exception; - void *nvic; } v7m; /* Coprocessor IO used by peripherals */ @@ -205,6 +204,7 @@ typedef struct CPUARMState { CPU_COMMON /* These fields after the common ones so they are preserved on reset. */ + void *nvic; struct arm_boot_info *boot_info; } CPUARMState; diff --git a/target-arm/helper.c b/target-arm/helper.c index e092b2122e..7e6a8186d5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -8,6 +8,7 @@ #include "helpers.h" #include "qemu-common.h" #include "host-utils.h" +#include "hw/loader.h" static uint32_t cortexa9_cp15_c0_c1[8] = { 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 }; @@ -204,14 +205,28 @@ void cpu_reset(CPUARMState *env) #else /* SVC mode with interrupts disabled. */ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + env->regs[15] = 0; /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is - clear at reset. */ - if (IS_M(env)) + 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; + 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 -kenrel have not been copied yet, so load the + values directly from there. */ + env->regs[13] = ldl_p(rom); + pc = ldl_p(rom + 4); + env->thumb = pc & 1; + env->regs[15] = pc & ~1; + } + } env->vfp.xregs[ARM_VFP_FPEXC] = 0; env->cp15.c2_base_mask = 0xffffc000u; #endif - env->regs[15] = 0; tlb_flush(env, 1); } @@ -624,7 +639,7 @@ static void do_v7m_exception_exit(CPUARMState *env) type = env->regs[15]; if (env->v7m.exception != 0) - armv7m_nvic_complete_irq(env->v7m.nvic, env->v7m.exception); + armv7m_nvic_complete_irq(env->nvic, env->v7m.exception); /* Switch to the target stack. */ switch_v7m_sp(env, (type & 4) != 0); @@ -666,15 +681,15 @@ static void do_interrupt_v7m(CPUARMState *env) one we're raising. */ switch (env->exception_index) { case EXCP_UDEF: - armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); return; case EXCP_SWI: env->regs[15] += 2; - armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC); return; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: - armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); return; case EXCP_BKPT: if (semihosting_enabled) { @@ -686,10 +701,10 @@ static void do_interrupt_v7m(CPUARMState *env) return; } } - armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG); return; case EXCP_IRQ: - env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic); + env->v7m.exception = armv7m_nvic_acknowledge_irq(env->nvic); break; case EXCP_EXCEPTION_EXIT: do_v7m_exception_exit(env); |