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 <dbrownell@users.sourceforge.net>
This commit is contained in:
parent
b853b9dbc0
commit
ce1feaa732
|
@ -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
|
* "classic ARM" processors, which build on the ARMv4 processor
|
||||||
* modes and register set.
|
* 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 {
|
enum arm_mode {
|
||||||
ARM_MODE_USR = 16,
|
ARM_MODE_USR = 16,
|
||||||
|
@ -53,6 +61,11 @@ enum arm_mode {
|
||||||
ARM_MODE_MON = 26,
|
ARM_MODE_MON = 26,
|
||||||
ARM_MODE_UND = 27,
|
ARM_MODE_UND = 27,
|
||||||
ARM_MODE_SYS = 31,
|
ARM_MODE_SYS = 31,
|
||||||
|
|
||||||
|
ARM_MODE_THREAD,
|
||||||
|
ARM_MODE_USER_THREAD,
|
||||||
|
ARM_MODE_HANDLER,
|
||||||
|
|
||||||
ARM_MODE_ANY = -1
|
ARM_MODE_ANY = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,6 +109,8 @@ struct arm {
|
||||||
* ARM_MODE_ANY indicates the standard set of 37 registers,
|
* ARM_MODE_ANY indicates the standard set of 37 registers,
|
||||||
* seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three
|
* seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three
|
||||||
* more registers are shadowed, for "Secure Monitor" mode.
|
* 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;
|
enum arm_mode core_type;
|
||||||
|
|
||||||
|
|
|
@ -1426,10 +1426,12 @@ int arm_init_arch_info(struct target *target, struct arm *armv4_5)
|
||||||
armv4_5->target = target;
|
armv4_5->target = target;
|
||||||
|
|
||||||
armv4_5->common_magic = ARM_COMMON_MAGIC;
|
armv4_5->common_magic = ARM_COMMON_MAGIC;
|
||||||
arm_set_cpsr(armv4_5, ARM_MODE_USR);
|
|
||||||
|
|
||||||
/* core_type may be overridden by subtype logic */
|
/* core_type may be overridden by subtype logic */
|
||||||
|
if (armv4_5->core_type != ARM_MODE_THREAD) {
|
||||||
armv4_5->core_type = ARM_MODE_ANY;
|
armv4_5->core_type = ARM_MODE_ANY;
|
||||||
|
arm_set_cpsr(armv4_5, ARM_MODE_USR);
|
||||||
|
}
|
||||||
|
|
||||||
/* default full_context() has no core-specific optimizations */
|
/* default full_context() has no core-specific optimizations */
|
||||||
if (!armv4_5->full_context && armv4_5->read_core_reg)
|
if (!armv4_5->full_context && armv4_5->read_core_reg)
|
||||||
|
|
|
@ -473,6 +473,7 @@ int armv7m_run_algorithm(struct target *target,
|
||||||
int armv7m_arch_state(struct target *target)
|
int armv7m_arch_state(struct target *target)
|
||||||
{
|
{
|
||||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
struct arm *arm = &armv7m->arm;
|
||||||
uint32_t ctrl, sp;
|
uint32_t ctrl, sp;
|
||||||
|
|
||||||
ctrl = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
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),
|
debug_reason_name(target),
|
||||||
armv7m_mode_strings[armv7m->core_mode],
|
armv7m_mode_strings[armv7m->core_mode],
|
||||||
armv7m_exception_string(armv7m->exception_number),
|
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),
|
buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_PC].value, 0, 32),
|
||||||
(ctrl & 0x02) ? 'p' : 'm',
|
(ctrl & 0x02) ? 'p' : 'm',
|
||||||
sp);
|
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 reg_cache *armv7m_build_reg_cache(struct target *target)
|
||||||
{
|
{
|
||||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
struct arm *arm = &armv7m->arm;
|
||||||
int num_regs = ARMV7M_NUM_REGS;
|
int num_regs = ARMV7M_NUM_REGS;
|
||||||
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
|
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
|
||||||
struct reg_cache *cache = malloc(sizeof(struct 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];
|
reg_list[i].arch_info = &arch_info[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arm->cpsr = reg_list + ARMV7M_xPSR;
|
||||||
|
arm->core_cache = cache;
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets up target as a generic ARMv7-M core */
|
/** Sets up target as a generic ARMv7-M core */
|
||||||
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
|
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
|
||||||
{
|
{
|
||||||
|
struct arm *arm = &armv7m->arm;
|
||||||
|
|
||||||
armv7m->common_magic = ARMV7M_COMMON_MAGIC;
|
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->read_core_reg = armv7m_read_core_reg;
|
||||||
armv7m->write_core_reg = armv7m_write_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. */
|
/** Generates a CRC32 checksum of a memory region. */
|
||||||
|
|
|
@ -100,6 +100,8 @@ enum
|
||||||
|
|
||||||
struct armv7m_common
|
struct armv7m_common
|
||||||
{
|
{
|
||||||
|
struct arm arm;
|
||||||
|
|
||||||
int common_magic;
|
int common_magic;
|
||||||
struct reg_cache *core_cache;
|
struct reg_cache *core_cache;
|
||||||
enum armv7m_mode core_mode;
|
enum armv7m_mode core_mode;
|
||||||
|
@ -128,7 +130,7 @@ struct armv7m_common
|
||||||
static inline struct armv7m_common *
|
static inline struct armv7m_common *
|
||||||
target_to_armv7m(struct target *target)
|
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)
|
static inline bool is_armv7m(struct armv7m_common *armv7m)
|
||||||
|
|
|
@ -323,6 +323,24 @@ static int cortex_m3_examine_exception_reason(struct target *target)
|
||||||
return ERROR_OK;
|
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)
|
static int cortex_m3_debug_entry(struct target *target)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -330,6 +348,7 @@ static int cortex_m3_debug_entry(struct target *target)
|
||||||
int retval;
|
int retval;
|
||||||
struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
|
struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
|
||||||
struct armv7m_common *armv7m = &cortex_m3->armv7m;
|
struct armv7m_common *armv7m = &cortex_m3->armv7m;
|
||||||
|
struct arm *arm = &armv7m->arm;
|
||||||
struct swjdp_common *swjdp = &armv7m->swjdp_info;
|
struct swjdp_common *swjdp = &armv7m->swjdp_info;
|
||||||
struct reg *r;
|
struct reg *r;
|
||||||
|
|
||||||
|
@ -377,11 +396,27 @@ static int cortex_m3_debug_entry(struct target *target)
|
||||||
{
|
{
|
||||||
armv7m->core_mode = ARMV7M_MODE_HANDLER;
|
armv7m->core_mode = ARMV7M_MODE_HANDLER;
|
||||||
armv7m->exception_number = (xPSR & 0x1FF);
|
armv7m->exception_number = (xPSR & 0x1FF);
|
||||||
|
|
||||||
|
arm->core_mode = ARM_MODE_HANDLER;
|
||||||
|
arm->map = armv7m_msp_reg_map;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
armv7m->core_mode = buf_get_u32(armv7m->core_cache
|
unsigned control = buf_get_u32(armv7m->core_cache
|
||||||
->reg_list[ARMV7M_CONTROL].value, 0, 1);
|
->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;
|
armv7m->exception_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue