semihosting armv7a: Add support for ARMv7-A

Add semihosting support for ARMv7-A based processors.

Tested with custom Vybrid VF610 based board
and Pandaboard ES (Rev. B1) board (Cortex-A9).

Change-Id: I6b896a61c1c6a1c5dcf89de834486f82dd6c80a2
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Tsung-Han Lin <tsunghan.tw@gmail.com>
Reviewed-on: http://openocd.zylin.com/2908
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
This commit is contained in:
Andrey Smirnov 2015-08-08 15:18:16 -07:00 committed by Freddie Chopin
parent b10037a0b7
commit d1bdcdcc8d
4 changed files with 89 additions and 4 deletions

View File

@ -39,8 +39,10 @@
#include "armv4_5.h" #include "armv4_5.h"
#include "arm7_9_common.h" #include "arm7_9_common.h"
#include "armv7m.h" #include "armv7m.h"
#include "armv7a.h"
#include "cortex_m.h" #include "cortex_m.h"
#include "register.h" #include "register.h"
#include "arm_opcodes.h"
#include "arm_semihosting.h" #include "arm_semihosting.h"
#include <helper/binarybuffer.h> #include <helper/binarybuffer.h>
#include <helper/log.h> #include <helper/log.h>
@ -415,7 +417,8 @@ static int do_semihosting(struct target *target)
/* REVISIT this looks wrong ... ARM11 and Cortex-A8 /* REVISIT this looks wrong ... ARM11 and Cortex-A8
* should work this way at least sometimes. * should work this way at least sometimes.
*/ */
if (is_arm7_9(target_to_arm7_9(target))) { if (is_arm7_9(target_to_arm7_9(target)) ||
is_armv7a(target_to_armv7a(target))) {
uint32_t spsr; uint32_t spsr;
/* return value in R0 */ /* return value in R0 */
@ -468,20 +471,42 @@ static int do_semihosting(struct target *target)
int arm_semihosting(struct target *target, int *retval) int arm_semihosting(struct target *target, int *retval)
{ {
struct arm *arm = target_to_arm(target); struct arm *arm = target_to_arm(target);
struct armv7a_common *armv7a = target_to_armv7a(target);
uint32_t pc, lr, spsr; uint32_t pc, lr, spsr;
struct reg *r; struct reg *r;
if (!arm->is_semihosting) if (!arm->is_semihosting)
return 0; return 0;
if (is_arm7_9(target_to_arm7_9(target))) { if (is_arm7_9(target_to_arm7_9(target)) ||
is_armv7a(armv7a)) {
uint32_t vbar = 0x00000000;
if (arm->core_mode != ARM_MODE_SVC) if (arm->core_mode != ARM_MODE_SVC)
return 0; return 0;
if (is_armv7a(armv7a)) {
struct arm_dpm *dpm = armv7a->arm.dpm;
*retval = dpm->prepare(dpm);
if (*retval == ERROR_OK) {
*retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 12, 0, 0),
&vbar);
dpm->finish(dpm);
if (*retval != ERROR_OK)
return 1;
} else {
return 1;
}
}
/* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
r = arm->pc; r = arm->pc;
pc = buf_get_u32(r->value, 0, 32); pc = buf_get_u32(r->value, 0, 32);
if (pc != 0x00000008 && pc != 0xffff0008) if (pc != (vbar + 0x00000008) && pc != 0xffff0008)
return 0; return 0;
r = arm_reg_current(arm, 14); r = arm_reg_current(arm, 14);

View File

@ -679,11 +679,40 @@ done:
} }
static int armv7a_setup_semihosting(struct target *target, int enable)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
uint32_t vcr;
int ret;
ret = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_VCR,
&vcr);
if (ret < 0) {
LOG_ERROR("Failed to read VCR register\n");
return ret;
}
if (enable)
vcr |= DBG_VCR_SVC_MASK;
else
vcr &= ~DBG_VCR_SVC_MASK;
ret = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_VCR,
vcr);
if (ret < 0)
LOG_ERROR("Failed to write VCR register\n");
return ret;
}
int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
{ {
struct arm *arm = &armv7a->arm; struct arm *arm = &armv7a->arm;
arm->arch_info = armv7a; arm->arch_info = armv7a;
target->arch_info = &armv7a->arm; target->arch_info = &armv7a->arm;
arm->setup_semihosting = armv7a_setup_semihosting;
/* target is useful in all function arm v4 5 compatible */ /* target is useful in all function arm v4 5 compatible */
armv7a->arm.target = target; armv7a->arm.target = target;
armv7a->arm.common_magic = ARM_COMMON_MAGIC; armv7a->arm.common_magic = ARM_COMMON_MAGIC;

View File

@ -134,6 +134,12 @@ target_to_armv7a(struct target *target)
return container_of(target->arch_info, struct armv7a_common, arm); return container_of(target->arch_info, struct armv7a_common, arm);
} }
static inline bool is_armv7a(struct armv7a_common *armv7a)
{
return armv7a->common_magic == ARMV7_COMMON_MAGIC;
}
/* register offsets from armv7a.debug_base */ /* register offsets from armv7a.debug_base */
/* See ARMv7a arch spec section C10.2 */ /* See ARMv7a arch spec section C10.2 */
@ -172,6 +178,13 @@ target_to_armv7a(struct target *target)
/* See ARMv7a arch spec section C10.8 */ /* See ARMv7a arch spec section C10.8 */
#define CPUDBG_AUTHSTATUS 0xFB8 #define CPUDBG_AUTHSTATUS 0xFB8
/* Masks for Vector Catch register */
#define DBG_VCR_FIQ_MASK ((1 << 31) | (1 << 7))
#define DBG_VCR_IRQ_MASK ((1 << 30) | (1 << 6))
#define DBG_VCR_DATA_ABORT_MASK ((1 << 28) | (1 << 4))
#define DBG_VCR_PREF_ABORT_MASK ((1 << 27) | (1 << 3))
#define DBG_VCR_SVC_MASK ((1 << 26) | (1 << 2))
int armv7a_arch_state(struct target *target); int armv7a_arch_state(struct target *target);
int armv7a_identify_cache(struct target *target); int armv7a_identify_cache(struct target *target);
int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a); int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a);

