From ce1feaa7322affd3b979c9fe93dd8f7462ea9eca Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 21 Feb 2010 14:28:53 -0800 Subject: [PATCH] ARMv7-M: start using "struct arm" This sets up a few of the core "struct arm" data structures so they can be used with ARMv7-M cores. Specifically, it: - defines new ARM core_modes to match the microcontroller modes (e.g. HANDLER not IRQ, and two types of thread mode); - Establishes a new microcontroller "core_type", which can be used to make sure v7-M (and v6-M) cores are handled right; - adds "struct arm" to "struct armv7m" and arranges for the target_to_armv7m() converter to use it; - sets up the arm.core_cache and arm.cpsr values - makes the Cortex-M3 code maintain arm.map and arm.core_mode. This is currently set up as a parallel data structure, primarily to minimize special cases for the semihosting support with microcontroller profile cores. Later patches can rip out the duplicative ARMv7-M support and start reusing core ARM code. Signed-off-by: David Brownell --- src/target/arm.h | 17 ++++++++++++++++- src/target/armv4_5.c | 6 ++++-- src/target/armv7m.c | 17 ++++++++++++++--- src/target/armv7m.h | 4 +++- src/target/cortex_m3.c | 39 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/target/arm.h b/src/target/arm.h index 988266e3c..c72b19426 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -40,9 +40,17 @@ */ /** - * These numbers match the five low bits of the *PSR registers on + * Represent state of an ARM core. + * + * Most numbers match the five low bits of the *PSR registers on * "classic ARM" processors, which build on the ARMv4 processor * modes and register set. + * + * ARM_MODE_ANY is a magic value, often used as a wildcard. + * + * Only the microcontroller cores (ARMv6-M, ARMv7-M) support ARM_MODE_THREAD, + * ARM_MODE_USER_THREAD, and ARM_MODE_HANDLER. Those are the only modes + * they support. */ enum arm_mode { ARM_MODE_USR = 16, @@ -53,6 +61,11 @@ enum arm_mode { ARM_MODE_MON = 26, ARM_MODE_UND = 27, ARM_MODE_SYS = 31, + + ARM_MODE_THREAD, + ARM_MODE_USER_THREAD, + ARM_MODE_HANDLER, + ARM_MODE_ANY = -1 }; @@ -96,6 +109,8 @@ struct arm { * ARM_MODE_ANY indicates the standard set of 37 registers, * seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three * more registers are shadowed, for "Secure Monitor" mode. + * ARM_MODE_THREAD indicates a microcontroller profile core, + * which only shadows SP. */ enum arm_mode core_type; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index c7b73676a..8d3a8917d 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1426,10 +1426,12 @@ int arm_init_arch_info(struct target *target, struct arm *armv4_5) armv4_5->target = target; armv4_5->common_magic = ARM_COMMON_MAGIC; - arm_set_cpsr(armv4_5, ARM_MODE_USR); /* core_type may be overridden by subtype logic */ - armv4_5->core_type = ARM_MODE_ANY; + if (armv4_5->core_type != ARM_MODE_THREAD) { + armv4_5->core_type = ARM_MODE_ANY; + arm_set_cpsr(armv4_5, ARM_MODE_USR); + } /* default full_context() has no core-specific optimizations */ if (!armv4_5->full_context && armv4_5->read_core_reg) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 9fe705af7..faa886b41 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -473,6 +473,7 @@ int armv7m_run_algorithm(struct target *target, int armv7m_arch_state(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); + struct arm *arm = &armv7m->arm; uint32_t ctrl, sp; ctrl = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); @@ -483,7 +484,7 @@ int armv7m_arch_state(struct target *target) debug_reason_name(target), armv7m_mode_strings[armv7m->core_mode], armv7m_exception_string(armv7m->exception_number), - buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32), + buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_PC].value, 0, 32), (ctrl & 0x02) ? 'p' : 'm', sp); @@ -499,6 +500,7 @@ static const struct reg_arch_type armv7m_reg_type = { struct reg_cache *armv7m_build_reg_cache(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); + struct arm *arm = &armv7m->arm; int num_regs = ARMV7M_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); @@ -532,19 +534,28 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].arch_info = &arch_info[i]; } + arm->cpsr = reg_list + ARMV7M_xPSR; + arm->core_cache = cache; return cache; } /** Sets up target as a generic ARMv7-M core */ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) { + struct arm *arm = &armv7m->arm; + armv7m->common_magic = ARMV7M_COMMON_MAGIC; - target->arch_info = armv7m; + arm->core_type = ARM_MODE_THREAD; + arm->arch_info = armv7m; + + /* FIXME remove v7m-specific r/w core_reg functions; + * use the generic ARM core support.. + */ armv7m->read_core_reg = armv7m_read_core_reg; armv7m->write_core_reg = armv7m_write_core_reg; - return ERROR_OK; + return arm_init_arch_info(target, arm); } /** Generates a CRC32 checksum of a memory region. */ diff --git a/src/target/armv7m.h b/src/target/armv7m.h index b6be1d224..89c5064cc 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -100,6 +100,8 @@ enum struct armv7m_common { + struct arm arm; + int common_magic; struct reg_cache *core_cache; enum armv7m_mode core_mode; @@ -128,7 +130,7 @@ struct armv7m_common static inline struct armv7m_common * target_to_armv7m(struct target *target) { - return target->arch_info; + return container_of(target->arch_info, struct armv7m_common, arm); } static inline bool is_armv7m(struct armv7m_common *armv7m) diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index 3f347697b..fbc879f1b 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -323,6 +323,24 @@ static int cortex_m3_examine_exception_reason(struct target *target) return ERROR_OK; } +/* PSP is used in some thread modes */ +static const int armv7m_psp_reg_map[17] = { + ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, + ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, + ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, + ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC, + ARMV7M_xPSR, +}; + +/* MSP is used in handler and some thread modes */ +static const int armv7m_msp_reg_map[17] = { + ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, + ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, + ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, + ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC, + ARMV7M_xPSR, +}; + static int cortex_m3_debug_entry(struct target *target) { int i; @@ -330,6 +348,7 @@ static int cortex_m3_debug_entry(struct target *target) int retval; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; + struct arm *arm = &armv7m->arm; struct swjdp_common *swjdp = &armv7m->swjdp_info; struct reg *r; @@ -377,11 +396,27 @@ static int cortex_m3_debug_entry(struct target *target) { armv7m->core_mode = ARMV7M_MODE_HANDLER; armv7m->exception_number = (xPSR & 0x1FF); + + arm->core_mode = ARM_MODE_HANDLER; + arm->map = armv7m_msp_reg_map; } else { - armv7m->core_mode = buf_get_u32(armv7m->core_cache - ->reg_list[ARMV7M_CONTROL].value, 0, 1); + unsigned control = buf_get_u32(armv7m->core_cache + ->reg_list[ARMV7M_CONTROL].value, 0, 2); + + /* is this thread privileged? */ + armv7m->core_mode = control & 1; + arm->core_mode = armv7m->core_mode + ? ARM_MODE_USER_THREAD + : ARM_MODE_THREAD; + + /* which stack is it using? */ + if (control & 2) + arm->map = armv7m_psp_reg_map; + else + arm->map = armv7m_msp_reg_map; + armv7m->exception_number = 0; }