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>
This commit is contained in:
Paul Brook 2010-04-05 19:34:51 +01:00
parent 116348def2
commit 983fe82611
3 changed files with 33 additions and 24 deletions

View File

@ -151,6 +151,12 @@ static void armv7m_bitband_init(void)
} }
/* Board init. */ /* Board init. */
static void armv7m_reset(void *opaque)
{
cpu_reset((CPUState *)opaque);
}
/* Init CPU and memory for a v7-M based board. /* Init CPU and memory for a v7-M based board.
flash_size and sram_size are in kb. flash_size and sram_size are in kb.
Returns the NVIC array. */ Returns the NVIC array. */
@ -163,7 +169,6 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
/* FIXME: make this local state. */ /* FIXME: make this local state. */
static qemu_irq pic[64]; static qemu_irq pic[64];
qemu_irq *cpu_pic; qemu_irq *cpu_pic;
uint32_t pc;
int image_size; int image_size;
uint64_t entry; uint64_t entry;
uint64_t lowaddr; uint64_t lowaddr;
@ -201,7 +206,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
armv7m_bitband_init(); armv7m_bitband_init();
nvic = qdev_create(NULL, "armv7m_nvic"); nvic = qdev_create(NULL, "armv7m_nvic");
env->v7m.nvic = nvic; env->nvic = nvic;
qdev_init_nofail(nvic); qdev_init_nofail(nvic);
cpu_pic = arm_pic_init_cpu(env); cpu_pic = arm_pic_init_cpu(env);
sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); 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); 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 /* Hack to map an additional page of ram at the top of the address
space. This stops qemu complaining about executing code outside RAM space. This stops qemu complaining about executing code outside RAM
when returning from an exception. */ when returning from an exception. */
cpu_register_physical_memory(0xfffff000, 0x1000, cpu_register_physical_memory(0xfffff000, 0x1000,
qemu_ram_alloc(0x1000) | IO_MEM_RAM); qemu_ram_alloc(0x1000) | IO_MEM_RAM);
qemu_register_reset(armv7m_reset, env);
return pic; return pic;
} }

View File

@ -146,7 +146,6 @@ typedef struct CPUARMState {
int current_sp; int current_sp;
int exception; int exception;
int pending_exception; int pending_exception;
void *nvic;
} v7m; } v7m;
/* Coprocessor IO used by peripherals */ /* Coprocessor IO used by peripherals */
@ -205,6 +204,7 @@ typedef struct CPUARMState {
CPU_COMMON CPU_COMMON
/* These fields after the common ones so they are preserved on reset. */ /* These fields after the common ones so they are preserved on reset. */
void *nvic;
struct arm_boot_info *boot_info; struct arm_boot_info *boot_info;
} CPUARMState; } CPUARMState;

View File

@ -8,6 +8,7 @@
#include "helpers.h" #include "helpers.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "host-utils.h" #include "host-utils.h"
#include "hw/loader.h"
static uint32_t cortexa9_cp15_c0_c1[8] = static uint32_t cortexa9_cp15_c0_c1[8] =
{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 }; { 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
@ -204,14 +205,28 @@ void cpu_reset(CPUARMState *env)
#else #else
/* SVC mode with interrupts disabled. */ /* 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 | 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 /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
clear at reset. */ clear at reset. Initial SP and PC are loaded from ROM. */
if (IS_M(env)) if (IS_M(env)) {
uint32_t pc;
uint8_t *rom;
env->uncached_cpsr &= ~CPSR_I; 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->vfp.xregs[ARM_VFP_FPEXC] = 0;
env->cp15.c2_base_mask = 0xffffc000u; env->cp15.c2_base_mask = 0xffffc000u;
#endif #endif
env->regs[15] = 0;
tlb_flush(env, 1); tlb_flush(env, 1);
} }
@ -624,7 +639,7 @@ static void do_v7m_exception_exit(CPUARMState *env)
type = env->regs[15]; type = env->regs[15];
if (env->v7m.exception != 0) 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 to the target stack. */
switch_v7m_sp(env, (type & 4) != 0); switch_v7m_sp(env, (type & 4) != 0);
@ -666,15 +681,15 @@ static void do_interrupt_v7m(CPUARMState *env)
one we're raising. */ one we're raising. */
switch (env->exception_index) { switch (env->exception_index) {
case EXCP_UDEF: case EXCP_UDEF:
armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
return; return;
case EXCP_SWI: case EXCP_SWI:
env->regs[15] += 2; env->regs[15] += 2;
armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
return; return;
case EXCP_PREFETCH_ABORT: case EXCP_PREFETCH_ABORT:
case EXCP_DATA_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; return;
case EXCP_BKPT: case EXCP_BKPT:
if (semihosting_enabled) { if (semihosting_enabled) {
@ -686,10 +701,10 @@ static void do_interrupt_v7m(CPUARMState *env)
return; return;
} }
} }
armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
return; return;
case EXCP_IRQ: case EXCP_IRQ:
env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic); env->v7m.exception = armv7m_nvic_acknowledge_irq(env->nvic);
break; break;
case EXCP_EXCEPTION_EXIT: case EXCP_EXCEPTION_EXIT:
do_v7m_exception_exit(env); do_v7m_exception_exit(env);