View File

@ -53,6 +53,7 @@
#include "target_request.h" #include "target_request.h"
#include "target_type.h" #include "target_type.h"
#include "arm_opcodes.h" #include "arm_opcodes.h"
#include "arm_semihosting.h"
#include <helper/time_support.h> #include <helper/time_support.h>
static int cortex_a_poll(struct target *target); static int cortex_a_poll(struct target *target);
@ -915,6 +916,10 @@ static int cortex_a_poll(struct target *target)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
} }
if (arm_semihosting(target, &retval) != 0)
return retval;
target_call_event_callbacks(target, target_call_event_callbacks(target,
TARGET_EVENT_HALTED); TARGET_EVENT_HALTED);
} }
@ -1201,7 +1206,7 @@ static int cortex_a_resume(struct target *target, int current,
static int cortex_a_debug_entry(struct target *target) static int cortex_a_debug_entry(struct target *target)
{ {
int i; int i;
uint32_t regfile[16], cpsr, dscr; uint32_t regfile[16], cpsr, spsr, dscr;
int retval = ERROR_OK; int retval = ERROR_OK;
struct working_area *regfile_working_area = NULL; struct working_area *regfile_working_area = NULL;
struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target);
@ -1250,6 +1255,7 @@ static int cortex_a_debug_entry(struct target *target)
if (cortex_a->fast_reg_read) if (cortex_a->fast_reg_read)
target_alloc_working_area(target, 64, &regfile_working_area); target_alloc_working_area(target, 64, &regfile_working_area);
/* First load register acessible through core debug port*/ /* First load register acessible through core debug port*/
if (!regfile_working_area) if (!regfile_working_area)
retval = arm_dpm_read_current_registers(&armv7a->dpm); retval = arm_dpm_read_current_registers(&armv7a->dpm);
@ -1294,6 +1300,17 @@ static int cortex_a_debug_entry(struct target *target)
reg->dirty = reg->valid; reg->dirty = reg->valid;
} }
/* read Saved PSR */
retval = cortex_a_dap_read_coreregister_u32(target, &spsr, 17);
/* store current spsr */
if (retval != ERROR_OK)
return retval;
reg = arm->spsr;
buf_set_u32(reg->value, 0, 32, spsr);
reg->valid = 1;
reg->dirty = 0;
#if 0 #if 0
/* TODO, Move this */ /* TODO, Move this */
uint32_t cp15_control_register, cp15_cacr, cp15_nacr; uint32_t cp15_control_register, cp15_cacr, cp15_nacr;
@ -2953,6 +2970,7 @@ static int cortex_a_examine_first(struct target *target)
struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct adiv5_dap *swjdp = armv7a->arm.dap; struct adiv5_dap *swjdp = armv7a->arm.dap;
int i; int i;
int retval = ERROR_OK; int retval = ERROR_OK;
uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg; uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg;