Merge branch 'riscv' into sba_tests
This commit is contained in:
@@ -4,7 +4,9 @@ else
|
||||
OOCD_TRACE_FILES =
|
||||
endif
|
||||
|
||||
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la
|
||||
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
|
||||
%D%/riscv/libriscv.la
|
||||
|
||||
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
|
||||
@@ -21,7 +23,6 @@ noinst_LTLIBRARIES += %D%/libtarget.la
|
||||
$(NDS32_SRC) \
|
||||
$(STM8_SRC) \
|
||||
$(INTEL_IA32_SRC) \
|
||||
$(RISCV_SRC) \
|
||||
%D%/avrt.c \
|
||||
%D%/dsp563xx.c \
|
||||
%D%/dsp563xx_once.c \
|
||||
@@ -40,6 +41,7 @@ TARGET_CORE_SRC = \
|
||||
%D%/target.c \
|
||||
%D%/target_request.c \
|
||||
%D%/testee.c \
|
||||
%D%/semihosting_common.c \
|
||||
%D%/smp.c
|
||||
|
||||
ARMV4_5_SRC = \
|
||||
@@ -89,6 +91,7 @@ ARM_DEBUG_SRC = \
|
||||
%D%/arm_simulator.c \
|
||||
%D%/arm_semihosting.c \
|
||||
%D%/arm_adi_v5.c \
|
||||
%D%/arm_dap.c \
|
||||
%D%/armv7a_cache.c \
|
||||
%D%/armv7a_cache_l2x.c \
|
||||
%D%/adi_v5_jtag.c \
|
||||
@@ -135,13 +138,6 @@ INTEL_IA32_SRC = \
|
||||
%D%/lakemont.c \
|
||||
%D%/x86_32_common.c
|
||||
|
||||
RISCV_SRC = \
|
||||
%D%/riscv/riscv-011.c \
|
||||
%D%/riscv/riscv-013.c \
|
||||
%D%/riscv/riscv.c \
|
||||
%D%/riscv/program.c \
|
||||
%D%/riscv/batch.c
|
||||
|
||||
%C%_libtarget_la_SOURCES += \
|
||||
%D%/algorithm.h \
|
||||
%D%/arm.h \
|
||||
@@ -217,9 +213,11 @@ RISCV_SRC = \
|
||||
%D%/nds32_v3.h \
|
||||
%D%/nds32_v3m.h \
|
||||
%D%/nds32_aice.h \
|
||||
%D%/semihosting_common.h \
|
||||
%D%/stm8.h \
|
||||
%D%/lakemont.h \
|
||||
%D%/x86_32_common.h \
|
||||
%D%/arm_cti.h
|
||||
|
||||
include %D%/openrisc/Makefile.am
|
||||
include %D%/riscv/Makefile.am
|
||||
|
||||
+299
-29
@@ -28,6 +28,7 @@
|
||||
#include "target_type.h"
|
||||
#include "armv8_opcodes.h"
|
||||
#include "armv8_cache.h"
|
||||
#include "arm_semihosting.h"
|
||||
#include <helper/time_support.h>
|
||||
|
||||
enum restart_mode {
|
||||
@@ -40,6 +41,11 @@ enum halt_mode {
|
||||
HALT_SYNC,
|
||||
};
|
||||
|
||||
struct aarch64_private_config {
|
||||
struct adiv5_private_config adiv5_config;
|
||||
struct arm_cti *cti;
|
||||
};
|
||||
|
||||
static int aarch64_poll(struct target *target);
|
||||
static int aarch64_debug_entry(struct target *target);
|
||||
static int aarch64_restore_context(struct target *target, bool bpwp);
|
||||
@@ -452,7 +458,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug
|
||||
struct target *curr;
|
||||
|
||||
if (debug_reason == DBG_REASON_NOTHALTED) {
|
||||
LOG_INFO("Halting remaining targets in SMP group");
|
||||
LOG_DEBUG("Halting remaining targets in SMP group");
|
||||
aarch64_halt_smp(target, true);
|
||||
}
|
||||
|
||||
@@ -517,6 +523,9 @@ static int aarch64_poll(struct target *target)
|
||||
if (target->smp)
|
||||
update_halt_gdb(target, debug_reason);
|
||||
|
||||
if (arm_semihosting(target, &retval) != 0)
|
||||
return retval;
|
||||
|
||||
switch (prev_target_state) {
|
||||
case TARGET_RUNNING:
|
||||
case TARGET_UNKNOWN:
|
||||
@@ -538,6 +547,9 @@ static int aarch64_poll(struct target *target)
|
||||
|
||||
static int aarch64_halt(struct target *target)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT;
|
||||
|
||||
if (target->smp)
|
||||
return aarch64_halt_smp(target, false);
|
||||
|
||||
@@ -826,6 +838,9 @@ static int aarch64_resume(struct target *target, int current,
|
||||
int retval = 0;
|
||||
uint64_t addr = address;
|
||||
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
|
||||
@@ -1064,6 +1079,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
int retval;
|
||||
uint32_t edecr;
|
||||
|
||||
armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
@@ -1086,7 +1103,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->smp && !handle_breakpoints) {
|
||||
if (target->smp && (current == 1)) {
|
||||
/*
|
||||
* isolate current target so that it doesn't get resumed
|
||||
* together with the others
|
||||
@@ -1677,17 +1694,19 @@ static int aarch64_deassert_reset(struct target *target)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = aarch64_init_debug_access(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->reset_halt) {
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||
target_name(target));
|
||||
retval = target_halt(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return aarch64_init_debug_access(target);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int aarch64_write_cpu_memory_slow(struct target *target,
|
||||
@@ -1861,7 +1880,7 @@ static int aarch64_write_cpu_memory(struct target *target,
|
||||
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
|
||||
/* Abort occurred - clear it and exit */
|
||||
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
armv8_dpm_handle_exception(dpm, true);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -2080,7 +2099,7 @@ static int aarch64_read_cpu_memory(struct target *target,
|
||||
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
|
||||
/* Abort occurred - clear it and exit */
|
||||
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
armv8_dpm_handle_exception(dpm, true);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -2198,7 +2217,7 @@ static int aarch64_examine_first(struct target *target)
|
||||
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
||||
struct armv8_common *armv8 = &aarch64->armv8_common;
|
||||
struct adiv5_dap *swjdp = armv8->arm.dap;
|
||||
uint32_t cti_base;
|
||||
struct aarch64_private_config *pc;
|
||||
int i;
|
||||
int retval = ERROR_OK;
|
||||
uint64_t debug, ttypr;
|
||||
@@ -2206,10 +2225,6 @@ static int aarch64_examine_first(struct target *target)
|
||||
uint32_t tmp0, tmp1, tmp2, tmp3;
|
||||
debug = ttypr = cpuid = 0;
|
||||
|
||||
retval = dap_dp_init(swjdp);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Search for the APB-AB - it is needed for access to debug registers */
|
||||
retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap);
|
||||
if (retval != ERROR_OK) {
|
||||
@@ -2289,17 +2304,15 @@ static int aarch64_examine_first(struct target *target)
|
||||
LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr);
|
||||
LOG_DEBUG("debug = 0x%08" PRIx64, debug);
|
||||
|
||||
if (target->ctibase == 0) {
|
||||
/* assume a v8 rom table layout */
|
||||
cti_base = armv8->debug_base + 0x10000;
|
||||
LOG_INFO("Target ctibase is not set, assuming 0x%0" PRIx32, cti_base);
|
||||
} else
|
||||
cti_base = target->ctibase;
|
||||
|
||||
armv8->cti = arm_cti_create(armv8->debug_ap, cti_base);
|
||||
if (armv8->cti == NULL)
|
||||
if (target->private_config == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
pc = (struct aarch64_private_config *)target->private_config;
|
||||
if (pc->cti == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
armv8->cti = pc->cti;
|
||||
|
||||
retval = aarch64_dpm_setup(aarch64, debug);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -2352,22 +2365,18 @@ static int aarch64_init_target(struct command_context *cmd_ctx,
|
||||
struct target *target)
|
||||
{
|
||||
/* examine_first() does a bunch of this */
|
||||
arm_semihosting_init(target);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aarch64_init_arch_info(struct target *target,
|
||||
struct aarch64_common *aarch64, struct jtag_tap *tap)
|
||||
struct aarch64_common *aarch64, struct adiv5_dap *dap)
|
||||
{
|
||||
struct armv8_common *armv8 = &aarch64->armv8_common;
|
||||
|
||||
/* Setup struct aarch64_common */
|
||||
aarch64->common_magic = AARCH64_COMMON_MAGIC;
|
||||
/* tap has no dap initialized */
|
||||
if (!tap->dap) {
|
||||
tap->dap = dap_init();
|
||||
tap->dap->tap = tap;
|
||||
}
|
||||
armv8->arm.dap = tap->dap;
|
||||
armv8->arm.dap = dap;
|
||||
|
||||
/* register arch-specific functions */
|
||||
armv8->examine_debug_reason = NULL;
|
||||
@@ -2383,9 +2392,27 @@ static int aarch64_init_arch_info(struct target *target,
|
||||
|
||||
static int aarch64_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct aarch64_private_config *pc = target->private_config;
|
||||
struct aarch64_common *aarch64 = calloc(1, sizeof(struct aarch64_common));
|
||||
|
||||
return aarch64_init_arch_info(target, aarch64, target->tap);
|
||||
if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap);
|
||||
}
|
||||
|
||||
static void aarch64_deinit_target(struct target *target)
|
||||
{
|
||||
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
||||
struct armv8_common *armv8 = &aarch64->armv8_common;
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
|
||||
armv8_free_reg_cache(target);
|
||||
free(aarch64->brp_list);
|
||||
free(dpm->dbp);
|
||||
free(dpm->dwp);
|
||||
free(target->private_config);
|
||||
free(aarch64);
|
||||
}
|
||||
|
||||
static int aarch64_mmu(struct target *target, int *enabled)
|
||||
@@ -2405,6 +2432,94 @@ static int aarch64_virt2phys(struct target *target, target_addr_t virt,
|
||||
return armv8_mmu_translate_va_pa(target, virt, phys, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* private target configuration items
|
||||
*/
|
||||
enum aarch64_cfg_param {
|
||||
CFG_CTI,
|
||||
};
|
||||
|
||||
static const Jim_Nvp nvp_config_opts[] = {
|
||||
{ .name = "-cti", .value = CFG_CTI },
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi)
|
||||
{
|
||||
struct aarch64_private_config *pc;
|
||||
Jim_Nvp *n;
|
||||
int e;
|
||||
|
||||
pc = (struct aarch64_private_config *)target->private_config;
|
||||
if (pc == NULL) {
|
||||
pc = calloc(1, sizeof(struct aarch64_private_config));
|
||||
target->private_config = pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call adiv5_jim_configure() to parse the common DAP options
|
||||
* It will return JIM_CONTINUE if it didn't find any known
|
||||
* options, JIM_OK if it correctly parsed the topmost option
|
||||
* and JIM_ERR if an error occured during parameter evaluation.
|
||||
* For JIM_CONTINUE, we check our own params.
|
||||
*/
|
||||
e = adiv5_jim_configure(target, goi);
|
||||
if (e != JIM_CONTINUE)
|
||||
return e;
|
||||
|
||||
/* parse config or cget options ... */
|
||||
if (goi->argc > 0) {
|
||||
Jim_SetEmptyResult(goi->interp);
|
||||
|
||||
/* check first if topmost item is for us */
|
||||
e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts,
|
||||
goi->argv[0], &n);
|
||||
if (e != JIM_OK)
|
||||
return JIM_CONTINUE;
|
||||
|
||||
e = Jim_GetOpt_Obj(goi, NULL);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
switch (n->value) {
|
||||
case CFG_CTI: {
|
||||
if (goi->isconfigure) {
|
||||
Jim_Obj *o_cti;
|
||||
struct arm_cti *cti;
|
||||
e = Jim_GetOpt_Obj(goi, &o_cti);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
cti = cti_instance_by_jim_obj(goi->interp, o_cti);
|
||||
if (cti == NULL) {
|
||||
Jim_SetResultString(goi->interp, "CTI name invalid!", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
pc->cti = cti;
|
||||
} else {
|
||||
if (goi->argc != 0) {
|
||||
Jim_WrongNumArgs(goi->interp,
|
||||
goi->argc, goi->argv,
|
||||
"NO PARAMS");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (pc == NULL || pc->cti == NULL) {
|
||||
Jim_SetResultString(goi->interp, "CTI not configured", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return JIM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(aarch64_handle_cache_info_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
@@ -2490,6 +2605,143 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
{
|
||||
struct command_context *context;
|
||||
struct target *target;
|
||||
struct arm *arm;
|
||||
int retval;
|
||||
bool is_mcr = false;
|
||||
int arg_cnt = 0;
|
||||
|
||||
if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) {
|
||||
is_mcr = true;
|
||||
arg_cnt = 7;
|
||||
} else {
|
||||
arg_cnt = 6;
|
||||
}
|
||||
|
||||
context = current_command_context(interp);
|
||||
assert(context != NULL);
|
||||
|
||||
target = get_current_target(context);
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("%s: no current target", __func__);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("%s: not yet examined", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
arm = target_to_arm(target);
|
||||
if (!is_arm(arm)) {
|
||||
LOG_ERROR("%s: not an ARM", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
LOG_ERROR("%s: not 32-bit arm target", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (argc != arg_cnt) {
|
||||
LOG_ERROR("%s: wrong number of arguments", __func__);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
int cpnum;
|
||||
uint32_t op1;
|
||||
uint32_t op2;
|
||||
uint32_t CRn;
|
||||
uint32_t CRm;
|
||||
uint32_t value;
|
||||
long l;
|
||||
|
||||
/* NOTE: parameter sequence matches ARM instruction set usage:
|
||||
* MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX
|
||||
* MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX
|
||||
* The "rX" is necessarily omitted; it uses Tcl mechanisms.
|
||||
*/
|
||||
retval = Jim_GetLong(interp, argv[1], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"coprocessor", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
cpnum = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[2], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0x7) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"op1", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
op1 = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[3], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"CRn", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
CRn = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[4], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"CRm", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
CRm = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[5], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0x7) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"op2", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
op2 = l;
|
||||
|
||||
value = 0;
|
||||
|
||||
if (is_mcr == true) {
|
||||
retval = Jim_GetLong(interp, argv[6], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
value = l;
|
||||
|
||||
/* NOTE: parameters reordered! */
|
||||
/* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */
|
||||
retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value);
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
} else {
|
||||
/* NOTE: parameters reordered! */
|
||||
/* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */
|
||||
retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
|
||||
Jim_SetResult(interp, Jim_NewIntObj(interp, value));
|
||||
}
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration aarch64_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cache_info",
|
||||
@@ -2525,9 +2777,25 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
|
||||
.help = "mask aarch64 interrupts during single-step",
|
||||
.usage = "['on'|'off']",
|
||||
},
|
||||
{
|
||||
.name = "mcr",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_mcrmrc,
|
||||
.help = "write coprocessor register",
|
||||
.usage = "cpnum op1 CRn CRm op2 value",
|
||||
},
|
||||
{
|
||||
.name = "mrc",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_mcrmrc,
|
||||
.help = "read coprocessor register",
|
||||
.usage = "cpnum op1 CRn CRm op2",
|
||||
},
|
||||
|
||||
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration aarch64_command_handlers[] = {
|
||||
{
|
||||
.chain = armv8_command_handlers,
|
||||
@@ -2570,7 +2838,9 @@ struct target_type aarch64_target = {
|
||||
|
||||
.commands = aarch64_command_handlers,
|
||||
.target_create = aarch64_target_create,
|
||||
.target_jim_configure = aarch64_jim_configure,
|
||||
.init_target = aarch64_init_target,
|
||||
.deinit_target = aarch64_deinit_target,
|
||||
.examine = aarch64_examine,
|
||||
|
||||
.read_phys_memory = aarch64_read_phys_memory,
|
||||
|
||||
@@ -553,7 +553,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
|
||||
static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval;
|
||||
uint32_t ctrlstat;
|
||||
uint32_t ctrlstat, pwrmask;
|
||||
|
||||
/* too expensive to call keep_alive() here */
|
||||
|
||||
@@ -571,9 +571,12 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
|
||||
if (ctrlstat & SSTICKYERR) {
|
||||
LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
|
||||
/* Check power to debug regions */
|
||||
if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) !=
|
||||
(CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) {
|
||||
pwrmask = CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ;
|
||||
if (!dap->ignore_syspwrupack)
|
||||
pwrmask |= CSYSPWRUPACK;
|
||||
if ((ctrlstat & pwrmask) != pwrmask) {
|
||||
LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened");
|
||||
dap->do_reconnect = true;
|
||||
}
|
||||
|
||||
if (ctrlstat & SSTICKYERR)
|
||||
@@ -598,6 +601,20 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int jtag_connect(struct adiv5_dap *dap)
|
||||
{
|
||||
dap->do_reconnect = false;
|
||||
return dap_dp_init(dap);
|
||||
}
|
||||
|
||||
static int jtag_check_reconnect(struct adiv5_dap *dap)
|
||||
{
|
||||
if (dap->do_reconnect)
|
||||
return jtag_connect(dap);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
@@ -633,7 +650,11 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg)
|
||||
static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
int retval = jtag_ap_q_bankselect(ap, reg);
|
||||
int retval = jtag_check_reconnect(ap->dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = jtag_ap_q_bankselect(ap, reg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
@@ -647,7 +668,11 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg,
|
||||
static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg,
|
||||
uint32_t data)
|
||||
{
|
||||
int retval = jtag_ap_q_bankselect(ap, reg);
|
||||
int retval = jtag_check_reconnect(ap->dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = jtag_ap_q_bankselect(ap, reg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
@@ -692,6 +717,7 @@ static int jtag_dp_sync(struct adiv5_dap *dap)
|
||||
* part of DAP setup
|
||||
*/
|
||||
const struct dap_ops jtag_dp_ops = {
|
||||
.connect = jtag_connect,
|
||||
.queue_dp_read = jtag_dp_q_read,
|
||||
.queue_dp_write = jtag_dp_q_write,
|
||||
.queue_ap_read = jtag_ap_q_read,
|
||||
|
||||
+31
-40
@@ -53,13 +53,11 @@
|
||||
|
||||
#include <jtag/swd.h>
|
||||
|
||||
/* YUK! - but this is currently a global.... */
|
||||
extern struct jtag_interface *jtag_interface;
|
||||
static bool do_sync;
|
||||
|
||||
static void swd_finish_read(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
if (dap->last_read != NULL) {
|
||||
swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0);
|
||||
dap->last_read = NULL;
|
||||
@@ -73,7 +71,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
|
||||
static void swd_clear_sticky_errors(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||
@@ -82,7 +80,7 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap)
|
||||
|
||||
static int swd_run_inner(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
int retval;
|
||||
|
||||
retval = swd->run();
|
||||
@@ -97,6 +95,7 @@ static int swd_run_inner(struct adiv5_dap *dap)
|
||||
|
||||
static int swd_connect(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
uint32_t dpidr;
|
||||
int status;
|
||||
|
||||
@@ -120,7 +119,7 @@ static int swd_connect(struct adiv5_dap *dap)
|
||||
}
|
||||
|
||||
/* Note, debugport_init() does setup too */
|
||||
jtag_interface->swd->switch_seq(JTAG_TO_SWD);
|
||||
swd->switch_seq(JTAG_TO_SWD);
|
||||
|
||||
/* Clear link state, including the SELECT cache. */
|
||||
dap->do_reconnect = false;
|
||||
@@ -136,6 +135,7 @@ static int swd_connect(struct adiv5_dap *dap)
|
||||
if (status == ERROR_OK) {
|
||||
LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr);
|
||||
dap->do_reconnect = false;
|
||||
status = dap_dp_init(dap);
|
||||
} else
|
||||
dap->do_reconnect = true;
|
||||
|
||||
@@ -157,7 +157,7 @@ static int swd_check_reconnect(struct adiv5_dap *dap)
|
||||
|
||||
static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||
@@ -187,7 +187,7 @@ static void swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg)
|
||||
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
@@ -203,7 +203,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t data)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
@@ -236,10 +236,9 @@ static void swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg)
|
||||
static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
assert(swd);
|
||||
|
||||
struct adiv5_dap *dap = ap->dap;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -255,10 +254,9 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
|
||||
static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
|
||||
uint32_t data)
|
||||
{
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
assert(swd);
|
||||
|
||||
struct adiv5_dap *dap = ap->dap;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -278,13 +276,25 @@ static int swd_run(struct adiv5_dap *dap)
|
||||
return swd_run_inner(dap);
|
||||
}
|
||||
|
||||
/** Put the SWJ-DP back to JTAG mode */
|
||||
static void swd_quit(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
|
||||
swd->switch_seq(SWD_TO_JTAG);
|
||||
/* flush the queue before exit */
|
||||
swd->run();
|
||||
}
|
||||
|
||||
const struct dap_ops swd_dap_ops = {
|
||||
.connect = swd_connect,
|
||||
.queue_dp_read = swd_queue_dp_read,
|
||||
.queue_dp_write = swd_queue_dp_write,
|
||||
.queue_ap_read = swd_queue_ap_read,
|
||||
.queue_ap_write = swd_queue_ap_write,
|
||||
.queue_ap_abort = swd_queue_ap_abort,
|
||||
.run = swd_run,
|
||||
.quit = swd_quit,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -381,15 +391,15 @@ static const struct command_registration swd_handlers[] = {
|
||||
|
||||
static int swd_select(struct command_context *ctx)
|
||||
{
|
||||
/* FIXME: only place where global 'jtag_interface' is still needed */
|
||||
extern struct jtag_interface *jtag_interface;
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
int retval;
|
||||
|
||||
retval = register_commands(ctx, NULL, swd_handlers);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
const struct swd_driver *swd = jtag_interface->swd;
|
||||
|
||||
/* be sure driver is in SWD mode; start
|
||||
* with hardware default TRN (1), it can be changed later
|
||||
*/
|
||||
@@ -404,33 +414,14 @@ static int swd_select(struct command_context *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* force DAP into SWD mode (not JTAG) */
|
||||
/*retval = dap_to_swd(target);*/
|
||||
|
||||
if (ctx->current_target) {
|
||||
/* force DAP into SWD mode (not JTAG) */
|
||||
struct target *target = get_current_target(ctx);
|
||||
retval = dap_to_swd(target);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_init(struct command_context *ctx)
|
||||
{
|
||||
struct target *target = get_current_target(ctx);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
/* Force the DAP's ops vector for SWD mode.
|
||||
* messy - is there a better way? */
|
||||
arm->dap->ops = &swd_dap_ops;
|
||||
/* First connect after init is not reconnecting. */
|
||||
dap->do_reconnect = false;
|
||||
|
||||
int retval = swd_connect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("SWD connect failed");
|
||||
return retval;
|
||||
/* nothing done here, SWD is initialized
|
||||
* together with the DAP */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static struct transport swd_transport = {
|
||||
|
||||
+52
-23
@@ -8,6 +8,9 @@
|
||||
* Copyright (C) 2009 by Øyvind Harboe
|
||||
* oyvind.harboe@zylin.com
|
||||
*
|
||||
* Copyright (C) 2018 by Liviu Ionescu
|
||||
* <ilg@livius.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -28,7 +31,6 @@
|
||||
#include <helper/command.h>
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Holds the interface to ARM cores.
|
||||
@@ -77,6 +79,43 @@ enum arm_mode {
|
||||
ARM_MODE_ANY = -1
|
||||
};
|
||||
|
||||
/* VFPv3 internal register numbers mapping to d0:31 */
|
||||
enum {
|
||||
ARM_VFP_V3_D0 = 51,
|
||||
ARM_VFP_V3_D1,
|
||||
ARM_VFP_V3_D2,
|
||||
ARM_VFP_V3_D3,
|
||||
ARM_VFP_V3_D4,
|
||||
ARM_VFP_V3_D5,
|
||||
ARM_VFP_V3_D6,
|
||||
ARM_VFP_V3_D7,
|
||||
ARM_VFP_V3_D8,
|
||||
ARM_VFP_V3_D9,
|
||||
ARM_VFP_V3_D10,
|
||||
ARM_VFP_V3_D11,
|
||||
ARM_VFP_V3_D12,
|
||||
ARM_VFP_V3_D13,
|
||||
ARM_VFP_V3_D14,
|
||||
ARM_VFP_V3_D15,
|
||||
ARM_VFP_V3_D16,
|
||||
ARM_VFP_V3_D17,
|
||||
ARM_VFP_V3_D18,
|
||||
ARM_VFP_V3_D19,
|
||||
ARM_VFP_V3_D20,
|
||||
ARM_VFP_V3_D21,
|
||||
ARM_VFP_V3_D22,
|
||||
ARM_VFP_V3_D23,
|
||||
ARM_VFP_V3_D24,
|
||||
ARM_VFP_V3_D25,
|
||||
ARM_VFP_V3_D26,
|
||||
ARM_VFP_V3_D27,
|
||||
ARM_VFP_V3_D28,
|
||||
ARM_VFP_V3_D29,
|
||||
ARM_VFP_V3_D30,
|
||||
ARM_VFP_V3_D31,
|
||||
ARM_VFP_V3_FPSCR,
|
||||
};
|
||||
|
||||
const char *arm_mode_name(unsigned psr_mode);
|
||||
bool is_arm_mode(unsigned psr_mode);
|
||||
|
||||
@@ -89,6 +128,14 @@ enum arm_state {
|
||||
ARM_STATE_AARCH64,
|
||||
};
|
||||
|
||||
/** ARM vector floating point enabled, if yes which version. */
|
||||
enum arm_vfp_version {
|
||||
ARM_VFP_DISABLED,
|
||||
ARM_VFP_V1,
|
||||
ARM_VFP_V2,
|
||||
ARM_VFP_V3,
|
||||
};
|
||||
|
||||
#define ARM_COMMON_MAGIC 0x0A450A45
|
||||
|
||||
/**
|
||||
@@ -136,29 +183,11 @@ struct arm {
|
||||
/** Flag reporting armv6m based core. */
|
||||
bool is_armv6m;
|
||||
|
||||
/** Flag reporting whether semihosting is active. */
|
||||
bool is_semihosting;
|
||||
|
||||
/** Flag reporting whether semihosting fileio is active. */
|
||||
bool is_semihosting_fileio;
|
||||
|
||||
/** Flag reporting whether semihosting fileio operation is active. */
|
||||
bool semihosting_hit_fileio;
|
||||
|
||||
/** Current semihosting operation. */
|
||||
int semihosting_op;
|
||||
|
||||
/** Current semihosting result. */
|
||||
int semihosting_result;
|
||||
|
||||
/** Value to be returned by semihosting SYS_ERRNO request. */
|
||||
int semihosting_errno;
|
||||
/** Floating point or VFP version, 0 if disabled. */
|
||||
int arm_vfp_version;
|
||||
|
||||
int (*setup_semihosting)(struct target *target, int enable);
|
||||
|
||||
/** Semihosting command line. */
|
||||
char *semihosting_cmdline;
|
||||
|
||||
/** Backpointer to the target. */
|
||||
struct target *target;
|
||||
|
||||
@@ -225,7 +254,7 @@ struct arm_reg {
|
||||
enum arm_mode mode;
|
||||
struct target *target;
|
||||
struct arm *arm;
|
||||
uint8_t value[8];
|
||||
uint8_t value[16];
|
||||
};
|
||||
|
||||
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm);
|
||||
@@ -260,7 +289,7 @@ int armv4_5_run_algorithm_inner(struct target *target,
|
||||
int arm_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
||||
int arm_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
|
||||
|
||||
void arm_set_cpsr(struct arm *arm, uint32_t cpsr);
|
||||
struct reg *arm_reg_current(struct arm *arm, unsigned regnum);
|
||||
|
||||
+224
-142
@@ -76,6 +76,7 @@
|
||||
#include <helper/jep106.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/list.h>
|
||||
#include <helper/jim-nvp.h>
|
||||
|
||||
/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */
|
||||
|
||||
@@ -96,14 +97,15 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address
|
||||
|
||||
static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
|
||||
{
|
||||
csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT |
|
||||
ap->csw_default;
|
||||
csw |= ap->csw_default;
|
||||
|
||||
if (csw != ap->csw_value) {
|
||||
/* LOG_DEBUG("DAP: Set CSW %x",csw); */
|
||||
int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw);
|
||||
if (retval != ERROR_OK)
|
||||
if (retval != ERROR_OK) {
|
||||
ap->csw_value = 0;
|
||||
return retval;
|
||||
}
|
||||
ap->csw_value = csw;
|
||||
}
|
||||
return ERROR_OK;
|
||||
@@ -114,8 +116,10 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
|
||||
if (!ap->tar_valid || tar != ap->tar_value) {
|
||||
/* LOG_DEBUG("DAP: Set TAR %x",tar); */
|
||||
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
|
||||
if (retval != ERROR_OK)
|
||||
if (retval != ERROR_OK) {
|
||||
ap->tar_valid = false;
|
||||
return retval;
|
||||
}
|
||||
ap->tar_value = tar;
|
||||
ap->tar_valid = true;
|
||||
}
|
||||
@@ -152,6 +156,8 @@ static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap)
|
||||
return 2;
|
||||
case CSW_32BIT:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case CSW_ADDRINC_PACKED:
|
||||
return 4;
|
||||
@@ -614,33 +620,8 @@ int mem_ap_write_buf_noincr(struct adiv5_ap *ap,
|
||||
|
||||
#define DAP_POWER_DOMAIN_TIMEOUT (10)
|
||||
|
||||
/* FIXME don't import ... just initialize as
|
||||
* part of DAP transport setup
|
||||
*/
|
||||
extern const struct dap_ops jtag_dp_ops;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Create a new DAP
|
||||
*/
|
||||
struct adiv5_dap *dap_init(void)
|
||||
{
|
||||
struct adiv5_dap *dap = calloc(1, sizeof(struct adiv5_dap));
|
||||
int i;
|
||||
/* Set up with safe defaults */
|
||||
for (i = 0; i <= 255; i++) {
|
||||
dap->ap[i].dap = dap;
|
||||
dap->ap[i].ap_num = i;
|
||||
/* memaccess_tck max is 255 */
|
||||
dap->ap[i].memaccess_tck = 255;
|
||||
/* Number of bits for tar autoincrement, impl. dep. at least 10 */
|
||||
dap->ap[i].tar_autoincr_block = (1<<10);
|
||||
}
|
||||
INIT_LIST_HEAD(&dap->cmd_journal);
|
||||
return dap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate cached DP select and cached TAR and CSW of all APs
|
||||
*/
|
||||
@@ -667,14 +648,7 @@ int dap_dp_init(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG(" ");
|
||||
/* JTAG-DP or SWJ-DP, in JTAG mode
|
||||
* ... for SWD mode this is patched as part
|
||||
* of link switchover
|
||||
* FIXME: This should already be setup by the respective transport specific DAP creation.
|
||||
*/
|
||||
if (!dap->ops)
|
||||
dap->ops = &jtag_dp_ops;
|
||||
LOG_DEBUG("%s", adiv5_dap_name(dap));
|
||||
|
||||
dap_invalidate_cache(dap);
|
||||
|
||||
@@ -707,12 +681,14 @@ int dap_dp_init(struct adiv5_dap *dap)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
LOG_DEBUG("DAP: wait CSYSPWRUPACK");
|
||||
retval = dap_dp_poll_register(dap, DP_CTRL_STAT,
|
||||
CSYSPWRUPACK, CSYSPWRUPACK,
|
||||
DAP_POWER_DOMAIN_TIMEOUT);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!dap->ignore_syspwrupack) {
|
||||
LOG_DEBUG("DAP: wait CSYSPWRUPACK");
|
||||
retval = dap_dp_poll_register(dap, DP_CTRL_STAT,
|
||||
CSYSPWRUPACK, CSYSPWRUPACK,
|
||||
DAP_POWER_DOMAIN_TIMEOUT);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -1376,7 +1352,7 @@ static int dap_rom_display(struct command_context *cmd_ctx,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dap_info_command(struct command_context *cmd_ctx,
|
||||
int dap_info_command(struct command_context *cmd_ctx,
|
||||
struct adiv5_ap *ap)
|
||||
{
|
||||
int retval;
|
||||
@@ -1434,46 +1410,131 @@ static int dap_info_command(struct command_context *cmd_ctx,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
enum adiv5_cfg_param {
|
||||
CFG_DAP,
|
||||
CFG_AP_NUM
|
||||
};
|
||||
|
||||
static const Jim_Nvp nvp_config_opts[] = {
|
||||
{ .name = "-dap", .value = CFG_DAP },
|
||||
{ .name = "-ap-num", .value = CFG_AP_NUM },
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
|
||||
{
|
||||
struct adiv5_private_config *pc;
|
||||
const char *arg;
|
||||
jim_wide ap_num;
|
||||
int e;
|
||||
|
||||
/* check if argv[0] is for us */
|
||||
arg = Jim_GetString(goi->argv[0], NULL);
|
||||
if (strcmp(arg, "-ap-num"))
|
||||
return JIM_CONTINUE;
|
||||
|
||||
e = Jim_GetOpt_String(goi, &arg, NULL);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
if (goi->argc == 0) {
|
||||
Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-ap-num ?ap-number? ...");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
e = Jim_GetOpt_Wide(goi, &ap_num);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
if (target->private_config == NULL) {
|
||||
pc = (struct adiv5_private_config *)target->private_config;
|
||||
if (pc == NULL) {
|
||||
pc = calloc(1, sizeof(struct adiv5_private_config));
|
||||
pc->ap_num = -1;
|
||||
target->private_config = pc;
|
||||
pc->ap_num = ap_num;
|
||||
}
|
||||
|
||||
target->has_dap = true;
|
||||
|
||||
if (goi->argc > 0) {
|
||||
Jim_Nvp *n;
|
||||
|
||||
Jim_SetEmptyResult(goi->interp);
|
||||
|
||||
/* check first if topmost item is for us */
|
||||
e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts,
|
||||
goi->argv[0], &n);
|
||||
if (e != JIM_OK)
|
||||
return JIM_CONTINUE;
|
||||
|
||||
e = Jim_GetOpt_Obj(goi, NULL);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
switch (n->value) {
|
||||
case CFG_DAP:
|
||||
if (goi->isconfigure) {
|
||||
Jim_Obj *o_t;
|
||||
struct adiv5_dap *dap;
|
||||
e = Jim_GetOpt_Obj(goi, &o_t);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
dap = dap_instance_by_jim_obj(goi->interp, o_t);
|
||||
if (dap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "DAP name invalid!", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (pc->dap != NULL && pc->dap != dap) {
|
||||
Jim_SetResultString(goi->interp,
|
||||
"DAP assignment cannot be changed after target was created!", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (target->tap_configured) {
|
||||
Jim_SetResultString(goi->interp,
|
||||
"-chain-position and -dap configparams are mutually exclusive!", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
pc->dap = dap;
|
||||
target->tap = dap->tap;
|
||||
target->dap_configured = true;
|
||||
} else {
|
||||
if (goi->argc != 0) {
|
||||
Jim_WrongNumArgs(goi->interp,
|
||||
goi->argc, goi->argv,
|
||||
"NO PARAMS");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (pc->dap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "DAP not configured", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case CFG_AP_NUM:
|
||||
if (goi->isconfigure) {
|
||||
jim_wide ap_num;
|
||||
e = Jim_GetOpt_Wide(goi, &ap_num);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
pc->ap_num = ap_num;
|
||||
} else {
|
||||
if (goi->argc != 0) {
|
||||
Jim_WrongNumArgs(goi->interp,
|
||||
goi->argc, goi->argv,
|
||||
"NO PARAMS");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (pc->ap_num < 0) {
|
||||
Jim_SetResultString(goi->interp, "AP number not configured", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
int adiv5_verify_config(struct adiv5_private_config *pc)
|
||||
{
|
||||
if (pc == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (pc->dap == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_HANDLER(handle_dap_info_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apsel;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
@@ -1494,10 +1555,7 @@ COMMAND_HANDLER(handle_dap_info_command)
|
||||
|
||||
COMMAND_HANDLER(dap_baseaddr_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apsel, baseaddr;
|
||||
int retval;
|
||||
|
||||
@@ -1534,10 +1592,7 @@ COMMAND_HANDLER(dap_baseaddr_command)
|
||||
|
||||
COMMAND_HANDLER(dap_memaccess_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t memaccess_tck;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
@@ -1560,17 +1615,13 @@ COMMAND_HANDLER(dap_memaccess_command)
|
||||
|
||||
COMMAND_HANDLER(dap_apsel_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
uint32_t apsel, apid;
|
||||
int retval;
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apsel;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
case 0:
|
||||
apsel = dap->apsel;
|
||||
break;
|
||||
command_print(CMD_CTX, "%" PRIi32, dap->apsel);
|
||||
return ERROR_OK;
|
||||
case 1:
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
|
||||
/* AP address is in bits 31:24 of DP_SELECT */
|
||||
@@ -1582,42 +1633,40 @@ COMMAND_HANDLER(dap_apsel_command)
|
||||
}
|
||||
|
||||
dap->apsel = apsel;
|
||||
|
||||
retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = dap_run(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32,
|
||||
apsel, apid);
|
||||
|
||||
return retval;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(dap_apcsw_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
uint32_t apcsw = dap->ap[dap->apsel].csw_default, sprot = 0;
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apcsw = dap->ap[dap->apsel].csw_default;
|
||||
uint32_t csw_val, csw_mask;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
case 0:
|
||||
command_print(CMD_CTX, "apsel %" PRIi32 " selected, csw 0x%8.8" PRIx32,
|
||||
(dap->apsel), apcsw);
|
||||
break;
|
||||
command_print(CMD_CTX, "ap %" PRIi32 " selected, csw 0x%8.8" PRIx32,
|
||||
dap->apsel, apcsw);
|
||||
return ERROR_OK;
|
||||
case 1:
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], sprot);
|
||||
/* AP address is in bits 31:24 of DP_SELECT */
|
||||
if (sprot > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
if (sprot)
|
||||
apcsw |= CSW_SPROT;
|
||||
if (strcmp(CMD_ARGV[0], "default") == 0)
|
||||
csw_val = CSW_DEFAULT;
|
||||
else
|
||||
apcsw &= ~CSW_SPROT;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val);
|
||||
|
||||
if (csw_val & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) {
|
||||
LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
apcsw = csw_val;
|
||||
break;
|
||||
case 2:
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], csw_mask);
|
||||
if (csw_mask & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) {
|
||||
LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask);
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -1631,10 +1680,7 @@ COMMAND_HANDLER(dap_apcsw_command)
|
||||
|
||||
COMMAND_HANDLER(dap_apid_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apsel, apid;
|
||||
int retval;
|
||||
|
||||
@@ -1666,11 +1712,9 @@ COMMAND_HANDLER(dap_apid_command)
|
||||
|
||||
COMMAND_HANDLER(dap_apreg_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t apsel, reg, value;
|
||||
struct adiv5_ap *ap;
|
||||
int retval;
|
||||
|
||||
if (CMD_ARGC < 2 || CMD_ARGC > 3)
|
||||
@@ -1680,6 +1724,7 @@ COMMAND_HANDLER(dap_apreg_command)
|
||||
/* AP address is in bits 31:24 of DP_SELECT */
|
||||
if (apsel >= 256)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
ap = dap_ap(dap, apsel);
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
|
||||
if (reg >= 256 || (reg & 3))
|
||||
@@ -1687,9 +1732,21 @@ COMMAND_HANDLER(dap_apreg_command)
|
||||
|
||||
if (CMD_ARGC == 3) {
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
|
||||
retval = dap_queue_ap_write(dap_ap(dap, apsel), reg, value);
|
||||
switch (reg) {
|
||||
case MEM_AP_REG_CSW:
|
||||
ap->csw_default = 0; /* invalid, force write */
|
||||
retval = mem_ap_setup_csw(ap, value);
|
||||
break;
|
||||
case MEM_AP_REG_TAR:
|
||||
ap->tar_valid = false; /* invalid, force write */
|
||||
retval = mem_ap_setup_tar(ap, value);
|
||||
break;
|
||||
default:
|
||||
retval = dap_queue_ap_write(ap, reg, value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
retval = dap_queue_ap_read(dap_ap(dap, apsel), reg, &value);
|
||||
retval = dap_queue_ap_read(ap, reg, &value);
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
retval = dap_run(dap);
|
||||
@@ -1703,12 +1760,40 @@ COMMAND_HANDLER(dap_apreg_command)
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(dap_dpreg_command)
|
||||
{
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t reg, value;
|
||||
int retval;
|
||||
|
||||
if (CMD_ARGC < 1 || CMD_ARGC > 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg);
|
||||
if (reg >= 256 || (reg & 3))
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (CMD_ARGC == 2) {
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
||||
retval = dap_queue_dp_write(dap, reg, value);
|
||||
} else {
|
||||
retval = dap_queue_dp_read(dap, reg, &value);
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
retval = dap_run(dap);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
command_print(CMD_CTX, "0x%08" PRIx32, value);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(dap_ti_be_32_quirks_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
|
||||
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
|
||||
uint32_t enable = dap->ti_be_32_quirks;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
@@ -1729,7 +1814,7 @@ COMMAND_HANDLER(dap_ti_be_32_quirks_command)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct command_registration dap_commands[] = {
|
||||
const struct command_registration dap_instance_commands[] = {
|
||||
{
|
||||
.name = "info",
|
||||
.handler = handle_dap_info_command,
|
||||
@@ -1741,7 +1826,7 @@ static const struct command_registration dap_commands[] = {
|
||||
{
|
||||
.name = "apsel",
|
||||
.handler = dap_apsel_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "Set the currently selected AP (default 0) "
|
||||
"and display the result",
|
||||
.usage = "[ap_num]",
|
||||
@@ -1749,9 +1834,9 @@ static const struct command_registration dap_commands[] = {
|
||||
{
|
||||
.name = "apcsw",
|
||||
.handler = dap_apcsw_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Set csw access bit ",
|
||||
.usage = "[sprot]",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "Set CSW default bits",
|
||||
.usage = "[value [mask]]",
|
||||
},
|
||||
|
||||
{
|
||||
@@ -1770,6 +1855,14 @@ static const struct command_registration dap_commands[] = {
|
||||
"(reg is byte address of a word register, like 0 4 8...)",
|
||||
.usage = "ap_num reg [value]",
|
||||
},
|
||||
{
|
||||
.name = "dpreg",
|
||||
.handler = dap_dpreg_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "read/write a register from DP "
|
||||
"(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)",
|
||||
.usage = "reg [value]",
|
||||
},
|
||||
{
|
||||
.name = "baseaddr",
|
||||
.handler = dap_baseaddr_command,
|
||||
@@ -1795,14 +1888,3 @@ static const struct command_registration dap_commands[] = {
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct command_registration dap_command_handlers[] = {
|
||||
{
|
||||
.name = "dap",
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "DAP command group",
|
||||
.usage = "",
|
||||
.chain = dap_commands,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
+28
-7
@@ -112,13 +112,16 @@
|
||||
#define CSW_ADDRINC_PACKED (2UL << 4)
|
||||
#define CSW_DEVICE_EN (1UL << 6)
|
||||
#define CSW_TRIN_PROG (1UL << 7)
|
||||
/* all fields in bits 12 and above are implementation-defined! */
|
||||
#define CSW_SPIDEN (1UL << 23)
|
||||
/* 30:24 - implementation-defined! */
|
||||
#define CSW_HPROT (1UL << 25) /* ? */
|
||||
#define CSW_MASTER_DEBUG (1UL << 29) /* ? */
|
||||
#define CSW_HPROT1 (1UL << 25) /* AHB: Privileged */
|
||||
#define CSW_MASTER_DEBUG (1UL << 29) /* AHB: set HMASTER signals to AHB-AP ID */
|
||||
#define CSW_SPROT (1UL << 30)
|
||||
#define CSW_DBGSWENABLE (1UL << 31)
|
||||
|
||||
/* initial value of csw_default used for MEM-AP transfers */
|
||||
#define CSW_DEFAULT (CSW_HPROT1 | CSW_MASTER_DEBUG | CSW_DBGSWENABLE)
|
||||
|
||||
/* Fields of the MEM-AP's IDR register */
|
||||
#define IDR_REV (0xFUL << 28)
|
||||
#define IDR_JEP106 (0x7FFUL << 17)
|
||||
@@ -244,6 +247,10 @@ struct adiv5_dap {
|
||||
* should be performed before the next access.
|
||||
*/
|
||||
bool do_reconnect;
|
||||
|
||||
/** Flag saying whether to ignore the syspwrupack flag in DAP. Some devices
|
||||
* do not set this bit until later in the bringup sequence */
|
||||
bool ignore_syspwrupack;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -254,6 +261,8 @@ struct adiv5_dap {
|
||||
* available until run().
|
||||
*/
|
||||
struct dap_ops {
|
||||
/** connect operation for SWD */
|
||||
int (*connect)(struct adiv5_dap *dap);
|
||||
/** DP register read. */
|
||||
int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t *data);
|
||||
@@ -277,6 +286,9 @@ struct dap_ops {
|
||||
/** Executes all queued DAP operations but doesn't check
|
||||
* sticky error conditions */
|
||||
int (*sync)(struct adiv5_dap *dap);
|
||||
|
||||
/** Optional; called at OpenOCD exit */
|
||||
void (*quit)(struct adiv5_dap *dap);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -473,9 +485,6 @@ int mem_ap_read_buf_noincr(struct adiv5_ap *ap,
|
||||
int mem_ap_write_buf_noincr(struct adiv5_ap *ap,
|
||||
const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address);
|
||||
|
||||
/* Create DAP struct */
|
||||
struct adiv5_dap *dap_init(void);
|
||||
|
||||
/* Initialisation of the debug system, power domains and registers */
|
||||
int dap_dp_init(struct adiv5_dap *dap);
|
||||
int mem_ap_init(struct adiv5_ap *ap);
|
||||
@@ -509,12 +518,24 @@ int dap_to_swd(struct target *target);
|
||||
/* Put debug link into JTAG mode */
|
||||
int dap_to_jtag(struct target *target);
|
||||
|
||||
extern const struct command_registration dap_command_handlers[];
|
||||
extern const struct command_registration dap_instance_commands[];
|
||||
|
||||
struct arm_dap_object;
|
||||
extern struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o);
|
||||
extern struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj);
|
||||
extern int dap_info_command(struct command_context *cmd_ctx,
|
||||
struct adiv5_ap *ap);
|
||||
extern int dap_register_commands(struct command_context *cmd_ctx);
|
||||
extern const char *adiv5_dap_name(struct adiv5_dap *self);
|
||||
extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self);
|
||||
extern int dap_cleanup_all(void);
|
||||
|
||||
struct adiv5_private_config {
|
||||
int ap_num;
|
||||
struct adiv5_dap *dap;
|
||||
};
|
||||
|
||||
extern int adiv5_verify_config(struct adiv5_private_config *pc);
|
||||
extern int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi);
|
||||
|
||||
#endif /* OPENOCD_TARGET_ARM_ADI_V5_H */
|
||||
|
||||
+440
-9
@@ -27,21 +27,47 @@
|
||||
#include "target/arm_cti.h"
|
||||
#include "target/target.h"
|
||||
#include "helper/time_support.h"
|
||||
#include "helper/list.h"
|
||||
#include "helper/command.h"
|
||||
|
||||
struct arm_cti {
|
||||
uint32_t base;
|
||||
target_addr_t base;
|
||||
struct adiv5_ap *ap;
|
||||
};
|
||||
|
||||
struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base)
|
||||
{
|
||||
struct arm_cti *self = calloc(1, sizeof(struct arm_cti));
|
||||
if (!self)
|
||||
return NULL;
|
||||
struct arm_cti_object {
|
||||
struct list_head lh;
|
||||
struct arm_cti cti;
|
||||
int ap_num;
|
||||
char *name;
|
||||
};
|
||||
|
||||
self->base = base;
|
||||
self->ap = ap;
|
||||
return self;
|
||||
static LIST_HEAD(all_cti);
|
||||
|
||||
const char *arm_cti_name(struct arm_cti *self)
|
||||
{
|
||||
struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti);
|
||||
return obj->name;
|
||||
}
|
||||
|
||||
struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
|
||||
{
|
||||
struct arm_cti_object *obj = NULL;
|
||||
const char *name;
|
||||
bool found = false;
|
||||
|
||||
name = Jim_GetString(o, NULL);
|
||||
|
||||
list_for_each_entry(obj, &all_cti, lh) {
|
||||
if (!strcmp(name, obj->name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return &obj->cti;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value)
|
||||
@@ -146,3 +172,408 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel)
|
||||
|
||||
return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel));
|
||||
}
|
||||
|
||||
static uint32_t cti_regs[26];
|
||||
|
||||
static const struct {
|
||||
uint32_t offset;
|
||||
const char *label;
|
||||
uint32_t *p_val;
|
||||
} cti_names[] = {
|
||||
{ CTI_CTR, "CTR", &cti_regs[0] },
|
||||
{ CTI_GATE, "GATE", &cti_regs[1] },
|
||||
{ CTI_INEN0, "INEN0", &cti_regs[2] },
|
||||
{ CTI_INEN1, "INEN1", &cti_regs[3] },
|
||||
{ CTI_INEN2, "INEN2", &cti_regs[4] },
|
||||
{ CTI_INEN3, "INEN3", &cti_regs[5] },
|
||||
{ CTI_INEN4, "INEN4", &cti_regs[6] },
|
||||
{ CTI_INEN5, "INEN5", &cti_regs[7] },
|
||||
{ CTI_INEN6, "INEN6", &cti_regs[8] },
|
||||
{ CTI_INEN7, "INEN7", &cti_regs[9] },
|
||||
{ CTI_INEN8, "INEN8", &cti_regs[10] },
|
||||
{ CTI_OUTEN0, "OUTEN0", &cti_regs[11] },
|
||||
{ CTI_OUTEN1, "OUTEN1", &cti_regs[12] },
|
||||
{ CTI_OUTEN2, "OUTEN2", &cti_regs[13] },
|
||||
{ CTI_OUTEN3, "OUTEN3", &cti_regs[14] },
|
||||
{ CTI_OUTEN4, "OUTEN4", &cti_regs[15] },
|
||||
{ CTI_OUTEN5, "OUTEN5", &cti_regs[16] },
|
||||
{ CTI_OUTEN6, "OUTEN6", &cti_regs[17] },
|
||||
{ CTI_OUTEN7, "OUTEN7", &cti_regs[18] },
|
||||
{ CTI_OUTEN8, "OUTEN8", &cti_regs[19] },
|
||||
{ CTI_TRIN_STATUS, "TRIN", &cti_regs[20] },
|
||||
{ CTI_TROUT_STATUS, "TROUT", &cti_regs[21] },
|
||||
{ CTI_CHIN_STATUS, "CHIN", &cti_regs[22] },
|
||||
{ CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] },
|
||||
{ CTI_APPSET, "APPSET", &cti_regs[24] },
|
||||
{ CTI_APPCLEAR, "APPCLR", &cti_regs[25] },
|
||||
};
|
||||
|
||||
static int cti_find_reg_offset(const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cti_names); i++) {
|
||||
if (!strcmp(name, cti_names[i].label))
|
||||
return cti_names[i].offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int arm_cti_cleanup_all(void)
|
||||
{
|
||||
struct arm_cti_object *obj, *tmp;
|
||||
|
||||
list_for_each_entry_safe(obj, tmp, &all_cti, lh) {
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cti_dump)
|
||||
{
|
||||
struct arm_cti_object *obj = CMD_DATA;
|
||||
struct arm_cti *cti = &obj->cti;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++)
|
||||
retval = mem_ap_read_u32(cti->ap,
|
||||
cti->base + cti_names[i].offset, cti_names[i].p_val);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
retval = dap_run(cti->ap->dap);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++)
|
||||
command_print(CMD_CTX, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32,
|
||||
cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val);
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cti_enable)
|
||||
{
|
||||
struct arm_cti_object *obj = CMD_DATA;
|
||||
Jim_Interp *interp = CMD_CTX->interp;
|
||||
struct arm_cti *cti = &obj->cti;
|
||||
bool on_off;
|
||||
|
||||
if (CMD_ARGC != 1) {
|
||||
Jim_SetResultString(interp, "wrong number of args", -1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
|
||||
|
||||
return arm_cti_enable(cti, on_off);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cti_testmode)
|
||||
{
|
||||
struct arm_cti_object *obj = CMD_DATA;
|
||||
Jim_Interp *interp = CMD_CTX->interp;
|
||||
struct arm_cti *cti = &obj->cti;
|
||||
bool on_off;
|
||||
|
||||
if (CMD_ARGC != 1) {
|
||||
Jim_SetResultString(interp, "wrong number of args", -1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
|
||||
|
||||
return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cti_write)
|
||||
{
|
||||
struct arm_cti_object *obj = CMD_DATA;
|
||||
Jim_Interp *interp = CMD_CTX->interp;
|
||||
struct arm_cti *cti = &obj->cti;
|
||||
int offset;
|
||||
uint32_t value;
|
||||
|
||||
if (CMD_ARGC != 2) {
|
||||
Jim_SetResultString(interp, "Wrong numer of args", -1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
offset = cti_find_reg_offset(CMD_ARGV[0]);
|
||||
if (offset < 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
||||
|
||||
return arm_cti_write_reg(cti, offset, value);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cti_read)
|
||||
{
|
||||
struct arm_cti_object *obj = CMD_DATA;
|
||||
Jim_Interp *interp = CMD_CTX->interp;
|
||||
struct arm_cti *cti = &obj->cti;
|
||||
int offset;
|
||||
int retval;
|
||||
uint32_t value;
|
||||
|
||||
if (CMD_ARGC != 1) {
|
||||
Jim_SetResultString(interp, "Wrong numer of args", -1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
offset = cti_find_reg_offset(CMD_ARGV[0]);
|
||||
if (offset < 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
retval = arm_cti_read_reg(cti, offset, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
command_print(CMD_CTX, "0x%08"PRIx32, value);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration cti_instance_command_handlers[] = {
|
||||
{
|
||||
.name = "dump",
|
||||
.mode = COMMAND_EXEC,
|
||||
.handler = handle_cti_dump,
|
||||
.help = "dump CTI registers",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "enable",
|
||||
.mode = COMMAND_EXEC,
|
||||
.handler = handle_cti_enable,
|
||||
.help = "enable or disable the CTI",
|
||||
.usage = "'on'|'off'",
|
||||
},
|
||||
{
|
||||
.name = "testmode",
|
||||
.mode = COMMAND_EXEC,
|
||||
.handler = handle_cti_testmode,
|
||||
.help = "enable or disable integration test mode",
|
||||
.usage = "'on'|'off'",
|
||||
},
|
||||
{
|
||||
.name = "write",
|
||||
.mode = COMMAND_EXEC,
|
||||
.handler = handle_cti_write,
|
||||
.help = "write to a CTI register",
|
||||
.usage = "register_name value",
|
||||
},
|
||||
{
|
||||
.name = "read",
|
||||
.mode = COMMAND_EXEC,
|
||||
.handler = handle_cti_read,
|
||||
.help = "read a CTI register",
|
||||
.usage = "register_name",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
enum cti_cfg_param {
|
||||
CFG_DAP,
|
||||
CFG_AP_NUM,
|
||||
CFG_CTIBASE
|
||||
};
|
||||
|
||||
static const Jim_Nvp nvp_config_opts[] = {
|
||||
{ .name = "-dap", .value = CFG_DAP },
|
||||
{ .name = "-ctibase", .value = CFG_CTIBASE },
|
||||
{ .name = "-ap-num", .value = CFG_AP_NUM },
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti)
|
||||
{
|
||||
struct adiv5_dap *dap = NULL;
|
||||
Jim_Nvp *n;
|
||||
jim_wide w;
|
||||
int e;
|
||||
|
||||
/* parse config or cget options ... */
|
||||
while (goi->argc > 0) {
|
||||
Jim_SetEmptyResult(goi->interp);
|
||||
|
||||
e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
|
||||
if (e != JIM_OK) {
|
||||
Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
|
||||
return e;
|
||||
}
|
||||
switch (n->value) {
|
||||
case CFG_DAP: {
|
||||
Jim_Obj *o_t;
|
||||
e = Jim_GetOpt_Obj(goi, &o_t);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
dap = dap_instance_by_jim_obj(goi->interp, o_t);
|
||||
if (dap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "-dap is invalid", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
/* loop for more */
|
||||
break;
|
||||
}
|
||||
case CFG_CTIBASE:
|
||||
e = Jim_GetOpt_Wide(goi, &w);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
cti->cti.base = (uint32_t)w;
|
||||
/* loop for more */
|
||||
break;
|
||||
|
||||
case CFG_AP_NUM:
|
||||
e = Jim_GetOpt_Wide(goi, &w);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
cti->ap_num = (uint32_t)w;
|
||||
}
|
||||
}
|
||||
|
||||
if (dap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
cti->cti.ap = dap_ap(dap, cti->ap_num);
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
static int cti_create(Jim_GetOptInfo *goi)
|
||||
{
|
||||
struct command_context *cmd_ctx;
|
||||
static struct arm_cti_object *cti;
|
||||
Jim_Obj *new_cmd;
|
||||
Jim_Cmd *cmd;
|
||||
const char *cp;
|
||||
int e;
|
||||
|
||||
cmd_ctx = current_command_context(goi->interp);
|
||||
assert(cmd_ctx != NULL);
|
||||
|
||||
if (goi->argc < 3) {
|
||||
Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
|
||||
return JIM_ERR;
|
||||
}
|
||||
/* COMMAND */
|
||||
Jim_GetOpt_Obj(goi, &new_cmd);
|
||||
/* does this command exist? */
|
||||
cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
|
||||
if (cmd) {
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
/* Create it */
|
||||
cti = calloc(1, sizeof(struct arm_cti_object));
|
||||
if (cti == NULL)
|
||||
return JIM_ERR;
|
||||
|
||||
e = cti_configure(goi, cti);
|
||||
if (e != JIM_OK) {
|
||||
free(cti);
|
||||
return e;
|
||||
}
|
||||
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
cti->name = strdup(cp);
|
||||
|
||||
/* now - create the new cti name command */
|
||||
const struct command_registration cti_subcommands[] = {
|
||||
{
|
||||
.chain = cti_instance_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
const struct command_registration cti_commands[] = {
|
||||
{
|
||||
.name = cp,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "cti instance command group",
|
||||
.usage = "",
|
||||
.chain = cti_subcommands,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
e = register_commands(cmd_ctx, NULL, cti_commands);
|
||||
if (ERROR_OK != e)
|
||||
return JIM_ERR;
|
||||
|
||||
struct command *c = command_find_in_context(cmd_ctx, cp);
|
||||
assert(c);
|
||||
command_set_handler_data(c, cti);
|
||||
|
||||
list_add_tail(&cti->lh, &all_cti);
|
||||
|
||||
return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
|
||||
}
|
||||
|
||||
static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
{
|
||||
Jim_GetOptInfo goi;
|
||||
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
||||
if (goi.argc < 2) {
|
||||
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
||||
"<name> [<cti_options> ...]");
|
||||
return JIM_ERR;
|
||||
}
|
||||
return cti_create(&goi);
|
||||
}
|
||||
|
||||
static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
{
|
||||
struct arm_cti_object *obj;
|
||||
|
||||
if (argc != 1) {
|
||||
Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
|
||||
return JIM_ERR;
|
||||
}
|
||||
Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
|
||||
list_for_each_entry(obj, &all_cti, lh) {
|
||||
Jim_ListAppendElement(interp, Jim_GetResult(interp),
|
||||
Jim_NewStringObj(interp, obj->name, -1));
|
||||
}
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
|
||||
static const struct command_registration cti_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "create",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_cti_create,
|
||||
.usage = "name '-chain-position' name [options ...]",
|
||||
.help = "Creates a new CTI object",
|
||||
},
|
||||
{
|
||||
.name = "names",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_cti_names,
|
||||
.usage = "",
|
||||
.help = "Lists all registered CTI objects by name",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration cti_command_handlers[] = {
|
||||
{
|
||||
.name = "cti",
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "CTI commands",
|
||||
.chain = cti_subcommand_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
int cti_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL, cti_command_handlers);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#define CTI_INEN5 0x34
|
||||
#define CTI_INEN6 0x38
|
||||
#define CTI_INEN7 0x3C
|
||||
#define CTI_INEN8 0x40
|
||||
#define CTI_INEN(n) (0x20 + 4 * n)
|
||||
#define CTI_OUTEN0 0xA0
|
||||
#define CTI_OUTEN1 0xA4
|
||||
@@ -43,6 +44,7 @@
|
||||
#define CTI_OUTEN5 0xB4
|
||||
#define CTI_OUTEN6 0xB8
|
||||
#define CTI_OUTEN7 0xBC
|
||||
#define CTI_OUTEN8 0xC0
|
||||
#define CTI_OUTEN(n) (0xA0 + 4 * n)
|
||||
#define CTI_TRIN_STATUS 0x130
|
||||
#define CTI_TROUT_STATUS 0x134
|
||||
@@ -58,8 +60,10 @@
|
||||
|
||||
/* forward-declare arm_cti struct */
|
||||
struct arm_cti;
|
||||
struct adiv5_ap;
|
||||
|
||||
extern struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base);
|
||||
extern const char *arm_cti_name(struct arm_cti *self);
|
||||
extern struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o);
|
||||
extern int arm_cti_enable(struct arm_cti *self, bool enable);
|
||||
extern int arm_cti_ack_events(struct arm_cti *self, uint32_t event);
|
||||
extern int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel);
|
||||
@@ -69,5 +73,7 @@ extern int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *va
|
||||
extern int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel);
|
||||
extern int arm_cti_set_channel(struct arm_cti *self, uint32_t channel);
|
||||
extern int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel);
|
||||
extern int arm_cti_cleanup_all(void);
|
||||
extern int cti_register_commands(struct command_context *cmd_ctx);
|
||||
|
||||
#endif /* OPENOCD_TARGET_ARM_CTI_H */
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2016 by Matthias Welwarsky *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "target/arm_adi_v5.h"
|
||||
#include "target/arm.h"
|
||||
#include "helper/list.h"
|
||||
#include "helper/command.h"
|
||||
#include "transport/transport.h"
|
||||
#include "jtag/interface.h"
|
||||
|
||||
static LIST_HEAD(all_dap);
|
||||
|
||||
extern const struct dap_ops swd_dap_ops;
|
||||
extern const struct dap_ops jtag_dp_ops;
|
||||
extern struct jtag_interface *jtag_interface;
|
||||
|
||||
/* DAP command support */
|
||||
struct arm_dap_object {
|
||||
struct list_head lh;
|
||||
struct adiv5_dap dap;
|
||||
char *name;
|
||||
const struct swd_driver *swd;
|
||||
};
|
||||
|
||||
static void dap_instance_init(struct adiv5_dap *dap)
|
||||
{
|
||||
int i;
|
||||
/* Set up with safe defaults */
|
||||
for (i = 0; i <= 255; i++) {
|
||||
dap->ap[i].dap = dap;
|
||||
dap->ap[i].ap_num = i;
|
||||
/* memaccess_tck max is 255 */
|
||||
dap->ap[i].memaccess_tck = 255;
|
||||
/* Number of bits for tar autoincrement, impl. dep. at least 10 */
|
||||
dap->ap[i].tar_autoincr_block = (1<<10);
|
||||
/* default CSW value */
|
||||
dap->ap[i].csw_default = CSW_DEFAULT;
|
||||
}
|
||||
INIT_LIST_HEAD(&dap->cmd_journal);
|
||||
}
|
||||
|
||||
const char *adiv5_dap_name(struct adiv5_dap *self)
|
||||
{
|
||||
struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap);
|
||||
return obj->name;
|
||||
}
|
||||
|
||||
const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self)
|
||||
{
|
||||
struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap);
|
||||
return obj->swd;
|
||||
}
|
||||
|
||||
struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj)
|
||||
{
|
||||
return &obj->dap;
|
||||
}
|
||||
struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
|
||||
{
|
||||
struct arm_dap_object *obj = NULL;
|
||||
const char *name;
|
||||
bool found = false;
|
||||
|
||||
name = Jim_GetString(o, NULL);
|
||||
|
||||
list_for_each_entry(obj, &all_dap, lh) {
|
||||
if (!strcmp(name, obj->name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return &obj->dap;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dap_init_all(void)
|
||||
{
|
||||
struct arm_dap_object *obj;
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("Initializing all DAPs ...");
|
||||
|
||||
list_for_each_entry(obj, &all_dap, lh) {
|
||||
struct adiv5_dap *dap = &obj->dap;
|
||||
|
||||
/* with hla, dap is just a dummy */
|
||||
if (transport_is_hla())
|
||||
continue;
|
||||
|
||||
/* skip taps that are disabled */
|
||||
if (!dap->tap->enabled)
|
||||
continue;
|
||||
|
||||
if (transport_is_swd()) {
|
||||
dap->ops = &swd_dap_ops;
|
||||
obj->swd = jtag_interface->swd;
|
||||
} else
|
||||
dap->ops = &jtag_dp_ops;
|
||||
|
||||
retval = dap->ops->connect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int dap_cleanup_all(void)
|
||||
{
|
||||
struct arm_dap_object *obj, *tmp;
|
||||
struct adiv5_dap *dap;
|
||||
|
||||
list_for_each_entry_safe(obj, tmp, &all_dap, lh) {
|
||||
dap = &obj->dap;
|
||||
if (dap->ops && dap->ops->quit)
|
||||
dap->ops->quit(dap);
|
||||
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
enum dap_cfg_param {
|
||||
CFG_CHAIN_POSITION,
|
||||
CFG_IGNORE_SYSPWRUPACK,
|
||||
};
|
||||
|
||||
static const Jim_Nvp nvp_config_opts[] = {
|
||||
{ .name = "-chain-position", .value = CFG_CHAIN_POSITION },
|
||||
{ .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK },
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
static int dap_configure(Jim_GetOptInfo *goi, struct arm_dap_object *dap)
|
||||
{
|
||||
struct jtag_tap *tap = NULL;
|
||||
Jim_Nvp *n;
|
||||
int e;
|
||||
|
||||
/* parse config or cget options ... */
|
||||
while (goi->argc > 0) {
|
||||
Jim_SetEmptyResult(goi->interp);
|
||||
|
||||
e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
|
||||
if (e != JIM_OK) {
|
||||
Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
|
||||
return e;
|
||||
}
|
||||
switch (n->value) {
|
||||
case CFG_CHAIN_POSITION: {
|
||||
Jim_Obj *o_t;
|
||||
e = Jim_GetOpt_Obj(goi, &o_t);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
tap = jtag_tap_by_jim_obj(goi->interp, o_t);
|
||||
if (tap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position is invalid", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
/* loop for more */
|
||||
break;
|
||||
}
|
||||
case CFG_IGNORE_SYSPWRUPACK:
|
||||
dap->dap.ignore_syspwrupack = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
dap_instance_init(&dap->dap);
|
||||
dap->dap.tap = tap;
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
static int dap_create(Jim_GetOptInfo *goi)
|
||||
{
|
||||
struct command_context *cmd_ctx;
|
||||
static struct arm_dap_object *dap;
|
||||
Jim_Obj *new_cmd;
|
||||
Jim_Cmd *cmd;
|
||||
const char *cp;
|
||||
int e;
|
||||
|
||||
cmd_ctx = current_command_context(goi->interp);
|
||||
assert(cmd_ctx != NULL);
|
||||
|
||||
if (goi->argc < 3) {
|
||||
Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
|
||||
return JIM_ERR;
|
||||
}
|
||||
/* COMMAND */
|
||||
Jim_GetOpt_Obj(goi, &new_cmd);
|
||||
/* does this command exist? */
|
||||
cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
|
||||
if (cmd) {
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
/* Create it */
|
||||
dap = calloc(1, sizeof(struct arm_dap_object));
|
||||
if (dap == NULL)
|
||||
return JIM_ERR;
|
||||
|
||||
e = dap_configure(goi, dap);
|
||||
if (e != JIM_OK) {
|
||||
free(dap);
|
||||
return e;
|
||||
}
|
||||
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
dap->name = strdup(cp);
|
||||
|
||||
struct command_registration dap_commands[] = {
|
||||
{
|
||||
.name = cp,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "dap instance command group",
|
||||
.usage = "",
|
||||
.chain = dap_instance_commands,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/* don't expose the instance commands when using hla */
|
||||
if (transport_is_hla())
|
||||
dap_commands[0].chain = NULL;
|
||||
|
||||
e = register_commands(cmd_ctx, NULL, dap_commands);
|
||||
if (ERROR_OK != e)
|
||||
return JIM_ERR;
|
||||
|
||||
struct command *c = command_find_in_context(cmd_ctx, cp);
|
||||
assert(c);
|
||||
command_set_handler_data(c, dap);
|
||||
|
||||
list_add_tail(&dap->lh, &all_dap);
|
||||
|
||||
return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
|
||||
}
|
||||
|
||||
static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
{
|
||||
Jim_GetOptInfo goi;
|
||||
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
||||
if (goi.argc < 2) {
|
||||
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
||||
"<name> [<dap_options> ...]");
|
||||
return JIM_ERR;
|
||||
}
|
||||
return dap_create(&goi);
|
||||
}
|
||||
|
||||
static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
{
|
||||
struct arm_dap_object *obj;
|
||||
|
||||
if (argc != 1) {
|
||||
Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
|
||||
return JIM_ERR;
|
||||
}
|
||||
Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
|
||||
list_for_each_entry(obj, &all_dap, lh) {
|
||||
Jim_ListAppendElement(interp, Jim_GetResult(interp),
|
||||
Jim_NewStringObj(interp, obj->name, -1));
|
||||
}
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_dap_init)
|
||||
{
|
||||
return dap_init_all();
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_dap_info_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct adiv5_dap *dap = arm->dap;
|
||||
uint32_t apsel;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
case 0:
|
||||
apsel = dap->apsel;
|
||||
break;
|
||||
case 1:
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
|
||||
if (apsel >= 256)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
return dap_info_command(CMD_CTX, &dap->ap[apsel]);
|
||||
}
|
||||
|
||||
static const struct command_registration dap_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "create",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_dap_create,
|
||||
.usage = "name '-chain-position' name",
|
||||
.help = "Creates a new DAP instance",
|
||||
},
|
||||
{
|
||||
.name = "names",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_dap_names,
|
||||
.usage = "",
|
||||
.help = "Lists all registered DAP instances by name",
|
||||
},
|
||||
{
|
||||
.name = "init",
|
||||
.mode = COMMAND_ANY,
|
||||
.handler = handle_dap_init,
|
||||
.usage = "",
|
||||
.help = "Initialize all registered DAP instances"
|
||||
},
|
||||
{
|
||||
.name = "info",
|
||||
.handler = handle_dap_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "display ROM table for MEM-AP of current target "
|
||||
"(default currently selected AP)",
|
||||
.usage = "[ap_num]",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration dap_commands[] = {
|
||||
{
|
||||
.name = "dap",
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "DAP commands",
|
||||
.chain = dap_subcommand_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
int dap_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL, dap_commands);
|
||||
}
|
||||
@@ -118,15 +118,78 @@ static int evaluate_pld(uint32_t opcode,
|
||||
uint32_t address, struct arm_instruction *instruction)
|
||||
{
|
||||
/* PLD */
|
||||
if ((opcode & 0x0d70f000) == 0x0550f000) {
|
||||
if ((opcode & 0x0d30f000) == 0x0510f000) {
|
||||
uint8_t Rn;
|
||||
uint8_t U;
|
||||
unsigned offset;
|
||||
|
||||
instruction->type = ARM_PLD;
|
||||
Rn = (opcode & 0xf0000) >> 16;
|
||||
U = (opcode & 0x00800000) >> 23;
|
||||
if (Rn == 0xf) {
|
||||
/* literal */
|
||||
offset = opcode & 0x0fff;
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d",
|
||||
address, opcode, U ? "" : "-", offset);
|
||||
} else {
|
||||
uint8_t I, R;
|
||||
|
||||
snprintf(instruction->text,
|
||||
128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...",
|
||||
address,
|
||||
opcode);
|
||||
I = (opcode & 0x02000000) >> 25;
|
||||
R = (opcode & 0x00400000) >> 22;
|
||||
|
||||
if (I) {
|
||||
/* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */
|
||||
offset = (opcode & 0x0F80) >> 7;
|
||||
uint8_t Rm;
|
||||
Rm = opcode & 0xf;
|
||||
|
||||
if (offset == 0) {
|
||||
/* No shift */
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm);
|
||||
|
||||
} else {
|
||||
uint8_t shift;
|
||||
shift = (opcode & 0x60) >> 5;
|
||||
|
||||
if (shift == 0x0) {
|
||||
/* LSL */
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
|
||||
} else if (shift == 0x1) {
|
||||
/* LSR */
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
|
||||
} else if (shift == 0x2) {
|
||||
/* ASR */
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
|
||||
} else if (shift == 0x3) {
|
||||
/* ROR */
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* immediate PLD{W} [<Rn>, #+/-<imm12>] */
|
||||
offset = opcode & 0x0fff;
|
||||
if (offset == 0) {
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]",
|
||||
address, opcode, R ? "" : "W", Rn);
|
||||
} else {
|
||||
snprintf(instruction->text, 128,
|
||||
"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]",
|
||||
address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
/* DSB */
|
||||
@@ -1549,7 +1612,7 @@ static int evaluate_misc_instr(uint32_t opcode,
|
||||
}
|
||||
|
||||
/* SMLAW < y> */
|
||||
if (((opcode & 0x00600000) == 0x00100000) && (x == 0)) {
|
||||
if (((opcode & 0x00600000) == 0x00200000) && (x == 0)) {
|
||||
uint8_t Rd, Rm, Rs, Rn;
|
||||
instruction->type = ARM_SMLAWy;
|
||||
Rd = (opcode & 0xf0000) >> 16;
|
||||
@@ -1571,7 +1634,7 @@ static int evaluate_misc_instr(uint32_t opcode,
|
||||
}
|
||||
|
||||
/* SMUL < x><y> */
|
||||
if ((opcode & 0x00600000) == 0x00300000) {
|
||||
if ((opcode & 0x00600000) == 0x00600000) {
|
||||
uint8_t Rd, Rm, Rs;
|
||||
instruction->type = ARM_SMULxy;
|
||||
Rd = (opcode & 0xf0000) >> 16;
|
||||
@@ -1592,7 +1655,7 @@ static int evaluate_misc_instr(uint32_t opcode,
|
||||
}
|
||||
|
||||
/* SMULW < y> */
|
||||
if (((opcode & 0x00600000) == 0x00100000) && (x == 1)) {
|
||||
if (((opcode & 0x00600000) == 0x00200000) && (x == 1)) {
|
||||
uint8_t Rd, Rm, Rs;
|
||||
instruction->type = ARM_SMULWy;
|
||||
Rd = (opcode & 0xf0000) >> 16;
|
||||
@@ -2978,6 +3041,7 @@ static int t2ev_b_bl(uint32_t opcode, uint32_t address,
|
||||
case 0x4:
|
||||
inst = "BLX";
|
||||
instruction->type = ARM_BLX;
|
||||
address &= 0xfffffffc;
|
||||
break;
|
||||
case 0x5:
|
||||
inst = "BL";
|
||||
|
||||
+110
-17
@@ -131,6 +131,42 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Read 64bit VFP registers */
|
||||
static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
uint32_t value_r0, value_r1;
|
||||
|
||||
switch (regnum) {
|
||||
case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
|
||||
/* move from double word register to r0:r1: "vmov r0, r1, vm"
|
||||
* then read r0 via dcc
|
||||
*/
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
|
||||
((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0);
|
||||
/* read r1 via dcc */
|
||||
retval = dpm->instr_read_data_dcc(dpm,
|
||||
ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
|
||||
&value_r1);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
buf_set_u32(r->value, 0, 32, value_r0);
|
||||
buf_set_u32(r->value + 4, 0, 32, value_r1);
|
||||
r->valid = true;
|
||||
r->dirty = false;
|
||||
LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name,
|
||||
(unsigned) value_r0, (unsigned) value_r1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* just read the register -- rely on the core mode being right */
|
||||
static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
@@ -171,6 +207,14 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
|
||||
return dpm_read_reg_u64(dpm, r, regnum);
|
||||
break;
|
||||
case ARM_VFP_V3_FPSCR:
|
||||
/* "VMRS r0, FPSCR"; then return via DCC */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_VMRS(0), &value);
|
||||
break;
|
||||
default:
|
||||
/* 16: "MRS r0, CPSR"; then return via DCC
|
||||
* 17: "MRS r0, SPSR"; then return via DCC
|
||||
@@ -191,6 +235,40 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Write 64bit VFP registers */
|
||||
static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
uint32_t value_r0 = buf_get_u32(r->value, 0, 32);
|
||||
uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32);
|
||||
|
||||
switch (regnum) {
|
||||
case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
|
||||
/* write value_r1 to r1 via dcc */
|
||||
retval = dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
|
||||
value_r1);
|
||||
/* write value_r0 to r0 via dcc then,
|
||||
* move to double word register from r0:r1: "vmov vm, r0, r1"
|
||||
*/
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
|
||||
((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
r->dirty = false;
|
||||
LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name,
|
||||
(unsigned) value_r0, (unsigned) value_r1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* just write the register -- rely on the core mode being right */
|
||||
static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
@@ -208,6 +286,14 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
* read r0 from DCC; then "MOV pc, r0" */
|
||||
retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
|
||||
break;
|
||||
case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
|
||||
return dpm_write_reg_u64(dpm, r, regnum);
|
||||
break;
|
||||
case ARM_VFP_V3_FPSCR:
|
||||
/* move to r0 from DCC, then "VMSR FPSCR, r0" */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_VMSR(0), value);
|
||||
break;
|
||||
default:
|
||||
/* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
|
||||
* 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
|
||||
@@ -262,14 +348,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* read R0 first (it's used for scratch), then CPSR */
|
||||
r = arm->core_cache->reg_list + 0;
|
||||
if (!r->valid) {
|
||||
retval = dpm_read_reg(dpm, r, 0);
|
||||
if (retval != ERROR_OK)
|
||||
goto fail;
|
||||
/* read R0 and R1 first (it's used for scratch), then CPSR */
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
r = arm->core_cache->reg_list + i;
|
||||
if (!r->valid) {
|
||||
retval = dpm_read_reg(dpm, r, i);
|
||||
if (retval != ERROR_OK)
|
||||
goto fail;
|
||||
}
|
||||
r->dirty = true;
|
||||
}
|
||||
r->dirty = true;
|
||||
|
||||
retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -279,7 +367,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||
arm_set_cpsr(arm, cpsr);
|
||||
|
||||
/* REVISIT we can probably avoid reading R1..R14, saving time... */
|
||||
for (unsigned i = 1; i < 16; i++) {
|
||||
for (unsigned i = 2; i < 16; i++) {
|
||||
r = arm_reg_current(arm, i);
|
||||
if (r->valid)
|
||||
continue;
|
||||
@@ -412,8 +500,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
|
||||
|
||||
did_write = false;
|
||||
|
||||
/* check everything except our scratch register R0 */
|
||||
for (unsigned i = 1; i < cache->num_regs; i++) {
|
||||
/* check everything except our scratch registers R0 and R1 */
|
||||
for (unsigned i = 2; i < cache->num_regs; i++) {
|
||||
struct arm_reg *r;
|
||||
unsigned regnum;
|
||||
|
||||
@@ -499,11 +587,13 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
|
||||
goto done;
|
||||
arm->pc->dirty = false;
|
||||
|
||||
/* flush R0 -- it's *very* dirty by now */
|
||||
retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
cache->reg_list[0].dirty = false;
|
||||
/* flush R0 and R1 (our scratch registers) */
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
retval = dpm_write_reg(dpm, &cache->reg_list[i], i);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
cache->reg_list[i].dirty = false;
|
||||
}
|
||||
|
||||
/* (void) */ dpm->finish(dpm);
|
||||
done:
|
||||
@@ -540,6 +630,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm,
|
||||
/* r13/sp, and r14/lr are always shadowed */
|
||||
case 13:
|
||||
case 14:
|
||||
case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR:
|
||||
return mode;
|
||||
default:
|
||||
LOG_WARNING("invalid register #%u", num);
|
||||
@@ -561,7 +652,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
|
||||
struct arm_dpm *dpm = target_to_arm(target)->dpm;
|
||||
int retval;
|
||||
|
||||
if (regnum < 0 || regnum > 16)
|
||||
if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
|
||||
(regnum > ARM_VFP_V3_FPSCR))
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (regnum == 16) {
|
||||
@@ -604,7 +696,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
|
||||
int retval;
|
||||
|
||||
|
||||
if (regnum < 0 || regnum > 16)
|
||||
if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
|
||||
(regnum > ARM_VFP_V3_FPSCR))
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (regnum == 16) {
|
||||
|
||||
@@ -132,6 +132,30 @@
|
||||
*/
|
||||
#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm))
|
||||
|
||||
/* Copies two words from two ARM core registers
|
||||
* into a doubleword extension register, or
|
||||
* from a doubleword extension register to two ARM core registers.
|
||||
* See Armv7-A arch reference manual section A8.8.345
|
||||
* Rt: Arm core register 1
|
||||
* Rt2: Arm core register 2
|
||||
* Vm: The doubleword extension register
|
||||
* M: m = UInt(M:Vm);
|
||||
* op: to_arm_registers = (op == ‘1’);
|
||||
*/
|
||||
#define ARMV4_5_VMOV(op, Rt2, Rt, M, Vm) \
|
||||
(0xec400b10 | ((op) << 20) | ((Rt2) << 16) | \
|
||||
((Rt) << 12) | ((M) << 5) | (Vm))
|
||||
|
||||
/* Moves the value of the FPSCR to an ARM core register
|
||||
* Rt: Arm core register
|
||||
*/
|
||||
#define ARMV4_5_VMRS(Rt) (0xeef10a10 | ((Rt) << 12))
|
||||
|
||||
/* Moves the value of an ARM core register to the FPSCR.
|
||||
* Rt: Arm core register
|
||||
*/
|
||||
#define ARMV4_5_VMSR(Rt) (0xeee10a10 | ((Rt) << 12))
|
||||
|
||||
/* Store data from coprocessor to consecutive memory
|
||||
* See Armv7-A arch doc section A8.6.187
|
||||
* P: 1=index mode (offset from Rn)
|
||||
|
||||
+92
-555
@@ -8,6 +8,9 @@
|
||||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.com> *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -43,6 +46,7 @@
|
||||
#include "arm7_9_common.h"
|
||||
#include "armv7m.h"
|
||||
#include "armv7a.h"
|
||||
#include "armv8.h"
|
||||
#include "cortex_m.h"
|
||||
#include "register.h"
|
||||
#include "arm_opcodes.h"
|
||||
@@ -52,25 +56,35 @@
|
||||
#include <helper/log.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static const int open_modeflags[12] = {
|
||||
O_RDONLY,
|
||||
O_RDONLY | O_BINARY,
|
||||
O_RDWR,
|
||||
O_RDWR | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_APPEND,
|
||||
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_APPEND,
|
||||
O_RDWR | O_CREAT | O_APPEND | O_BINARY
|
||||
};
|
||||
static int arm_semihosting_resume(struct target *target, int *retval)
|
||||
{
|
||||
if (is_armv8(target_to_armv8(target))) {
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) {
|
||||
*retval = target_resume(target, 1, 0, 0, 0);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to resume target");
|
||||
return 0;
|
||||
}
|
||||
} else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP)
|
||||
target->debug_reason = DBG_REASON_SINGLESTEP;
|
||||
} else {
|
||||
*retval = target_resume(target, 1, 0, 0, 0);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to resume target");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int post_result(struct target *target)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!target->semihosting)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* REVISIT this looks wrong ... ARM11 and Cortex-A8
|
||||
* should work this way at least sometimes.
|
||||
*/
|
||||
@@ -79,7 +93,7 @@ static int post_result(struct target *target)
|
||||
uint32_t spsr;
|
||||
|
||||
/* return value in R0 */
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
|
||||
arm->core_cache->reg_list[0].dirty = 1;
|
||||
|
||||
/* LR --> PC */
|
||||
@@ -100,528 +114,28 @@ static int post_result(struct target *target)
|
||||
if (spsr & 0x20)
|
||||
arm->core_state = ARM_STATE_THUMB;
|
||||
|
||||
} else if (is_armv8(target_to_armv8(target))) {
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
/* return value in R0 */
|
||||
buf_set_u64(arm->core_cache->reg_list[0].value, 0, 64, target->semihosting->result);
|
||||
arm->core_cache->reg_list[0].dirty = 1;
|
||||
|
||||
uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64);
|
||||
buf_set_u64(arm->pc->value, 0, 64, pc + 4);
|
||||
arm->pc->dirty = 1;
|
||||
}
|
||||
} else {
|
||||
/* resume execution, this will be pc+2 to skip over the
|
||||
* bkpt instruction */
|
||||
|
||||
/* return result in R0 */
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
|
||||
arm->core_cache->reg_list[0].dirty = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int do_semihosting(struct target *target)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct gdb_fileio_info *fileio_info = target->fileio_info;
|
||||
uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
|
||||
uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
|
||||
uint8_t params[16];
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* TODO: lots of security issues are not considered yet, such as:
|
||||
* - no validation on target provided file descriptors
|
||||
* - no safety checks on opened/deleted/renamed file paths
|
||||
* Beware the target app you use this support with.
|
||||
*
|
||||
* TODO: unsupported semihosting fileio operations could be
|
||||
* implemented if we had a small working area at our disposal.
|
||||
*/
|
||||
switch ((arm->semihosting_op = r0)) {
|
||||
case 0x01: /* SYS_OPEN */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t m = target_buffer_get_u32(target, params+4);
|
||||
uint32_t l = target_buffer_get_u32(target, params+8);
|
||||
uint8_t fn[256];
|
||||
retval = target_read_memory(target, a, 1, l, fn);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn[l] = 0;
|
||||
if (arm->is_semihosting_fileio) {
|
||||
if (strcmp((char *)fn, ":tt") == 0)
|
||||
arm->semihosting_result = 0;
|
||||
else {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "open";
|
||||
fileio_info->param_1 = a;
|
||||
fileio_info->param_2 = l;
|
||||
fileio_info->param_3 = open_modeflags[m];
|
||||
fileio_info->param_4 = 0644;
|
||||
}
|
||||
} else {
|
||||
if (l <= 255 && m <= 11) {
|
||||
if (strcmp((char *)fn, ":tt") == 0) {
|
||||
if (m < 4)
|
||||
arm->semihosting_result = dup(STDIN_FILENO);
|
||||
else
|
||||
arm->semihosting_result = dup(STDOUT_FILENO);
|
||||
} else {
|
||||
/* cygwin requires the permission setting
|
||||
* otherwise it will fail to reopen a previously
|
||||
* written file */
|
||||
arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644);
|
||||
}
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02: /* SYS_CLOSE */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "close";
|
||||
fileio_info->param_1 = fd;
|
||||
} else {
|
||||
arm->semihosting_result = close(fd);
|
||||
arm->semihosting_errno = errno;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: /* SYS_WRITEC */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = 1;
|
||||
fileio_info->param_2 = r1;
|
||||
fileio_info->param_3 = 1;
|
||||
} else {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, r1, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
putchar(c);
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04: /* SYS_WRITE0 */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
size_t count = 0;
|
||||
for (uint32_t a = r1;; a++) {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, a, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (c == '\0')
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = 1;
|
||||
fileio_info->param_2 = r1;
|
||||
fileio_info->param_3 = count;
|
||||
} else {
|
||||
do {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, r1++, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!c)
|
||||
break;
|
||||
putchar(c);
|
||||
} while (1);
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05: /* SYS_WRITE */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
uint32_t a = target_buffer_get_u32(target, params+4);
|
||||
size_t l = target_buffer_get_u32(target, params+8);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = a;
|
||||
fileio_info->param_3 = l;
|
||||
} else {
|
||||
uint8_t *buf = malloc(l);
|
||||
if (!buf) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOMEM;
|
||||
} else {
|
||||
retval = target_read_buffer(target, a, l, buf);
|
||||
if (retval != ERROR_OK) {
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
arm->semihosting_result = write(fd, buf, l);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result >= 0)
|
||||
arm->semihosting_result = l - arm->semihosting_result;
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: /* SYS_READ */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
uint32_t a = target_buffer_get_u32(target, params+4);
|
||||
ssize_t l = target_buffer_get_u32(target, params+8);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "read";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = a;
|
||||
fileio_info->param_3 = l;
|
||||
} else {
|
||||
uint8_t *buf = malloc(l);
|
||||
if (!buf) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOMEM;
|
||||
} else {
|
||||
arm->semihosting_result = read(fd, buf, l);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result >= 0) {
|
||||
retval = target_write_buffer(target, a, arm->semihosting_result, buf);
|
||||
if (retval != ERROR_OK) {
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
arm->semihosting_result = l - arm->semihosting_result;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x07: /* SYS_READC */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
LOG_ERROR("SYS_READC not supported by semihosting fileio");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
arm->semihosting_result = getchar();
|
||||
break;
|
||||
|
||||
case 0x08: /* SYS_ISERROR */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0);
|
||||
break;
|
||||
|
||||
case 0x09: /* SYS_ISTTY */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "isatty";
|
||||
fileio_info->param_1 = r1;
|
||||
} else {
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0a: /* SYS_SEEK */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
off_t pos = target_buffer_get_u32(target, params+4);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "lseek";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = pos;
|
||||
fileio_info->param_3 = SEEK_SET;
|
||||
} else {
|
||||
arm->semihosting_result = lseek(fd, pos, SEEK_SET);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result == pos)
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0c: /* SYS_FLEN */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
struct stat buf;
|
||||
arm->semihosting_result = fstat(fd, &buf);
|
||||
if (arm->semihosting_result == -1) {
|
||||
arm->semihosting_errno = errno;
|
||||
arm->semihosting_result = -1;
|
||||
break;
|
||||
}
|
||||
arm->semihosting_result = buf.st_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0e: /* SYS_REMOVE */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l = target_buffer_get_u32(target, params+4);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "unlink";
|
||||
fileio_info->param_1 = a;
|
||||
fileio_info->param_2 = l;
|
||||
} else {
|
||||
if (l <= 255) {
|
||||
uint8_t fn[256];
|
||||
retval = target_read_memory(target, a, 1, l, fn);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn[l] = 0;
|
||||
arm->semihosting_result = remove((char *)fn);
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0f: /* SYS_RENAME */
|
||||
retval = target_read_memory(target, r1, 4, 4, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a1 = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l1 = target_buffer_get_u32(target, params+4);
|
||||
uint32_t a2 = target_buffer_get_u32(target, params+8);
|
||||
uint32_t l2 = target_buffer_get_u32(target, params+12);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "rename";
|
||||
fileio_info->param_1 = a1;
|
||||
fileio_info->param_2 = l1;
|
||||
fileio_info->param_3 = a2;
|
||||
fileio_info->param_4 = l2;
|
||||
} else {
|
||||
if (l1 <= 255 && l2 <= 255) {
|
||||
uint8_t fn1[256], fn2[256];
|
||||
retval = target_read_memory(target, a1, 1, l1, fn1);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = target_read_memory(target, a2, 1, l2, fn2);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn1[l1] = 0;
|
||||
fn2[l2] = 0;
|
||||
arm->semihosting_result = rename((char *)fn1, (char *)fn2);
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11: /* SYS_TIME */
|
||||
arm->semihosting_result = time(NULL);
|
||||
break;
|
||||
|
||||
case 0x13: /* SYS_ERRNO */
|
||||
arm->semihosting_result = arm->semihosting_errno;
|
||||
break;
|
||||
|
||||
case 0x15: /* SYS_GET_CMDLINE */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l = target_buffer_get_u32(target, params+4);
|
||||
char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : "";
|
||||
uint32_t s = strlen(arg) + 1;
|
||||
if (l < s)
|
||||
arm->semihosting_result = -1;
|
||||
else {
|
||||
retval = target_write_buffer(target, a, s, (uint8_t *)arg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x16: /* SYS_HEAPINFO */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
/* tell the remote we have no idea */
|
||||
memset(params, 0, 4*4);
|
||||
retval = target_write_memory(target, a, 4, 4, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x18: /* angel_SWIreason_ReportException */
|
||||
switch (r1) {
|
||||
case 0x20026: /* ADP_Stopped_ApplicationExit */
|
||||
fprintf(stderr, "semihosting: *** application exited ***\n");
|
||||
break;
|
||||
case 0x20000: /* ADP_Stopped_BranchThroughZero */
|
||||
case 0x20001: /* ADP_Stopped_UndefinedInstr */
|
||||
case 0x20002: /* ADP_Stopped_SoftwareInterrupt */
|
||||
case 0x20003: /* ADP_Stopped_PrefetchAbort */
|
||||
case 0x20004: /* ADP_Stopped_DataAbort */
|
||||
case 0x20005: /* ADP_Stopped_AddressException */
|
||||
case 0x20006: /* ADP_Stopped_IRQ */
|
||||
case 0x20007: /* ADP_Stopped_FIQ */
|
||||
case 0x20020: /* ADP_Stopped_BreakPoint */
|
||||
case 0x20021: /* ADP_Stopped_WatchPoint */
|
||||
case 0x20022: /* ADP_Stopped_StepComplete */
|
||||
case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
|
||||
case 0x20024: /* ADP_Stopped_InternalError */
|
||||
case 0x20025: /* ADP_Stopped_UserInterruption */
|
||||
case 0x20027: /* ADP_Stopped_StackOverflow */
|
||||
case 0x20028: /* ADP_Stopped_DivisionByZero */
|
||||
case 0x20029: /* ADP_Stopped_OSSpecific */
|
||||
default:
|
||||
fprintf(stderr, "semihosting: exception %#x\n",
|
||||
(unsigned) r1);
|
||||
}
|
||||
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
|
||||
case 0x12: /* SYS_SYSTEM */
|
||||
/* Provide SYS_SYSTEM functionality. Uses the
|
||||
* libc system command, there may be a reason *NOT*
|
||||
* to use this, but as I can't think of one, I
|
||||
* implemented it this way.
|
||||
*/
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t len = target_buffer_get_u32(target, params+4);
|
||||
uint32_t c_ptr = target_buffer_get_u32(target, params);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "system";
|
||||
fileio_info->param_1 = c_ptr;
|
||||
fileio_info->param_2 = len;
|
||||
} else {
|
||||
uint8_t cmd[256];
|
||||
if (len > 255) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
} else {
|
||||
memset(cmd, 0x0, 256);
|
||||
retval = target_read_memory(target, c_ptr, 1, len, cmd);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else
|
||||
arm->semihosting_result = system((const char *)cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0d: /* SYS_TMPNAM */
|
||||
case 0x10: /* SYS_CLOCK */
|
||||
case 0x17: /* angel_SWIreason_EnterSVC */
|
||||
case 0x30: /* SYS_ELAPSED */
|
||||
case 0x31: /* SYS_TICKFREQ */
|
||||
default:
|
||||
fprintf(stderr, "semihosting: unsupported call %#x\n",
|
||||
(unsigned) r0);
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOTSUP;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
/* To avoid uneccessary duplication, semihosting prepares the
|
||||
* fileio_info structure out-of-band when the target halts. See
|
||||
* do_semihosting for more detail.
|
||||
*/
|
||||
if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct gdb_fileio_info *fileio_info = target->fileio_info;
|
||||
|
||||
/* clear pending status */
|
||||
arm->semihosting_hit_fileio = false;
|
||||
|
||||
arm->semihosting_result = result;
|
||||
arm->semihosting_errno = fileio_errno;
|
||||
|
||||
/* Some fileio results do not match up with what the semihosting
|
||||
* operation expects; for these operations, we munge the results
|
||||
* below:
|
||||
*/
|
||||
switch (arm->semihosting_op) {
|
||||
case 0x05: /* SYS_WRITE */
|
||||
if (result < 0)
|
||||
arm->semihosting_result = fileio_info->param_3;
|
||||
else
|
||||
arm->semihosting_result = 0;
|
||||
break;
|
||||
|
||||
case 0x06: /* SYS_READ */
|
||||
if (result == (int)fileio_info->param_3)
|
||||
arm->semihosting_result = 0;
|
||||
if (result <= 0)
|
||||
arm->semihosting_result = fileio_info->param_3;
|
||||
break;
|
||||
|
||||
case 0x0a: /* SYS_SEEK */
|
||||
if (result > 0)
|
||||
arm->semihosting_result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return post_result(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize ARM semihosting support.
|
||||
*
|
||||
@@ -630,14 +144,9 @@ static int gdb_fileio_end(struct target *target, int result, int fileio_errno, b
|
||||
*/
|
||||
int arm_semihosting_init(struct target *target)
|
||||
{
|
||||
target->fileio_info = malloc(sizeof(*target->fileio_info));
|
||||
if (target->fileio_info == NULL) {
|
||||
LOG_ERROR("out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
target->type->get_gdb_fileio_info = get_gdb_fileio_info;
|
||||
target->type->gdb_fileio_end = gdb_fileio_end;
|
||||
struct arm *arm = target_to_arm(target);
|
||||
assert(arm->setup_semihosting);
|
||||
semihosting_common_init(target, arm->setup_semihosting, post_result);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -662,7 +171,11 @@ int arm_semihosting(struct target *target, int *retval)
|
||||
uint32_t pc, lr, spsr;
|
||||
struct reg *r;
|
||||
|
||||
if (!arm->is_semihosting)
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
if (!semihosting)
|
||||
return 0;
|
||||
|
||||
if (!semihosting->is_active)
|
||||
return 0;
|
||||
|
||||
if (is_arm7_9(target_to_arm7_9(target)) ||
|
||||
@@ -758,6 +271,24 @@ int arm_semihosting(struct target *target, int *retval)
|
||||
/* bkpt 0xAB */
|
||||
if (insn != 0xBEAB)
|
||||
return 0;
|
||||
} else if (is_armv8(target_to_armv8(target))) {
|
||||
if (target->debug_reason != DBG_REASON_BREAKPOINT)
|
||||
return 0;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
uint32_t insn = 0;
|
||||
r = arm->pc;
|
||||
uint64_t pc64 = buf_get_u64(r->value, 0, 64);
|
||||
*retval = target_read_u32(target, pc64, &insn);
|
||||
|
||||
if (*retval != ERROR_OK)
|
||||
return 1;
|
||||
|
||||
/* bkpt 0xAB */
|
||||
if (insn != 0xD45E0000)
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
} else {
|
||||
LOG_ERROR("Unsupported semi-hosting Target");
|
||||
return 0;
|
||||
@@ -766,32 +297,38 @@ int arm_semihosting(struct target *target, int *retval)
|
||||
/* Perform semihosting if we are not waiting on a fileio
|
||||
* operation to complete.
|
||||
*/
|
||||
if (!arm->semihosting_hit_fileio) {
|
||||
*retval = do_semihosting(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation");
|
||||
if (!semihosting->hit_fileio) {
|
||||
if (is_armv8(target_to_armv8(target)) &&
|
||||
arm->core_state == ARM_STATE_AARCH64) {
|
||||
/* Read op and param from register x0 and x1 respectively. */
|
||||
semihosting->op = buf_get_u64(arm->core_cache->reg_list[0].value, 0, 64);
|
||||
semihosting->param = buf_get_u64(arm->core_cache->reg_list[1].value, 0, 64);
|
||||
semihosting->word_size_bytes = 8;
|
||||
} else {
|
||||
/* Read op and param from register r0 and r1 respectively. */
|
||||
semihosting->op = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
|
||||
semihosting->param = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
|
||||
semihosting->word_size_bytes = 4;
|
||||
}
|
||||
|
||||
/* Check for ARM operation numbers. */
|
||||
if (0 <= semihosting->op && semihosting->op <= 0x31) {
|
||||
*retval = semihosting_common(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Unknown operation number, not a semihosting call. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Post result to target if we are not waiting on a fileio
|
||||
/* Resume if target it is resumable and we are not waiting on a fileio
|
||||
* operation to complete:
|
||||
*/
|
||||
if (!arm->semihosting_hit_fileio) {
|
||||
*retval = post_result(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to post semihosting result");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*retval = target_resume(target, 1, 0, 0, 0);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to resume target");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (semihosting->is_resumable && !semihosting->hit_fileio)
|
||||
return arm_semihosting_resume(target, retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H
|
||||
#define OPENOCD_TARGET_ARM_SEMIHOSTING_H
|
||||
|
||||
#include "semihosting_common.h"
|
||||
|
||||
int arm_semihosting_init(struct target *target);
|
||||
int arm_semihosting(struct target *target, int *retval);
|
||||
|
||||
|
||||
+121
-126
@@ -8,6 +8,9 @@
|
||||
* Copyright (C) 2008 by Oyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -34,6 +37,7 @@
|
||||
#include <helper/binarybuffer.h>
|
||||
#include "algorithm.h"
|
||||
#include "register.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
/* offsets into armv4_5 core register cache */
|
||||
enum {
|
||||
@@ -340,6 +344,50 @@ static const struct {
|
||||
|
||||
};
|
||||
|
||||
static const struct {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
uint32_t bits;
|
||||
enum arm_mode mode;
|
||||
enum reg_type type;
|
||||
const char *group;
|
||||
const char *feature;
|
||||
} arm_vfp_v3_regs[] = {
|
||||
{ ARM_VFP_V3_D0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D1, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D2, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D3, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D4, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D5, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D6, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D7, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D8, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D9, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D10, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D11, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D12, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D13, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D14, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D15, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D16, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D17, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D18, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D19, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D20, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D21, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D22, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D23, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D24, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D25, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D26, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D27, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D28, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D29, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D30, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_D31, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARM_VFP_V3_FPSCR, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp"},
|
||||
};
|
||||
|
||||
/* map core mode (USR, FIQ, ...) and register number to
|
||||
* indices into the register cache
|
||||
*/
|
||||
@@ -567,6 +615,10 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
|
||||
}
|
||||
} else {
|
||||
buf_set_u32(reg->value, 0, 32, value);
|
||||
if (reg->size == 64) {
|
||||
value = buf_get_u32(buf + 4, 0, 32);
|
||||
buf_set_u32(reg->value + 4, 0, 32, value);
|
||||
}
|
||||
reg->valid = 1;
|
||||
}
|
||||
reg->dirty = 1;
|
||||
@@ -582,6 +634,10 @@ static const struct reg_arch_type arm_reg_type = {
|
||||
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||
{
|
||||
int num_regs = ARRAY_SIZE(arm_core_regs);
|
||||
int num_core_regs = num_regs;
|
||||
if (arm->arm_vfp_version == ARM_VFP_V3)
|
||||
num_regs += ARRAY_SIZE(arm_vfp_v3_regs);
|
||||
|
||||
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
|
||||
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
|
||||
struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg));
|
||||
@@ -599,7 +655,7 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||
cache->reg_list = reg_list;
|
||||
cache->num_regs = 0;
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
for (i = 0; i < num_core_regs; i++) {
|
||||
/* Skip registers this core doesn't expose */
|
||||
if (arm_core_regs[i].mode == ARM_MODE_MON
|
||||
&& arm->core_type != ARM_MODE_MON)
|
||||
@@ -651,9 +707,38 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||
cache->num_regs++;
|
||||
}
|
||||
|
||||
int j;
|
||||
for (i = num_core_regs, j = 0; i < num_regs; i++, j++) {
|
||||
reg_arch_info[i].num = arm_vfp_v3_regs[j].id;
|
||||
reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode;
|
||||
reg_arch_info[i].target = target;
|
||||
reg_arch_info[i].arm = arm;
|
||||
|
||||
reg_list[i].name = arm_vfp_v3_regs[j].name;
|
||||
reg_list[i].number = arm_vfp_v3_regs[j].id;
|
||||
reg_list[i].size = arm_vfp_v3_regs[j].bits;
|
||||
reg_list[i].value = reg_arch_info[i].value;
|
||||
reg_list[i].type = &arm_reg_type;
|
||||
reg_list[i].arch_info = ®_arch_info[i];
|
||||
reg_list[i].exist = true;
|
||||
|
||||
reg_list[i].caller_save = false;
|
||||
|
||||
reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
|
||||
reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type;
|
||||
|
||||
reg_list[i].feature = malloc(sizeof(struct reg_feature));
|
||||
reg_list[i].feature->name = arm_vfp_v3_regs[j].feature;
|
||||
|
||||
reg_list[i].group = arm_vfp_v3_regs[j].group;
|
||||
|
||||
cache->num_regs++;
|
||||
}
|
||||
|
||||
arm->pc = reg_list + 15;
|
||||
arm->cpsr = reg_list + ARMV4_5_CPSR;
|
||||
arm->core_cache = cache;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@@ -667,7 +752,7 @@ int arm_arch_state(struct target *target)
|
||||
}
|
||||
|
||||
/* avoid filling log waiting for fileio reply */
|
||||
if (arm->semihosting_hit_fileio)
|
||||
if (target->semihosting && target->semihosting->hit_fileio)
|
||||
return ERROR_OK;
|
||||
|
||||
LOG_USER("target halted in %s state due to %s, current mode: %s\n"
|
||||
@@ -677,8 +762,8 @@ int arm_arch_state(struct target *target)
|
||||
arm_mode_name(arm->core_mode),
|
||||
buf_get_u32(arm->cpsr->value, 0, 32),
|
||||
buf_get_u32(arm->pc->value, 0, 32),
|
||||
arm->is_semihosting ? ", semihosting" : "",
|
||||
arm->is_semihosting_fileio ? " fileio" : "");
|
||||
(target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
|
||||
(target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1013,119 +1098,10 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->setup_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting not supported for current target");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (CMD_ARGC > 0) {
|
||||
int semihosting;
|
||||
|
||||
COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting);
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (arm->setup_semihosting(target, semihosting) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to Configure semihosting");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* FIXME never let that "catch" be dropped! */
|
||||
arm->is_semihosting = semihosting;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "semihosting is %s",
|
||||
arm->is_semihosting
|
||||
? "enabled" : "disabled");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_fileio_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->is_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting is not enabled");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (CMD_ARGC > 0)
|
||||
COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm->is_semihosting_fileio);
|
||||
|
||||
command_print(CMD_CTX, "semihosting fileio is %s",
|
||||
arm->is_semihosting_fileio
|
||||
? "enabled" : "disabled");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_cmdline)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
unsigned int i;
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->setup_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting not supported for current target");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
free(arm->semihosting_cmdline);
|
||||
arm->semihosting_cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
|
||||
|
||||
for (i = 1; i < CMD_ARGC; i++) {
|
||||
char *cmdline = alloc_printf("%s %s", arm->semihosting_cmdline, CMD_ARGV[i]);
|
||||
if (cmdline == NULL)
|
||||
break;
|
||||
free(arm->semihosting_cmdline);
|
||||
arm->semihosting_cmdline = cmdline;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_cmdline);
|
||||
|
||||
static const struct command_registration arm_exec_command_handlers[] = {
|
||||
{
|
||||
@@ -1164,26 +1140,32 @@ static const struct command_registration arm_exec_command_handlers[] = {
|
||||
},
|
||||
{
|
||||
"semihosting",
|
||||
.handler = handle_arm_semihosting_command,
|
||||
.handler = handle_common_semihosting_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting operations",
|
||||
},
|
||||
{
|
||||
"semihosting_cmdline",
|
||||
.handler = handle_arm_semihosting_cmdline,
|
||||
.handler = handle_common_semihosting_cmdline,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "arguments",
|
||||
.help = "command line arguments to be passed to program",
|
||||
},
|
||||
{
|
||||
"semihosting_fileio",
|
||||
.handler = handle_arm_semihosting_fileio_command,
|
||||
.handler = handle_common_semihosting_fileio_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting fileio operations",
|
||||
},
|
||||
|
||||
{
|
||||
"semihosting_resexit",
|
||||
.handler = handle_common_semihosting_resumable_exit_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting resumable exit",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
const struct command_registration arm_command_handlers[] = {
|
||||
@@ -1229,6 +1211,10 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||
|
||||
case REG_CLASS_ALL:
|
||||
*reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51);
|
||||
unsigned int list_size_core = *reg_list_size;
|
||||
if (arm->arm_vfp_version == ARM_VFP_V3)
|
||||
*reg_list_size += 33;
|
||||
|
||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
@@ -1249,6 +1235,12 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
||||
(*reg_list)[24]->size = 0;
|
||||
|
||||
if (arm->arm_vfp_version == ARM_VFP_V3) {
|
||||
unsigned int num_core_regs = ARRAY_SIZE(arm_core_regs);
|
||||
for (i = 0; i < 33; i++)
|
||||
(*reg_list)[list_size_core + i] = &(arm->core_cache->reg_list[num_core_regs + i]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
break;
|
||||
|
||||
@@ -1572,7 +1564,7 @@ cleanup:
|
||||
*
|
||||
*/
|
||||
int arm_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
@@ -1615,10 +1607,10 @@ int arm_blank_check_memory(struct target *target,
|
||||
arm_algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
@@ -1633,7 +1625,7 @@ int arm_blank_check_memory(struct target *target,
|
||||
10000, &arm_algo);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
@@ -1642,7 +1634,10 @@ int arm_blank_check_memory(struct target *target,
|
||||
cleanup:
|
||||
target_free_working_area(target, check_algorithm);
|
||||
|
||||
return retval;
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return 1; /* only one block has been checked */
|
||||
}
|
||||
|
||||
static int arm_full_context(struct target *target)
|
||||
|
||||
+18
-35
@@ -124,14 +124,18 @@ done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv7a_read_ttbcr(struct target *target)
|
||||
int armv7a_read_ttbcr(struct target *target)
|
||||
{
|
||||
struct armv7a_common *armv7a = target_to_armv7a(target);
|
||||
struct arm_dpm *dpm = armv7a->arm.dpm;
|
||||
uint32_t ttbcr, ttbcr_n;
|
||||
int retval = dpm->prepare(dpm);
|
||||
int ttbidx;
|
||||
int retval;
|
||||
|
||||
retval = dpm->prepare(dpm);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
/* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
|
||||
@@ -145,6 +149,15 @@ static int armv7a_read_ttbcr(struct target *target)
|
||||
armv7a->armv7a_mmu.ttbcr = ttbcr;
|
||||
armv7a->armv7a_mmu.cached = 1;
|
||||
|
||||
for (ttbidx = 0; ttbidx < 2; ttbidx++) {
|
||||
/* MRC p15,0,<Rt>,c2,c0,ttbidx */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
|
||||
&armv7a->armv7a_mmu.ttbr[ttbidx]);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
|
||||
* document # ARM DDI 0406C
|
||||
@@ -182,42 +195,21 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
|
||||
uint32_t second_lvl_descriptor = 0x0;
|
||||
int retval;
|
||||
struct armv7a_common *armv7a = target_to_armv7a(target);
|
||||
struct arm_dpm *dpm = armv7a->arm.dpm;
|
||||
uint32_t ttbidx = 0; /* default to ttbr0 */
|
||||
uint32_t ttb_mask;
|
||||
uint32_t va_mask;
|
||||
uint32_t ttbcr;
|
||||
uint32_t ttb;
|
||||
|
||||
retval = dpm->prepare(dpm);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
/* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
|
||||
&ttbcr);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
/* if ttbcr has changed or was not read before, re-read the information */
|
||||
if ((armv7a->armv7a_mmu.cached == 0) ||
|
||||
(armv7a->armv7a_mmu.ttbcr != ttbcr)) {
|
||||
armv7a_read_ttbcr(target);
|
||||
}
|
||||
if (target->state != TARGET_HALTED)
|
||||
LOG_INFO("target not halted, using cached values for translation table!");
|
||||
|
||||
/* if va is above the range handled by ttbr0, select ttbr1 */
|
||||
if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
|
||||
/* select ttb 1 */
|
||||
ttbidx = 1;
|
||||
}
|
||||
/* MRC p15,0,<Rt>,c2,c0,ttbidx */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
|
||||
&ttb);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
|
||||
ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
|
||||
va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
|
||||
|
||||
@@ -279,9 +271,6 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* V7 method VA TO PA */
|
||||
@@ -565,9 +554,6 @@ int armv7a_identify_cache(struct target *target)
|
||||
struct armv7a_cache_common *cache =
|
||||
&(armv7a->armv7a_mmu.armv7a_cache);
|
||||
|
||||
if (!armv7a->is_armv7r)
|
||||
armv7a_read_ttbcr(target);
|
||||
|
||||
retval = dpm->prepare(dpm);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
@@ -785,9 +771,6 @@ const struct command_registration l2x_cache_command_handlers[] = {
|
||||
};
|
||||
|
||||
const struct command_registration armv7a_command_handlers[] = {
|
||||
{
|
||||
.chain = dap_command_handlers,
|
||||
},
|
||||
{
|
||||
.chain = l2x_cache_command_handlers,
|
||||
},
|
||||
|
||||
@@ -87,6 +87,7 @@ struct armv7a_mmu_common {
|
||||
/* following field mmu working way */
|
||||
int32_t cached; /* 0: not initialized, 1: initialized */
|
||||
uint32_t ttbcr; /* cache for ttbcr register */
|
||||
uint32_t ttbr[2];
|
||||
uint32_t ttbr_mask[2];
|
||||
uint32_t ttbr_range[2];
|
||||
|
||||
@@ -193,6 +194,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
|
||||
|
||||
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
|
||||
struct armv7a_cache_common *armv7a_cache);
|
||||
int armv7a_read_ttbcr(struct target *target);
|
||||
|
||||
extern const struct command_registration armv7a_command_handlers[];
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
|
||||
|
||||
LOG_DEBUG("cl %" PRId32, cl);
|
||||
do {
|
||||
keep_alive();
|
||||
c_way = size->way;
|
||||
do {
|
||||
uint32_t value = (c_index << size->index_shift)
|
||||
@@ -89,6 +90,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
|
||||
} while (c_index >= 0);
|
||||
|
||||
done:
|
||||
keep_alive();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -148,10 +150,11 @@ int armv7a_cache_auto_flush_all_data(struct target *target)
|
||||
} else
|
||||
retval = armv7a_l1_d_cache_clean_inval_all(target);
|
||||
|
||||
/* do outer cache flushing after inner caches have been flushed */
|
||||
retval = arm7a_l2x_flush_all_data(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return retval;
|
||||
/* do outer cache flushing after inner caches have been flushed */
|
||||
return arm7a_l2x_flush_all_data(target);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +166,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
|
||||
uint32_t linelen = armv7a_cache->dminline;
|
||||
uint32_t va_line, va_end;
|
||||
int retval;
|
||||
int retval, i = 0;
|
||||
|
||||
retval = armv7a_l1_d_cache_sanity_check(target);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -197,6 +200,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
}
|
||||
|
||||
while (va_line < va_end) {
|
||||
if ((i++ & 0x3f) == 0)
|
||||
keep_alive();
|
||||
/* DCIMVAC - Invalidate data cache line by VA to PoC. */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
|
||||
@@ -205,11 +210,13 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
va_line += linelen;
|
||||
}
|
||||
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
|
||||
done:
|
||||
LOG_ERROR("d-cache invalidate failed");
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
|
||||
return retval;
|
||||
@@ -223,7 +230,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
|
||||
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
|
||||
uint32_t linelen = armv7a_cache->dminline;
|
||||
uint32_t va_line, va_end;
|
||||
int retval;
|
||||
int retval, i = 0;
|
||||
|
||||
retval = armv7a_l1_d_cache_sanity_check(target);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -237,6 +244,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
|
||||
va_end = virt + size;
|
||||
|
||||
while (va_line < va_end) {
|
||||
if ((i++ & 0x3f) == 0)
|
||||
keep_alive();
|
||||
/* DCCMVAC - Data Cache Clean by MVA to PoC */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
|
||||
@@ -245,11 +254,13 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
|
||||
va_line += linelen;
|
||||
}
|
||||
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
|
||||
done:
|
||||
LOG_ERROR("d-cache invalidate failed");
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
|
||||
return retval;
|
||||
@@ -263,7 +274,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
|
||||
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
|
||||
uint32_t linelen = armv7a_cache->dminline;
|
||||
uint32_t va_line, va_end;
|
||||
int retval;
|
||||
int retval, i = 0;
|
||||
|
||||
retval = armv7a_l1_d_cache_sanity_check(target);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -277,6 +288,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
|
||||
va_end = virt + size;
|
||||
|
||||
while (va_line < va_end) {
|
||||
if ((i++ & 0x3f) == 0)
|
||||
keep_alive();
|
||||
/* DCCIMVAC */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
|
||||
@@ -285,11 +298,13 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
|
||||
va_line += linelen;
|
||||
}
|
||||
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
|
||||
done:
|
||||
LOG_ERROR("d-cache invalidate failed");
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
|
||||
return retval;
|
||||
@@ -341,7 +356,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
&armv7a->armv7a_mmu.armv7a_cache;
|
||||
uint32_t linelen = armv7a_cache->iminline;
|
||||
uint32_t va_line, va_end;
|
||||
int retval;
|
||||
int retval, i = 0;
|
||||
|
||||
retval = armv7a_l1_i_cache_sanity_check(target);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -355,6 +370,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
va_end = virt + size;
|
||||
|
||||
while (va_line < va_end) {
|
||||
if ((i++ & 0x3f) == 0)
|
||||
keep_alive();
|
||||
/* ICIMVAU - Invalidate instruction cache by VA to PoU. */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
|
||||
@@ -367,10 +384,13 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
|
||||
goto done;
|
||||
va_line += linelen;
|
||||
}
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
|
||||
done:
|
||||
LOG_ERROR("i-cache invalidate failed");
|
||||
keep_alive();
|
||||
dpm->finish(dpm);
|
||||
|
||||
return retval;
|
||||
|
||||
+102
-42
@@ -11,6 +11,9 @@
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -37,6 +40,7 @@
|
||||
#include "armv7m.h"
|
||||
#include "algorithm.h"
|
||||
#include "register.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
#if 0
|
||||
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||
@@ -537,7 +541,7 @@ int armv7m_arch_state(struct target *target)
|
||||
uint32_t ctrl, sp;
|
||||
|
||||
/* avoid filling log waiting for fileio reply */
|
||||
if (arm->semihosting_hit_fileio)
|
||||
if (target->semihosting && target->semihosting->hit_fileio)
|
||||
return ERROR_OK;
|
||||
|
||||
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
||||
@@ -552,8 +556,8 @@ int armv7m_arch_state(struct target *target)
|
||||
buf_get_u32(arm->pc->value, 0, 32),
|
||||
(ctrl & 0x02) ? 'p' : 'm',
|
||||
sp,
|
||||
arm->is_semihosting ? ", semihosting" : "",
|
||||
arm->is_semihosting_fileio ? " fileio" : "");
|
||||
(target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
|
||||
(target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -731,34 +735,23 @@ cleanup:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Checks whether a memory region is erased. */
|
||||
/** Checks an array of memory regions whether they are erased. */
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
struct working_area *erase_check_params;
|
||||
struct reg_param reg_params[2];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
const uint8_t *code;
|
||||
uint32_t code_size;
|
||||
int retval;
|
||||
|
||||
static bool timed_out;
|
||||
|
||||
static const uint8_t erase_check_code[] = {
|
||||
#include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
|
||||
};
|
||||
static const uint8_t zero_erase_check_code[] = {
|
||||
#include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
|
||||
};
|
||||
|
||||
switch (erased_value) {
|
||||
case 0x00:
|
||||
code = zero_erase_check_code;
|
||||
code_size = sizeof(zero_erase_check_code);
|
||||
break;
|
||||
case 0xff:
|
||||
default:
|
||||
code = erase_check_code;
|
||||
code_size = sizeof(erase_check_code);
|
||||
}
|
||||
const uint32_t code_size = sizeof(erase_check_code);
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, code_size,
|
||||
@@ -766,40 +759,110 @@ int armv7m_blank_check_memory(struct target *target,
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target_write_buffer(target, erase_check_algorithm->address,
|
||||
code_size, code);
|
||||
code_size, erase_check_code);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup;
|
||||
goto cleanup1;
|
||||
|
||||
/* prepare blocks array for algo */
|
||||
struct algo_block {
|
||||
union {
|
||||
uint32_t size;
|
||||
uint32_t result;
|
||||
};
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
uint32_t avail = target_get_working_area_avail(target);
|
||||
int blocks_to_check = avail / sizeof(struct algo_block) - 1;
|
||||
if (num_blocks < blocks_to_check)
|
||||
blocks_to_check = num_blocks;
|
||||
|
||||
struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block));
|
||||
if (params == NULL) {
|
||||
retval = ERROR_FAIL;
|
||||
goto cleanup1;
|
||||
}
|
||||
|
||||
int i;
|
||||
uint32_t total_size = 0;
|
||||
for (i = 0; i < blocks_to_check; i++) {
|
||||
total_size += blocks[i].size;
|
||||
target_buffer_set_u32(target, (uint8_t *)&(params[i].size),
|
||||
blocks[i].size / sizeof(uint32_t));
|
||||
target_buffer_set_u32(target, (uint8_t *)&(params[i].address),
|
||||
blocks[i].address);
|
||||
}
|
||||
target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0);
|
||||
|
||||
uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block);
|
||||
if (target_alloc_working_area(target, param_size,
|
||||
&erase_check_params) != ERROR_OK) {
|
||||
retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
retval = target_write_buffer(target, erase_check_params->address,
|
||||
param_size, (uint8_t *)params);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup3;
|
||||
|
||||
uint32_t erased_word = erased_value | (erased_value << 8)
|
||||
| (erased_value << 16) | (erased_value << 24);
|
||||
|
||||
LOG_DEBUG("Starting erase check of %d blocks, parameters@"
|
||||
TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address);
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, erased_word);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
/* assume CPU clk at least 1 MHz */
|
||||
int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
|
||||
|
||||
retval = target_run_algorithm(target,
|
||||
0,
|
||||
NULL,
|
||||
3,
|
||||
reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (code_size - 2),
|
||||
10000,
|
||||
&armv7m_info);
|
||||
0, NULL,
|
||||
ARRAY_SIZE(reg_params), reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (code_size - 2),
|
||||
timeout,
|
||||
&armv7m_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
timed_out = retval == ERROR_TARGET_TIMEOUT;
|
||||
if (retval != ERROR_OK && !timed_out)
|
||||
goto cleanup4;
|
||||
|
||||
retval = target_read_buffer(target, erase_check_params->address,
|
||||
param_size, (uint8_t *)params);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup4;
|
||||
|
||||
for (i = 0; i < blocks_to_check; i++) {
|
||||
uint32_t result = target_buffer_get_u32(target,
|
||||
(uint8_t *)&(params[i].result));
|
||||
if (result != 0 && result != 1)
|
||||
break;
|
||||
|
||||
blocks[i].result = result;
|
||||
}
|
||||
if (i && timed_out)
|
||||
LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i);
|
||||
|
||||
retval = i; /* return number of blocks really checked */
|
||||
|
||||
cleanup4:
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
cleanup:
|
||||
cleanup3:
|
||||
target_free_working_area(target, erase_check_params);
|
||||
cleanup2:
|
||||
free(params);
|
||||
cleanup1:
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return retval;
|
||||
@@ -843,8 +906,5 @@ const struct command_registration armv7m_command_handlers[] = {
|
||||
{
|
||||
.chain = arm_command_handlers,
|
||||
},
|
||||
{
|
||||
.chain = dap_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ int armv7m_restore_context(struct target *target);
|
||||
int armv7m_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
|
||||
|
||||
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found);
|
||||
|
||||
|
||||
+10
-10
@@ -62,7 +62,7 @@ int armv7m_trace_tpiu_config(struct target *target)
|
||||
target_unregister_timer_callback(armv7m_poll_trace, target);
|
||||
|
||||
|
||||
retval = adapter_config_trace(trace_config->config_type == INTERNAL,
|
||||
retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
|
||||
trace_config->pin_protocol,
|
||||
trace_config->port_size,
|
||||
&trace_config->trace_freq);
|
||||
@@ -83,7 +83,7 @@ int armv7m_trace_tpiu_config(struct target *target)
|
||||
trace_config->trace_freq, trace_config->traceclkin_freq,
|
||||
trace_freq);
|
||||
trace_config->trace_freq = trace_freq;
|
||||
retval = adapter_config_trace(trace_config->config_type == INTERNAL,
|
||||
retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
|
||||
trace_config->pin_protocol,
|
||||
trace_config->port_size,
|
||||
&trace_config->trace_freq);
|
||||
@@ -115,7 +115,7 @@ int armv7m_trace_tpiu_config(struct target *target)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (trace_config->config_type == INTERNAL)
|
||||
if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
|
||||
target_register_timer_callback(armv7m_poll_trace, 1, 1, target);
|
||||
|
||||
target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
|
||||
@@ -173,7 +173,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
|
||||
if (CMD_ARGC == cmd_idx + 1) {
|
||||
close_trace_file(armv7m);
|
||||
|
||||
armv7m->trace_config.config_type = DISABLED;
|
||||
armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
|
||||
if (CMD_CTX->mode == COMMAND_EXEC)
|
||||
return armv7m_trace_tpiu_config(target);
|
||||
else
|
||||
@@ -183,13 +183,13 @@ COMMAND_HANDLER(handle_tpiu_config_command)
|
||||
!strcmp(CMD_ARGV[cmd_idx], "internal")) {
|
||||
close_trace_file(armv7m);
|
||||
|
||||
armv7m->trace_config.config_type = EXTERNAL;
|
||||
armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
|
||||
if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
|
||||
cmd_idx++;
|
||||
if (CMD_ARGC == cmd_idx)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
armv7m->trace_config.config_type = INTERNAL;
|
||||
armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
|
||||
|
||||
if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
|
||||
armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
|
||||
@@ -204,7 +204,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
|
||||
armv7m->trace_config.pin_protocol = SYNC;
|
||||
armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
|
||||
|
||||
cmd_idx++;
|
||||
if (CMD_ARGC == cmd_idx)
|
||||
@@ -213,9 +213,9 @@ COMMAND_HANDLER(handle_tpiu_config_command)
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
|
||||
} else {
|
||||
if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
|
||||
armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER;
|
||||
armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
|
||||
else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
|
||||
armv7m->trace_config.pin_protocol = ASYNC_UART;
|
||||
armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
@@ -237,7 +237,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
|
||||
cmd_idx++;
|
||||
} else {
|
||||
if (armv7m->trace_config.config_type != INTERNAL) {
|
||||
if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
|
||||
LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
*/
|
||||
|
||||
enum trace_config_type {
|
||||
DISABLED, /**< tracing is disabled */
|
||||
EXTERNAL, /**< trace output is captured externally */
|
||||
INTERNAL /**< trace output is handled by OpenOCD adapter driver */
|
||||
TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */
|
||||
TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */
|
||||
TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */
|
||||
};
|
||||
|
||||
enum tpio_pin_protocol {
|
||||
SYNC, /**< synchronous trace output */
|
||||
ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
|
||||
ASYNC_UART /**< asynchronous output with NRZ coding */
|
||||
enum tpiu_pin_protocol {
|
||||
TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */
|
||||
TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
|
||||
TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */
|
||||
};
|
||||
|
||||
enum itm_ts_prescaler {
|
||||
@@ -50,7 +50,7 @@ struct armv7m_trace_config {
|
||||
enum trace_config_type config_type;
|
||||
|
||||
/** Currently active trace output mode */
|
||||
enum tpio_pin_protocol pin_protocol;
|
||||
enum tpiu_pin_protocol pin_protocol;
|
||||
/** TPIU formatter enable/disable (in async mode) */
|
||||
bool formatter;
|
||||
/** Synchronous output port width */
|
||||
|
||||
+567
-84
@@ -1,6 +1,9 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2015 by David Ung *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -36,6 +39,7 @@
|
||||
#include "armv8_opcodes.h"
|
||||
#include "target.h"
|
||||
#include "target_type.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
static const char * const armv8_state_strings[] = {
|
||||
"AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
|
||||
@@ -135,6 +139,16 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
|
||||
ARMV8_MRS_DSPSR(0), &value);
|
||||
value_64 = value;
|
||||
break;
|
||||
case ARMV8_FPSR:
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV8_MRS_FPSR(0), &value);
|
||||
value_64 = value;
|
||||
break;
|
||||
case ARMV8_FPCR:
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV8_MRS_FPCR(0), &value);
|
||||
value_64 = value;
|
||||
break;
|
||||
case ARMV8_ELR_EL1:
|
||||
retval = dpm->instr_read_data_r0_64(dpm,
|
||||
ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64);
|
||||
@@ -184,6 +198,31 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
|
||||
|
||||
if (retval == ERROR_OK && regval != NULL)
|
||||
*regval = value_64;
|
||||
else
|
||||
retval = ERROR_FAIL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
|
||||
switch (regnum) {
|
||||
case ARMV8_V0 ... ARMV8_V31:
|
||||
retval = dpm->instr_read_data_r0_64(dpm,
|
||||
ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 1), hvalue);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = dpm->instr_read_data_r0_64(dpm,
|
||||
ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 0), lvalue);
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -216,6 +255,18 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu
|
||||
ARMV8_MSR_DSPSR(0),
|
||||
value);
|
||||
break;
|
||||
case ARMV8_FPSR:
|
||||
value = value_64;
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV8_MSR_FPSR(0),
|
||||
value);
|
||||
break;
|
||||
case ARMV8_FPCR:
|
||||
value = value_64;
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV8_MSR_FPCR(0),
|
||||
value);
|
||||
break;
|
||||
/* registers clobbered by taking exception in debug state */
|
||||
case ARMV8_ELR_EL1:
|
||||
retval = dpm->instr_write_data_r0_64(dpm,
|
||||
@@ -267,6 +318,29 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv8_write_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
|
||||
switch (regnum) {
|
||||
case ARMV8_V0 ... ARMV8_V31:
|
||||
retval = dpm->instr_write_data_r0_64(dpm,
|
||||
ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 1), hvalue);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = dpm->instr_write_data_r0_64(dpm,
|
||||
ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 0), lvalue);
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval)
|
||||
{
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
@@ -338,6 +412,11 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re
|
||||
ARMV8_MRS_xPSR_T1(1, 0),
|
||||
&value);
|
||||
break;
|
||||
case ARMV8_FPSR:
|
||||
/* "VMRS r0, FPSCR"; then return via DCC */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_VMRS(0), &value);
|
||||
break;
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
@@ -349,6 +428,56 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1;
|
||||
uint32_t value_r0 = 0, value_r1 = 0;
|
||||
unsigned num = (regnum - ARMV8_V0) << 1;
|
||||
|
||||
switch (regnum) {
|
||||
case ARMV8_V0 ... ARMV8_V15:
|
||||
/* we are going to write R1, mark it dirty */
|
||||
reg_r1->dirty = true;
|
||||
/* move from double word register to r0:r1: "vmov r0, r1, vm"
|
||||
* then read r0 via dcc
|
||||
*/
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)),
|
||||
&value_r0);
|
||||
/* read r1 via dcc */
|
||||
retval = dpm->instr_read_data_dcc(dpm,
|
||||
ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
|
||||
&value_r1);
|
||||
if (retval == ERROR_OK) {
|
||||
*lvalue = value_r1;
|
||||
*lvalue = ((*lvalue) << 32) | value_r0;
|
||||
} else
|
||||
return retval;
|
||||
|
||||
num++;
|
||||
/* repeat above steps for high 64 bits of V register */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)),
|
||||
&value_r0);
|
||||
retval = dpm->instr_read_data_dcc(dpm,
|
||||
ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
|
||||
&value_r1);
|
||||
if (retval == ERROR_OK) {
|
||||
*hvalue = value_r1;
|
||||
*hvalue = ((*hvalue) << 32) | value_r0;
|
||||
} else
|
||||
return retval;
|
||||
break;
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value)
|
||||
{
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
@@ -417,6 +546,11 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va
|
||||
ARMV8_MSR_GP_xPSR_T1(1, 0, 15),
|
||||
value);
|
||||
break;
|
||||
case ARMV8_FPSR:
|
||||
/* move to r0 from DCC, then "VMSR FPSCR, r0" */
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_VMSR(0), value);
|
||||
break;
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
@@ -426,14 +560,63 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va
|
||||
|
||||
}
|
||||
|
||||
static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm_dpm *dpm = &armv8->dpm;
|
||||
struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1;
|
||||
uint32_t value_r0 = 0, value_r1 = 0;
|
||||
unsigned num = (regnum - ARMV8_V0) << 1;
|
||||
|
||||
switch (regnum) {
|
||||
case ARMV8_V0 ... ARMV8_V15:
|
||||
/* we are going to write R1, mark it dirty */
|
||||
reg_r1->dirty = true;
|
||||
value_r1 = lvalue >> 32;
|
||||
value_r0 = lvalue & 0xFFFFFFFF;
|
||||
/* write value_r1 to r1 via dcc */
|
||||
retval = dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
|
||||
value_r1);
|
||||
/* write value_r0 to r0 via dcc then,
|
||||
* move to double word register from r0:r1: "vmov vm, r0, r1"
|
||||
*/
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)),
|
||||
value_r0);
|
||||
|
||||
num++;
|
||||
/* repeat above steps for high 64 bits of V register */
|
||||
value_r1 = hvalue >> 32;
|
||||
value_r0 = hvalue & 0xFFFFFFFF;
|
||||
retval = dpm->instr_write_data_dcc(dpm,
|
||||
ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
|
||||
value_r1);
|
||||
retval = dpm->instr_write_data_r0(dpm,
|
||||
ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)),
|
||||
value_r0);
|
||||
break;
|
||||
default:
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64)
|
||||
{
|
||||
if (is_aarch64) {
|
||||
armv8->read_reg_u64 = armv8_read_reg;
|
||||
armv8->write_reg_u64 = armv8_write_reg;
|
||||
armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch64;
|
||||
armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch64;
|
||||
|
||||
} else {
|
||||
armv8->read_reg_u64 = armv8_read_reg32;
|
||||
armv8->write_reg_u64 = armv8_write_reg32;
|
||||
armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch32;
|
||||
armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch32;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,6 +624,7 @@ void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64)
|
||||
int armv8_read_mpidr(struct armv8_common *armv8)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm *arm = &armv8->arm;
|
||||
struct arm_dpm *dpm = armv8->arm.dpm;
|
||||
uint32_t mpidr;
|
||||
|
||||
@@ -448,6 +632,13 @@ int armv8_read_mpidr(struct armv8_common *armv8)
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
/* check if we're in an unprivileged mode */
|
||||
if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
|
||||
retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
@@ -463,6 +654,7 @@ int armv8_read_mpidr(struct armv8_common *armv8)
|
||||
LOG_ERROR("mpidr not in multiprocessor format");
|
||||
|
||||
done:
|
||||
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
}
|
||||
@@ -825,11 +1017,24 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int armv8_setup_semihosting(struct target *target, int enable)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (arm->core_state != ARM_STATE_AARCH64) {
|
||||
LOG_ERROR("semihosting only supported in AArch64 state\n");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
|
||||
{
|
||||
struct arm *arm = &armv8->arm;
|
||||
arm->arch_info = armv8;
|
||||
target->arch_info = &armv8->arm;
|
||||
arm->setup_semihosting = armv8_setup_semihosting;
|
||||
/* target is useful in all function arm v4 5 compatible */
|
||||
armv8->arm.target = target;
|
||||
armv8->arm.common_magic = ARM_COMMON_MAGIC;
|
||||
@@ -858,7 +1063,7 @@ int armv8_aarch64_state(struct target *target)
|
||||
armv8_mode_name(arm->core_mode),
|
||||
buf_get_u32(arm->cpsr->value, 0, 32),
|
||||
buf_get_u64(arm->pc->value, 0, 64),
|
||||
arm->is_semihosting ? ", semihosting" : "");
|
||||
(target->semihosting && target->semihosting->is_active) ? ", semihosting" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -897,63 +1102,150 @@ int armv8_arch_state(struct target *target)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
unsigned id;
|
||||
const char *name;
|
||||
unsigned bits;
|
||||
enum arm_mode mode;
|
||||
enum reg_type type;
|
||||
const char *group;
|
||||
const char *feature;
|
||||
} armv8_regs[] = {
|
||||
{ ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" },
|
||||
static struct reg_data_type aarch64_vector_base_types[] = {
|
||||
{REG_TYPE_IEEE_DOUBLE, "ieee_double", 0, {NULL} },
|
||||
{REG_TYPE_UINT64, "uint64", 0, {NULL} },
|
||||
{REG_TYPE_INT64, "int64", 0, {NULL} },
|
||||
{REG_TYPE_IEEE_SINGLE, "ieee_single", 0, {NULL} },
|
||||
{REG_TYPE_UINT32, "uint32", 0, {NULL} },
|
||||
{REG_TYPE_INT32, "int32", 0, {NULL} },
|
||||
{REG_TYPE_UINT16, "uint16", 0, {NULL} },
|
||||
{REG_TYPE_INT16, "int16", 0, {NULL} },
|
||||
{REG_TYPE_UINT8, "uint8", 0, {NULL} },
|
||||
{REG_TYPE_INT8, "int8", 0, {NULL} },
|
||||
{REG_TYPE_UINT128, "uint128", 0, {NULL} },
|
||||
{REG_TYPE_INT128, "int128", 0, {NULL} }
|
||||
};
|
||||
|
||||
{ ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core" },
|
||||
{ ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core" },
|
||||
static struct reg_data_type_vector aarch64_vector_types[] = {
|
||||
{aarch64_vector_base_types + 0, 2},
|
||||
{aarch64_vector_base_types + 1, 2},
|
||||
{aarch64_vector_base_types + 2, 2},
|
||||
{aarch64_vector_base_types + 3, 4},
|
||||
{aarch64_vector_base_types + 4, 4},
|
||||
{aarch64_vector_base_types + 5, 4},
|
||||
{aarch64_vector_base_types + 6, 8},
|
||||
{aarch64_vector_base_types + 7, 8},
|
||||
{aarch64_vector_base_types + 8, 16},
|
||||
{aarch64_vector_base_types + 9, 16},
|
||||
{aarch64_vector_base_types + 10, 01},
|
||||
{aarch64_vector_base_types + 11, 01},
|
||||
};
|
||||
|
||||
{ ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" },
|
||||
static struct reg_data_type aarch64_fpu_vector[] = {
|
||||
{REG_TYPE_ARCH_DEFINED, "v2d", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 0} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v2u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 1} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v2i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 2} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v4f", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 3} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v4u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 4} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v4i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 5} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v8u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 6} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v8i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 7} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v16u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 8} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v16i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 9} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v1u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 10} },
|
||||
{REG_TYPE_ARCH_DEFINED, "v1i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 11} },
|
||||
};
|
||||
|
||||
{ ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
static struct reg_data_type_union_field aarch64_union_fields_vnd[] = {
|
||||
{"f", aarch64_fpu_vector + 0, aarch64_union_fields_vnd + 1},
|
||||
{"u", aarch64_fpu_vector + 1, aarch64_union_fields_vnd + 2},
|
||||
{"s", aarch64_fpu_vector + 2, NULL},
|
||||
};
|
||||
|
||||
{ ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
static struct reg_data_type_union_field aarch64_union_fields_vns[] = {
|
||||
{"f", aarch64_fpu_vector + 3, aarch64_union_fields_vns + 1},
|
||||
{"u", aarch64_fpu_vector + 4, aarch64_union_fields_vns + 2},
|
||||
{"s", aarch64_fpu_vector + 5, NULL},
|
||||
};
|
||||
|
||||
{ ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
{ ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
|
||||
static struct reg_data_type_union_field aarch64_union_fields_vnh[] = {
|
||||
{"u", aarch64_fpu_vector + 6, aarch64_union_fields_vnh + 1},
|
||||
{"s", aarch64_fpu_vector + 7, NULL},
|
||||
};
|
||||
|
||||
static struct reg_data_type_union_field aarch64_union_fields_vnb[] = {
|
||||
{"u", aarch64_fpu_vector + 8, aarch64_union_fields_vnb + 1},
|
||||
{"s", aarch64_fpu_vector + 9, NULL},
|
||||
};
|
||||
|
||||
static struct reg_data_type_union_field aarch64_union_fields_vnq[] = {
|
||||
{"u", aarch64_fpu_vector + 10, aarch64_union_fields_vnq + 1},
|
||||
{"s", aarch64_fpu_vector + 11, NULL},
|
||||
};
|
||||
|
||||
static struct reg_data_type_union aarch64_union_types[] = {
|
||||
{aarch64_union_fields_vnd},
|
||||
{aarch64_union_fields_vns},
|
||||
{aarch64_union_fields_vnh},
|
||||
{aarch64_union_fields_vnb},
|
||||
{aarch64_union_fields_vnq},
|
||||
};
|
||||
|
||||
static struct reg_data_type aarch64_fpu_union[] = {
|
||||
{REG_TYPE_ARCH_DEFINED, "vnd", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 0} },
|
||||
{REG_TYPE_ARCH_DEFINED, "vns", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 1} },
|
||||
{REG_TYPE_ARCH_DEFINED, "vnh", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 2} },
|
||||
{REG_TYPE_ARCH_DEFINED, "vnb", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 3} },
|
||||
{REG_TYPE_ARCH_DEFINED, "vnq", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 4} },
|
||||
};
|
||||
|
||||
static struct reg_data_type_union_field aarch64v_union_fields[] = {
|
||||
{"d", aarch64_fpu_union + 0, aarch64v_union_fields + 1},
|
||||
{"s", aarch64_fpu_union + 1, aarch64v_union_fields + 2},
|
||||
{"h", aarch64_fpu_union + 2, aarch64v_union_fields + 3},
|
||||
{"b", aarch64_fpu_union + 3, aarch64v_union_fields + 4},
|
||||
{"q", aarch64_fpu_union + 4, NULL},
|
||||
};
|
||||
|
||||
static struct reg_data_type_union aarch64v_union[] = {
|
||||
{aarch64v_union_fields}
|
||||
};
|
||||
|
||||
static struct reg_data_type aarch64v[] = {
|
||||
{REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION,
|
||||
{.reg_type_union = aarch64v_union} },
|
||||
};
|
||||
|
||||
static struct reg_data_type_bitfield aarch64_cpsr_bits[] = {
|
||||
{ 0, 0 , REG_TYPE_UINT8 },
|
||||
{ 2, 3, REG_TYPE_UINT8 },
|
||||
{ 4, 4 , REG_TYPE_UINT8 },
|
||||
{ 6, 6 , REG_TYPE_BOOL },
|
||||
{ 7, 7 , REG_TYPE_BOOL },
|
||||
{ 8, 8 , REG_TYPE_BOOL },
|
||||
{ 9, 9 , REG_TYPE_BOOL },
|
||||
{ 20, 20, REG_TYPE_BOOL },
|
||||
{ 21, 21, REG_TYPE_BOOL },
|
||||
{ 28, 28, REG_TYPE_BOOL },
|
||||
{ 29, 29, REG_TYPE_BOOL },
|
||||
{ 30, 30, REG_TYPE_BOOL },
|
||||
{ 31, 31, REG_TYPE_BOOL },
|
||||
};
|
||||
|
||||
static struct reg_data_type_flags_field aarch64_cpsr_fields[] = {
|
||||
{ "SP", aarch64_cpsr_bits + 0, aarch64_cpsr_fields + 1 },
|
||||
{ "EL", aarch64_cpsr_bits + 1, aarch64_cpsr_fields + 2 },
|
||||
{ "nRW", aarch64_cpsr_bits + 2, aarch64_cpsr_fields + 3 },
|
||||
{ "F" , aarch64_cpsr_bits + 3, aarch64_cpsr_fields + 4 },
|
||||
{ "I" , aarch64_cpsr_bits + 4, aarch64_cpsr_fields + 5 },
|
||||
{ "A" , aarch64_cpsr_bits + 5, aarch64_cpsr_fields + 6 },
|
||||
{ "D" , aarch64_cpsr_bits + 6, aarch64_cpsr_fields + 7 },
|
||||
{ "IL" , aarch64_cpsr_bits + 7, aarch64_cpsr_fields + 8 },
|
||||
{ "SS" , aarch64_cpsr_bits + 8, aarch64_cpsr_fields + 9 },
|
||||
{ "V" , aarch64_cpsr_bits + 9, aarch64_cpsr_fields + 10 },
|
||||
{ "C" , aarch64_cpsr_bits + 10, aarch64_cpsr_fields + 11 },
|
||||
{ "Z" , aarch64_cpsr_bits + 11, aarch64_cpsr_fields + 12 },
|
||||
{ "N" , aarch64_cpsr_bits + 12, NULL }
|
||||
};
|
||||
|
||||
static struct reg_data_type_flags aarch64_cpsr_flags[] = {
|
||||
{ 4, aarch64_cpsr_fields }
|
||||
};
|
||||
|
||||
static struct reg_data_type aarch64_flags_cpsr[] = {
|
||||
{REG_TYPE_ARCH_DEFINED, "cpsr_flags", REG_TYPE_CLASS_FLAGS,
|
||||
{.reg_type_flags = aarch64_cpsr_flags} },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@@ -964,24 +1256,161 @@ static const struct {
|
||||
enum reg_type type;
|
||||
const char *group;
|
||||
const char *feature;
|
||||
struct reg_data_type *data_type;
|
||||
} armv8_regs[] = {
|
||||
{ ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
|
||||
{ ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL},
|
||||
{ ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED,
|
||||
"general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr},
|
||||
{ ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V2, "v2", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V3, "v3", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V4, "v4", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V5, "v5", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V6, "v6", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V7, "v7", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V8, "v8", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V9, "v9", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V10, "v10", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V11, "v11", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V12, "v12", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V13, "v13", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V14, "v14", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V15, "v15", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V16, "v16", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V17, "v17", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V18, "v18", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V19, "v19", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V20, "v20", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V21, "v21", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V22, "v22", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V23, "v23", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V24, "v24", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V25, "v25", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V26, "v26", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V27, "v27", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V28, "v28", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V29, "v29", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V30, "v30", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_V31, "v31", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
|
||||
{ ARMV8_FPSR, "fpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL},
|
||||
{ ARMV8_FPCR, "fpcr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL},
|
||||
|
||||
{ ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
|
||||
{ ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
|
||||
{ ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
{ ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||
NULL},
|
||||
};
|
||||
|
||||
static const struct {
|
||||
unsigned id;
|
||||
unsigned mapping;
|
||||
const char *name;
|
||||
unsigned bits;
|
||||
enum arm_mode mode;
|
||||
enum reg_type type;
|
||||
const char *group;
|
||||
const char *feature;
|
||||
} armv8_regs32[] = {
|
||||
{ ARMV8_R0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R1, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R2, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R3, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R4, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R5, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R6, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R7, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R8, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R9, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R10, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R11, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R12, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R13, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R14, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_PC, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R0, 0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R1, 0, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R2, 0, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R3, 0, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R4, 0, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R5, 0, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R6, 0, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R7, 0, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R8, 0, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R9, 0, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R10, 0, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R11, 0, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R12, 0, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R13, 0, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_R14, 0, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_PC, 0, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_xPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
|
||||
{ ARMV8_V0, 0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V0, 8, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V1, 0, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V1, 8, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V2, 0, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V2, 8, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V3, 0, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V3, 8, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V4, 0, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V4, 8, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V5, 0, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V5, 8, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V6, 0, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V6, 8, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V7, 0, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V7, 8, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V8, 0, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V8, 8, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V9, 0, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V9, 8, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V10, 0, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V10, 8, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V11, 0, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V11, 8, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V12, 0, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V12, 8, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V13, 0, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V13, 8, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V14, 0, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V14, 8, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V15, 0, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_V15, 8, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
|
||||
{ ARMV8_FPSR, 0, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "float", "org.gnu.gdb.arm.vfp"},
|
||||
};
|
||||
|
||||
#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs)
|
||||
@@ -1004,15 +1433,23 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
|
||||
struct arm_reg *armv8_reg = reg->arch_info;
|
||||
struct target *target = armv8_reg->target;
|
||||
struct arm *arm = target_to_arm(target);
|
||||
uint64_t value = buf_get_u64(buf, 0, 64);
|
||||
uint64_t value = buf_get_u64(buf, 0, reg->size);
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
|
||||
if (reg == arm->cpsr) {
|
||||
armv8_set_cpsr(arm, (uint32_t)value);
|
||||
} else {
|
||||
if (reg->size <= 64) {
|
||||
if (reg == arm->cpsr)
|
||||
armv8_set_cpsr(arm, (uint32_t)value);
|
||||
else {
|
||||
buf_set_u64(reg->value, 0, reg->size, value);
|
||||
reg->valid = 1;
|
||||
}
|
||||
} else if (reg->size <= 128) {
|
||||
uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64);
|
||||
|
||||
buf_set_u64(reg->value, 0, 64, value);
|
||||
buf_set_u64(reg->value + 8, 0, reg->size - 64, hvalue);
|
||||
reg->valid = 1;
|
||||
}
|
||||
|
||||
@@ -1061,7 +1498,12 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
|
||||
if (reg64 == arm->cpsr) {
|
||||
armv8_set_cpsr(arm, value);
|
||||
} else {
|
||||
buf_set_u32(reg->value, 0, 32, value);
|
||||
if (reg->size <= 32)
|
||||
buf_set_u32(reg->value, 0, 32, value);
|
||||
else if (reg->size <= 64) {
|
||||
uint64_t value64 = buf_get_u64(buf, 0, 64);
|
||||
buf_set_u64(reg->value, 0, 64, value64);
|
||||
}
|
||||
reg->valid = 1;
|
||||
reg64->valid = 1;
|
||||
}
|
||||
@@ -1123,9 +1565,12 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
|
||||
LOG_ERROR("unable to allocate feature list");
|
||||
|
||||
reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
|
||||
if (reg_list[i].reg_data_type)
|
||||
reg_list[i].reg_data_type->type = armv8_regs[i].type;
|
||||
else
|
||||
if (reg_list[i].reg_data_type) {
|
||||
if (armv8_regs[i].data_type == NULL)
|
||||
reg_list[i].reg_data_type->type = armv8_regs[i].type;
|
||||
else
|
||||
*reg_list[i].reg_data_type = *armv8_regs[i].data_type;
|
||||
} else
|
||||
LOG_ERROR("unable to allocate reg type list");
|
||||
}
|
||||
|
||||
@@ -1142,7 +1587,7 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
|
||||
for (i = 0; i < num_regs32; i++) {
|
||||
reg_list32[i].name = armv8_regs32[i].name;
|
||||
reg_list32[i].size = armv8_regs32[i].bits;
|
||||
reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[0];
|
||||
reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[armv8_regs32[i].mapping];
|
||||
reg_list32[i].type = &armv8_reg32_type;
|
||||
reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id];
|
||||
reg_list32[i].group = armv8_regs32[i].group;
|
||||
@@ -1179,14 +1624,45 @@ struct reg *armv8_reg_current(struct arm *arm, unsigned regnum)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void armv8_free_cache(struct reg_cache *cache, bool regs32)
|
||||
{
|
||||
struct reg *reg;
|
||||
unsigned int i;
|
||||
|
||||
if (!cache)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->num_regs; i++) {
|
||||
reg = &cache->reg_list[i];
|
||||
|
||||
free(reg->feature);
|
||||
free(reg->reg_data_type);
|
||||
}
|
||||
|
||||
if (!regs32)
|
||||
free(cache->reg_list[0].arch_info);
|
||||
free(cache->reg_list);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
void armv8_free_reg_cache(struct target *target)
|
||||
{
|
||||
struct armv8_common *armv8 = target_to_armv8(target);
|
||||
struct arm *arm = &armv8->arm;
|
||||
struct reg_cache *cache = NULL, *cache32 = NULL;
|
||||
|
||||
cache = arm->core_cache;
|
||||
if (cache != NULL)
|
||||
cache32 = cache->next;
|
||||
armv8_free_cache(cache32, true);
|
||||
armv8_free_cache(cache, false);
|
||||
arm->core_cache = NULL;
|
||||
}
|
||||
|
||||
const struct command_registration armv8_command_handlers[] = {
|
||||
{
|
||||
.chain = dap_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
|
||||
int armv8_get_gdb_reg_list(struct target *target,
|
||||
struct reg **reg_list[], int *reg_list_size,
|
||||
enum target_register_class reg_class)
|
||||
@@ -1200,7 +1676,7 @@ int armv8_get_gdb_reg_list(struct target *target,
|
||||
|
||||
switch (reg_class) {
|
||||
case REG_CLASS_GENERAL:
|
||||
*reg_list_size = ARMV8_ELR_EL1;
|
||||
*reg_list_size = ARMV8_V0;
|
||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||
|
||||
for (i = 0; i < *reg_list_size; i++)
|
||||
@@ -1227,6 +1703,13 @@ int armv8_get_gdb_reg_list(struct target *target,
|
||||
|
||||
switch (reg_class) {
|
||||
case REG_CLASS_GENERAL:
|
||||
*reg_list_size = ARMV8_R14 + 3;
|
||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||
|
||||
for (i = 0; i < *reg_list_size; i++)
|
||||
(*reg_list)[i] = cache32->reg_list + i;
|
||||
|
||||
return ERROR_OK;
|
||||
case REG_CLASS_ALL:
|
||||
*reg_list_size = cache32->num_regs;
|
||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||
|
||||
+66
-9
@@ -63,21 +63,62 @@ enum {
|
||||
ARMV8_PC = 32,
|
||||
ARMV8_xPSR = 33,
|
||||
|
||||
ARMV8_ELR_EL1 = 34,
|
||||
ARMV8_ESR_EL1 = 35,
|
||||
ARMV8_SPSR_EL1 = 36,
|
||||
ARMV8_V0 = 34,
|
||||
ARMV8_V1,
|
||||
ARMV8_V2,
|
||||
ARMV8_V3,
|
||||
ARMV8_V4,
|
||||
ARMV8_V5,
|
||||
ARMV8_V6,
|
||||
ARMV8_V7,
|
||||
ARMV8_V8,
|
||||
ARMV8_V9,
|
||||
ARMV8_V10,
|
||||
ARMV8_V11,
|
||||
ARMV8_V12,
|
||||
ARMV8_V13,
|
||||
ARMV8_V14,
|
||||
ARMV8_V15,
|
||||
ARMV8_V16,
|
||||
ARMV8_V17,
|
||||
ARMV8_V18,
|
||||
ARMV8_V19,
|
||||
ARMV8_V20,
|
||||
ARMV8_V21,
|
||||
ARMV8_V22,
|
||||
ARMV8_V23,
|
||||
ARMV8_V24,
|
||||
ARMV8_V25,
|
||||
ARMV8_V26,
|
||||
ARMV8_V27,
|
||||
ARMV8_V28,
|
||||
ARMV8_V29,
|
||||
ARMV8_V30,
|
||||
ARMV8_V31,
|
||||
ARMV8_FPSR,
|
||||
ARMV8_FPCR,
|
||||
|
||||
ARMV8_ELR_EL2 = 37,
|
||||
ARMV8_ESR_EL2 = 38,
|
||||
ARMV8_SPSR_EL2 = 39,
|
||||
ARMV8_ELR_EL1 = 68,
|
||||
ARMV8_ESR_EL1 = 69,
|
||||
ARMV8_SPSR_EL1 = 70,
|
||||
|
||||
ARMV8_ELR_EL3 = 40,
|
||||
ARMV8_ESR_EL3 = 41,
|
||||
ARMV8_SPSR_EL3 = 42,
|
||||
ARMV8_ELR_EL2 = 71,
|
||||
ARMV8_ESR_EL2 = 72,
|
||||
ARMV8_SPSR_EL2 = 73,
|
||||
|
||||
ARMV8_ELR_EL3 = 74,
|
||||
ARMV8_ESR_EL3 = 75,
|
||||
ARMV8_SPSR_EL3 = 76,
|
||||
|
||||
ARMV8_LAST_REG,
|
||||
};
|
||||
|
||||
enum run_control_op {
|
||||
ARMV8_RUNCONTROL_UNKNOWN = 0,
|
||||
ARMV8_RUNCONTROL_RESUME = 1,
|
||||
ARMV8_RUNCONTROL_HALT = 2,
|
||||
ARMV8_RUNCONTROL_STEP = 3,
|
||||
};
|
||||
|
||||
#define ARMV8_COMMON_MAGIC 0x0A450AAA
|
||||
|
||||
@@ -175,10 +216,19 @@ struct armv8_common {
|
||||
|
||||
struct arm_cti *cti;
|
||||
|
||||
/* last run-control command issued to this target (resume, halt, step) */
|
||||
enum run_control_op last_run_control_op;
|
||||
|
||||
/* Direct processor core register read and writes */
|
||||
int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value);
|
||||
int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value);
|
||||
|
||||
/* SIMD/FPU registers read/write interface */
|
||||
int (*read_reg_u128)(struct armv8_common *armv8, int num,
|
||||
uint64_t *lvalue, uint64_t *hvalue);
|
||||
int (*write_reg_u128)(struct armv8_common *armv8, int num,
|
||||
uint64_t lvalue, uint64_t hvalue);
|
||||
|
||||
int (*examine_debug_reason)(struct target *target);
|
||||
int (*post_debug_entry)(struct target *target);
|
||||
|
||||
@@ -191,6 +241,11 @@ target_to_armv8(struct target *target)
|
||||
return container_of(target->arch_info, struct armv8_common, arm);
|
||||
}
|
||||
|
||||
static inline bool is_armv8(struct armv8_common *armv8)
|
||||
{
|
||||
return armv8->common_magic == ARMV8_COMMON_MAGIC;
|
||||
}
|
||||
|
||||
/* register offsets from armv8.debug_base */
|
||||
#define CPUV8_DBG_MAINID0 0xD00
|
||||
#define CPUV8_DBG_CPUFEATURE0 0xD20
|
||||
@@ -277,6 +332,8 @@ static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode)
|
||||
void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64);
|
||||
int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value);
|
||||
|
||||
extern void armv8_free_reg_cache(struct target *target);
|
||||
|
||||
extern const struct command_registration armv8_command_handlers[];
|
||||
|
||||
#endif /* OPENOCD_TARGET_ARMV8_H */
|
||||
|
||||
@@ -310,6 +310,7 @@ int armv8_identify_cache(struct armv8_common *armv8)
|
||||
{
|
||||
/* read cache descriptor */
|
||||
int retval = ERROR_FAIL;
|
||||
struct arm *arm = &armv8->arm;
|
||||
struct arm_dpm *dpm = armv8->arm.dpm;
|
||||
uint32_t csselr, clidr, ctr;
|
||||
uint32_t cache_reg;
|
||||
@@ -320,6 +321,13 @@ int armv8_identify_cache(struct armv8_common *armv8)
|
||||
if (retval != ERROR_OK)
|
||||
goto done;
|
||||
|
||||
/* check if we're in an unprivileged mode */
|
||||
if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
|
||||
retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* retrieve CTR */
|
||||
retval = dpm->instr_read_data_r0(dpm,
|
||||
armv8_opcode(armv8, READ_REG_CTR), &ctr);
|
||||
@@ -417,6 +425,7 @@ int armv8_identify_cache(struct armv8_common *armv8)
|
||||
}
|
||||
|
||||
done:
|
||||
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||
dpm->finish(dpm);
|
||||
return retval;
|
||||
|
||||
|
||||
+63
-26
@@ -258,7 +258,7 @@ static int dpmv8_exec_opcode(struct arm_dpm *dpm,
|
||||
|
||||
if (dscr & DSCR_ERR) {
|
||||
LOG_ERROR("Opcode 0x%08"PRIx32", DSCR.ERR=1, DSCR.EL=%i", opcode, dpm->last_el);
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
armv8_dpm_handle_exception(dpm, true);
|
||||
retval = ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||
armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el);
|
||||
|
||||
/* DCPS clobbers registers just like an exception taken */
|
||||
armv8_dpm_handle_exception(dpm);
|
||||
armv8_dpm_handle_exception(dpm, false);
|
||||
} else {
|
||||
core_state = armv8_dpm_get_core_state(dpm);
|
||||
if (core_state != ARM_STATE_AARCH64) {
|
||||
@@ -650,21 +650,37 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||
static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
struct armv8_common *armv8 = dpm->arm->arch_info;
|
||||
uint64_t value_64;
|
||||
int retval;
|
||||
int retval = ERROR_FAIL;
|
||||
|
||||
retval = armv8->read_reg_u64(armv8, regnum, &value_64);
|
||||
if (r->size <= 64) {
|
||||
uint64_t value_64;
|
||||
retval = armv8->read_reg_u64(armv8, regnum, &value_64);
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
r->valid = true;
|
||||
r->dirty = false;
|
||||
buf_set_u64(r->value, 0, r->size, value_64);
|
||||
if (r->size == 64)
|
||||
LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64);
|
||||
else
|
||||
LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64);
|
||||
if (retval == ERROR_OK) {
|
||||
r->valid = true;
|
||||
r->dirty = false;
|
||||
buf_set_u64(r->value, 0, r->size, value_64);
|
||||
if (r->size == 64)
|
||||
LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64);
|
||||
else
|
||||
LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64);
|
||||
}
|
||||
} else if (r->size <= 128) {
|
||||
uint64_t lvalue = 0, hvalue = 0;
|
||||
retval = armv8->read_reg_u128(armv8, regnum, &lvalue, &hvalue);
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
r->valid = true;
|
||||
r->dirty = false;
|
||||
|
||||
buf_set_u64(r->value, 0, 64, lvalue);
|
||||
buf_set_u64(r->value + 8, 0, r->size - 64, hvalue);
|
||||
|
||||
LOG_DEBUG("READ: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue);
|
||||
LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue);
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -674,20 +690,36 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||
{
|
||||
struct armv8_common *armv8 = dpm->arm->arch_info;
|
||||
int retval = ERROR_FAIL;
|
||||
uint64_t value_64;
|
||||
|
||||
value_64 = buf_get_u64(r->value, 0, r->size);
|
||||
if (r->size <= 64) {
|
||||
uint64_t value_64;
|
||||
|
||||
retval = armv8->write_reg_u64(armv8, regnum, value_64);
|
||||
if (retval == ERROR_OK) {
|
||||
r->dirty = false;
|
||||
if (r->size == 64)
|
||||
LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64);
|
||||
else
|
||||
LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64);
|
||||
value_64 = buf_get_u64(r->value, 0, r->size);
|
||||
retval = armv8->write_reg_u64(armv8, regnum, value_64);
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
r->dirty = false;
|
||||
if (r->size == 64)
|
||||
LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64);
|
||||
else
|
||||
LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64);
|
||||
}
|
||||
} else if (r->size <= 128) {
|
||||
uint64_t lvalue, hvalue;
|
||||
|
||||
lvalue = buf_get_u64(r->value, 0, 64);
|
||||
hvalue = buf_get_u64(r->value + 8, 0, r->size - 64);
|
||||
retval = armv8->write_reg_u128(armv8, regnum, lvalue, hvalue);
|
||||
|
||||
if (retval == ERROR_OK) {
|
||||
r->dirty = false;
|
||||
|
||||
LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue);
|
||||
LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -745,6 +777,10 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||
if (r->valid)
|
||||
continue;
|
||||
|
||||
/* Skip reading FP-SIMD registers */
|
||||
if (r->number >= ARMV8_V0 && r->number <= ARMV8_FPCR)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Only read registers that are available from the
|
||||
* current EL (or core mode).
|
||||
@@ -1262,7 +1298,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr)
|
||||
* This function must not perform any actions that trigger another exception
|
||||
* or a recursion will happen.
|
||||
*/
|
||||
void armv8_dpm_handle_exception(struct arm_dpm *dpm)
|
||||
void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore)
|
||||
{
|
||||
struct armv8_common *armv8 = dpm->arm->arch_info;
|
||||
struct reg_cache *cache = dpm->arm->core_cache;
|
||||
@@ -1308,7 +1344,8 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm)
|
||||
armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64);
|
||||
armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64);
|
||||
|
||||
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||
if (do_restore)
|
||||
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -116,7 +116,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *, uint64_t wfar);
|
||||
#define PRCR_COREPURQ (1 << 3)
|
||||
|
||||
void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr);
|
||||
void armv8_dpm_handle_exception(struct arm_dpm *dpm);
|
||||
void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore);
|
||||
enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm);
|
||||
|
||||
#endif /* OPENOCD_TARGET_ARM_DPM_H */
|
||||
|
||||
@@ -167,6 +167,14 @@
|
||||
#define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd)
|
||||
#define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd)
|
||||
|
||||
#define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd)
|
||||
#define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd)
|
||||
|
||||
#define ARMV8_MRS_FPCR(Rt) (0xd53b4400 | (Rt))
|
||||
#define ARMV8_MRS_FPSR(Rt) (0xd53b4420 | (Rt))
|
||||
#define ARMV8_MSR_FPCR(Rt) (0xd51b4400 | (Rt))
|
||||
#define ARMV8_MSR_FPSR(Rt) (0xd51b4420 | (Rt))
|
||||
|
||||
#define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt)
|
||||
|
||||
enum armv8_opcode {
|
||||
|
||||
@@ -315,11 +315,8 @@ int breakpoint_remove_internal(struct target *target, target_addr_t address)
|
||||
struct breakpoint *breakpoint = target->breakpoints;
|
||||
|
||||
while (breakpoint) {
|
||||
if ((breakpoint->address == address) && (breakpoint->asid == 0))
|
||||
break;
|
||||
else if ((breakpoint->address == 0) && (breakpoint->asid == address))
|
||||
break;
|
||||
else if ((breakpoint->address == address) && (breakpoint->asid != 0))
|
||||
if ((breakpoint->address == address) ||
|
||||
(breakpoint->address == 0 && breakpoint->asid == address))
|
||||
break;
|
||||
breakpoint = breakpoint->next;
|
||||
}
|
||||
|
||||
+60
-34
@@ -54,7 +54,7 @@
|
||||
#include "target_type.h"
|
||||
#include "arm_opcodes.h"
|
||||
#include "arm_semihosting.h"
|
||||
#include "jtag/swd.h"
|
||||
#include "transport/transport.h"
|
||||
#include <helper/time_support.h>
|
||||
|
||||
static int cortex_a_poll(struct target *target);
|
||||
@@ -206,23 +206,27 @@ static int cortex_a_init_debug_access(struct target *target)
|
||||
|
||||
/* lock memory-mapped access to debug registers to prevent
|
||||
* software interference */
|
||||
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
||||
retval = mem_ap_write_u32(armv7a->debug_ap,
|
||||
armv7a->debug_base + CPUDBG_LOCKACCESS, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Disable cacheline fills and force cache write-through in debug state */
|
||||
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
||||
retval = mem_ap_write_u32(armv7a->debug_ap,
|
||||
armv7a->debug_base + CPUDBG_DSCCR, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Disable TLB lookup and refill/eviction in debug state */
|
||||
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
||||
retval = mem_ap_write_u32(armv7a->debug_ap,
|
||||
armv7a->debug_base + CPUDBG_DSMCR, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = dap_run(armv7a->debug_ap->dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Enabling of instruction execution in debug mode is done in debug_entry code */
|
||||
|
||||
/* Resync breakpoint registers */
|
||||
@@ -1293,6 +1297,9 @@ static int cortex_a_post_debug_entry(struct target *target)
|
||||
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg);
|
||||
cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg;
|
||||
|
||||
if (!armv7a->is_armv7r)
|
||||
armv7a_read_ttbcr(target);
|
||||
|
||||
if (armv7a->armv7a_mmu.armv7a_cache.info == -1)
|
||||
armv7a_identify_cache(target);
|
||||
|
||||
@@ -1496,10 +1503,22 @@ static int cortex_a_set_breakpoint(struct target *target,
|
||||
brp_list[brp_i].value);
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
uint8_t code[4];
|
||||
/* length == 2: Thumb breakpoint */
|
||||
if (breakpoint->length == 2)
|
||||
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
||||
else
|
||||
/* length == 3: Thumb-2 breakpoint, actual encoding is
|
||||
* a regular Thumb BKPT instruction but we replace a
|
||||
* 32bit Thumb-2 instruction, so fix-up the breakpoint
|
||||
* length
|
||||
*/
|
||||
if (breakpoint->length == 3) {
|
||||
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
||||
breakpoint->length = 4;
|
||||
} else
|
||||
/* length == 4, normal ARM breakpoint */
|
||||
buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11));
|
||||
|
||||
retval = target_read_memory(target,
|
||||
breakpoint->address & 0xFFFFFFFE,
|
||||
breakpoint->length, 1,
|
||||
@@ -2931,12 +2950,6 @@ static int cortex_a_examine_first(struct target *target)
|
||||
int retval = ERROR_OK;
|
||||
uint32_t didr, cpuid, dbg_osreg;
|
||||
|
||||
retval = dap_dp_init(swjdp);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Could not initialize the debug port");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Search for the APB-AP - it is needed for access to debug registers */
|
||||
retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
|
||||
if (retval != ERROR_OK) {
|
||||
@@ -3118,22 +3131,13 @@ static int cortex_a_init_target(struct command_context *cmd_ctx,
|
||||
}
|
||||
|
||||
static int cortex_a_init_arch_info(struct target *target,
|
||||
struct cortex_a_common *cortex_a, struct jtag_tap *tap)
|
||||
struct cortex_a_common *cortex_a, struct adiv5_dap *dap)
|
||||
{
|
||||
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
|
||||
|
||||
/* Setup struct cortex_a_common */
|
||||
cortex_a->common_magic = CORTEX_A_COMMON_MAGIC;
|
||||
|
||||
/* tap has no dap initialized */
|
||||
if (!tap->dap) {
|
||||
tap->dap = dap_init();
|
||||
|
||||
/* Leave (only) generic DAP stuff for debugport_init() */
|
||||
tap->dap->tap = tap;
|
||||
}
|
||||
|
||||
armv7a->arm.dap = tap->dap;
|
||||
armv7a->arm.dap = dap;
|
||||
|
||||
cortex_a->fast_reg_read = 0;
|
||||
|
||||
@@ -3159,19 +3163,34 @@ static int cortex_a_init_arch_info(struct target *target,
|
||||
static int cortex_a_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common));
|
||||
cortex_a->common_magic = CORTEX_A_COMMON_MAGIC;
|
||||
struct adiv5_private_config *pc;
|
||||
|
||||
if (target->private_config == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
pc = (struct adiv5_private_config *)target->private_config;
|
||||
|
||||
cortex_a->armv7a_common.is_armv7r = false;
|
||||
|
||||
return cortex_a_init_arch_info(target, cortex_a, target->tap);
|
||||
cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3;
|
||||
|
||||
return cortex_a_init_arch_info(target, cortex_a, pc->dap);
|
||||
}
|
||||
|
||||
static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common));
|
||||
cortex_a->common_magic = CORTEX_A_COMMON_MAGIC;
|
||||
struct adiv5_private_config *pc;
|
||||
|
||||
pc = (struct adiv5_private_config *)target->private_config;
|
||||
if (adiv5_verify_config(pc) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
cortex_a->armv7a_common.is_armv7r = true;
|
||||
|
||||
return cortex_a_init_arch_info(target, cortex_a, target->tap);
|
||||
return cortex_a_init_arch_info(target, cortex_a, pc->dap);
|
||||
}
|
||||
|
||||
static void cortex_a_deinit_target(struct target *target)
|
||||
@@ -3182,6 +3201,7 @@ static void cortex_a_deinit_target(struct target *target)
|
||||
free(cortex_a->brp_list);
|
||||
free(dpm->dbp);
|
||||
free(dpm->dwp);
|
||||
free(target->private_config);
|
||||
free(cortex_a);
|
||||
}
|
||||
|
||||
@@ -3209,6 +3229,20 @@ static int cortex_a_virt2phys(struct target *target,
|
||||
struct armv7a_common *armv7a = target_to_armv7a(target);
|
||||
struct adiv5_dap *swjdp = armv7a->arm.dap;
|
||||
uint8_t apsel = swjdp->apsel;
|
||||
int mmu_enabled = 0;
|
||||
|
||||
/*
|
||||
* If the MMU was not enabled at debug entry, there is no
|
||||
* way of knowing if there was ever a valid configuration
|
||||
* for it and thus it's not safe to enable it. In this case,
|
||||
* just return the virtual address as physical.
|
||||
*/
|
||||
cortex_a_mmu(target, &mmu_enabled);
|
||||
if (!mmu_enabled) {
|
||||
*phys = virt;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) {
|
||||
uint32_t ret;
|
||||
retval = armv7a_mmu_translate_va(target,
|
||||
@@ -3404,7 +3438,7 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "dacrfixup",
|
||||
.handler = handle_cortex_a_dacrfixup_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "set domain access control (DACR) to all-manager "
|
||||
"on memory access",
|
||||
.usage = "['on'|'off']",
|
||||
@@ -3466,6 +3500,7 @@ struct target_type cortexa_target = {
|
||||
|
||||
.commands = cortex_a_command_handlers,
|
||||
.target_create = cortex_a_target_create,
|
||||
.target_jim_configure = adiv5_jim_configure,
|
||||
.init_target = cortex_a_init_target,
|
||||
.examine = cortex_a_examine,
|
||||
.deinit_target = cortex_a_deinit_target,
|
||||
@@ -3477,13 +3512,6 @@ struct target_type cortexa_target = {
|
||||
};
|
||||
|
||||
static const struct command_registration cortex_r4_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cache_info",
|
||||
.handler = cortex_a_handle_cache_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "display information about target caches",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "dbginit",
|
||||
.handler = cortex_a_handle_dbginit_command,
|
||||
@@ -3505,9 +3533,6 @@ static const struct command_registration cortex_r4_command_handlers[] = {
|
||||
{
|
||||
.chain = arm_command_handlers,
|
||||
},
|
||||
{
|
||||
.chain = armv7a_command_handlers,
|
||||
},
|
||||
{
|
||||
.name = "cortex_r4",
|
||||
.mode = COMMAND_ANY,
|
||||
@@ -3551,6 +3576,7 @@ struct target_type cortexr4_target = {
|
||||
|
||||
.commands = cortex_r4_command_handlers,
|
||||
.target_create = cortex_r4_target_create,
|
||||
.target_jim_configure = adiv5_jim_configure,
|
||||
.init_target = cortex_a_init_target,
|
||||
.examine = cortex_a_examine,
|
||||
.deinit_target = cortex_a_deinit_target,
|
||||
|
||||
+53
-74
@@ -51,11 +51,6 @@
|
||||
* any longer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the type of a break point required by address location
|
||||
*/
|
||||
#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT)
|
||||
|
||||
/* forward declarations */
|
||||
static int cortex_m_store_core_reg_u32(struct target *target,
|
||||
uint32_t num, uint32_t value);
|
||||
@@ -170,7 +165,7 @@ static int cortex_m_single_step_core(struct target *target)
|
||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||
int retval;
|
||||
|
||||
/* Mask interrupts before clearing halt, if done already. This avoids
|
||||
/* Mask interrupts before clearing halt, if not done already. This avoids
|
||||
* Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
|
||||
* HALT can put the core into an unknown state.
|
||||
*/
|
||||
@@ -242,8 +237,11 @@ static int cortex_m_endreset_event(struct target *target)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* clear any interrupt masking */
|
||||
cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
|
||||
/* Restore proper interrupt masking setting. */
|
||||
if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON)
|
||||
cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0);
|
||||
else
|
||||
cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
|
||||
|
||||
/* Enable features controlled by ITM and DWT blocks, and catch only
|
||||
* the vectors we were told to pay attention to.
|
||||
@@ -868,7 +866,7 @@ static int cortex_m_step(struct target *target, int current,
|
||||
if (breakpoint)
|
||||
retval = cortex_m_set_breakpoint(target, breakpoint);
|
||||
else
|
||||
retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value));
|
||||
retval = breakpoint_add(target, pc_value, 2, BKPT_HARD);
|
||||
bool tmp_bp_set = (retval == ERROR_OK);
|
||||
|
||||
/* No more breakpoints left, just do a step */
|
||||
@@ -1131,9 +1129,6 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (cortex_m->auto_bp_type)
|
||||
breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
uint32_t fpcr_value;
|
||||
while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code))
|
||||
@@ -1145,6 +1140,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
|
||||
breakpoint->set = fp_num + 1;
|
||||
fpcr_value = breakpoint->address | 1;
|
||||
if (cortex_m->fp_rev == 0) {
|
||||
if (breakpoint->address > 0x1FFFFFFF) {
|
||||
LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
uint32_t hilo;
|
||||
hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW;
|
||||
fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1;
|
||||
@@ -1253,21 +1252,6 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
|
||||
if (cortex_m->auto_bp_type)
|
||||
breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
|
||||
|
||||
if (breakpoint->type != BKPT_TYPE_BY_ADDR(breakpoint->address)) {
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
LOG_INFO("flash patch comparator requested outside code memory region");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (breakpoint->type == BKPT_SOFT) {
|
||||
LOG_INFO("soft breakpoint requested in code (flash) memory region");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((breakpoint->type == BKPT_HARD) && (cortex_m->fp_code_available < 1)) {
|
||||
LOG_INFO("no flash patch comparator unit available for hardware breakpoint");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
@@ -1299,9 +1283,6 @@ int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpo
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (cortex_m->auto_bp_type)
|
||||
breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address);
|
||||
|
||||
if (breakpoint->set)
|
||||
cortex_m_unset_breakpoint(target, breakpoint);
|
||||
|
||||
@@ -1832,11 +1813,11 @@ static int cortex_m_dwt_set_reg(struct reg *reg, uint8_t *buf)
|
||||
|
||||
struct dwt_reg {
|
||||
uint32_t addr;
|
||||
char *name;
|
||||
const char *name;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
static struct dwt_reg dwt_base_regs[] = {
|
||||
static const struct dwt_reg dwt_base_regs[] = {
|
||||
{ DWT_CTRL, "dwt_ctrl", 32, },
|
||||
/* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly
|
||||
* increments while the core is asleep.
|
||||
@@ -1845,7 +1826,7 @@ static struct dwt_reg dwt_base_regs[] = {
|
||||
/* plus some 8 bit counters, useful for profiling with TPIU */
|
||||
};
|
||||
|
||||
static struct dwt_reg dwt_comp[] = {
|
||||
static const struct dwt_reg dwt_comp[] = {
|
||||
#define DWT_COMPARATOR(i) \
|
||||
{ DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \
|
||||
{ DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \
|
||||
@@ -1854,6 +1835,18 @@ static struct dwt_reg dwt_comp[] = {
|
||||
DWT_COMPARATOR(1),
|
||||
DWT_COMPARATOR(2),
|
||||
DWT_COMPARATOR(3),
|
||||
DWT_COMPARATOR(4),
|
||||
DWT_COMPARATOR(5),
|
||||
DWT_COMPARATOR(6),
|
||||
DWT_COMPARATOR(7),
|
||||
DWT_COMPARATOR(8),
|
||||
DWT_COMPARATOR(9),
|
||||
DWT_COMPARATOR(10),
|
||||
DWT_COMPARATOR(11),
|
||||
DWT_COMPARATOR(12),
|
||||
DWT_COMPARATOR(13),
|
||||
DWT_COMPARATOR(14),
|
||||
DWT_COMPARATOR(15),
|
||||
#undef DWT_COMPARATOR
|
||||
};
|
||||
|
||||
@@ -1862,7 +1855,7 @@ static const struct reg_arch_type dwt_reg_type = {
|
||||
.set = cortex_m_dwt_set_reg,
|
||||
};
|
||||
|
||||
static void cortex_m_dwt_addreg(struct target *t, struct reg *r, struct dwt_reg *d)
|
||||
static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dwt_reg *d)
|
||||
{
|
||||
struct dwt_reg_state *state;
|
||||
|
||||
@@ -1887,6 +1880,7 @@ void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target)
|
||||
int reg, i;
|
||||
|
||||
target_read_u32(target, DWT_CTRL, &dwtcr);
|
||||
LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr);
|
||||
if (!dwtcr) {
|
||||
LOG_DEBUG("no DWT");
|
||||
return;
|
||||
@@ -1992,12 +1986,6 @@ int cortex_m_examine(struct target *target)
|
||||
/* stlink shares the examine handler but does not support
|
||||
* all its calls */
|
||||
if (!armv7m->stlink) {
|
||||
retval = dap_dp_init(swjdp);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Could not initialize the debug port");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (cortex_m->apsel < 0) {
|
||||
/* Search for the MEM-AP */
|
||||
retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap);
|
||||
@@ -2095,7 +2083,7 @@ int cortex_m_examine(struct target *target)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (armv7m->trace_config.config_type != DISABLED) {
|
||||
if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) {
|
||||
armv7m_trace_tpiu_config(target);
|
||||
armv7m_trace_itm_config(target);
|
||||
}
|
||||
@@ -2104,7 +2092,6 @@ int cortex_m_examine(struct target *target)
|
||||
|
||||
/* Setup FPB */
|
||||
target_read_u32(target, FP_CTRL, &fpcr);
|
||||
cortex_m->auto_bp_type = 1;
|
||||
/* bits [14:12] and [7:4] */
|
||||
cortex_m->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF);
|
||||
cortex_m->fp_num_lit = (fpcr >> 8) & 0xF;
|
||||
@@ -2228,25 +2215,17 @@ static int cortex_m_handle_target_request(void *priv)
|
||||
}
|
||||
|
||||
static int cortex_m_init_arch_info(struct target *target,
|
||||
struct cortex_m_common *cortex_m, struct jtag_tap *tap)
|
||||
struct cortex_m_common *cortex_m, struct adiv5_dap *dap)
|
||||
{
|
||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||
|
||||
armv7m_init_arch_info(target, armv7m);
|
||||
|
||||
/* tap has no dap initialized */
|
||||
if (!tap->dap) {
|
||||
tap->dap = dap_init();
|
||||
|
||||
/* Leave (only) generic DAP stuff for debugport_init() */
|
||||
tap->dap->tap = tap;
|
||||
}
|
||||
|
||||
/* default reset mode is to use srst if fitted
|
||||
* if not it will use CORTEX_M3_RESET_VECTRESET */
|
||||
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
|
||||
|
||||
armv7m->arm.dap = tap->dap;
|
||||
armv7m->arm.dap = dap;
|
||||
|
||||
/* register arch-specific functions */
|
||||
armv7m->examine_debug_reason = cortex_m_examine_debug_reason;
|
||||
@@ -2266,16 +2245,16 @@ static int cortex_m_init_arch_info(struct target *target,
|
||||
static int cortex_m_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
|
||||
|
||||
cortex_m->common_magic = CORTEX_M_COMMON_MAGIC;
|
||||
cortex_m_init_arch_info(target, cortex_m, target->tap);
|
||||
struct adiv5_private_config *pc;
|
||||
|
||||
if (target->private_config != NULL) {
|
||||
struct adiv5_private_config *pc =
|
||||
(struct adiv5_private_config *)target->private_config;
|
||||
cortex_m->apsel = pc->ap_num;
|
||||
} else
|
||||
cortex_m->apsel = -1;
|
||||
pc = (struct adiv5_private_config *)target->private_config;
|
||||
if (adiv5_verify_config(pc) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
cortex_m->apsel = pc->ap_num;
|
||||
|
||||
cortex_m_init_arch_info(target, cortex_m, pc->dap);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -2298,20 +2277,6 @@ static int cortex_m_verify_pointer(struct command_context *cmd_ctx,
|
||||
* cortexm3_target structure, which is only used with CM3 targets.
|
||||
*/
|
||||
|
||||
static const struct {
|
||||
char name[10];
|
||||
unsigned mask;
|
||||
} vec_ids[] = {
|
||||
{ "hard_err", VC_HARDERR, },
|
||||
{ "int_err", VC_INTERR, },
|
||||
{ "bus_err", VC_BUSERR, },
|
||||
{ "state_err", VC_STATERR, },
|
||||
{ "chk_err", VC_CHKERR, },
|
||||
{ "nocp_err", VC_NOCPERR, },
|
||||
{ "mm_err", VC_MMERR, },
|
||||
{ "reset", VC_CORERESET, },
|
||||
};
|
||||
|
||||
COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
@@ -2320,6 +2285,20 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
|
||||
uint32_t demcr = 0;
|
||||
int retval;
|
||||
|
||||
static const struct {
|
||||
char name[10];
|
||||
unsigned mask;
|
||||
} vec_ids[] = {
|
||||
{ "hard_err", VC_HARDERR, },
|
||||
{ "int_err", VC_INTERR, },
|
||||
{ "bus_err", VC_BUSERR, },
|
||||
{ "state_err", VC_STATERR, },
|
||||
{ "chk_err", VC_CHKERR, },
|
||||
{ "nocp_err", VC_NOCPERR, },
|
||||
{ "mm_err", VC_MMERR, },
|
||||
{ "reset", VC_CORERESET, },
|
||||
};
|
||||
|
||||
retval = cortex_m_verify_pointer(CMD_CTX, cortex_m);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
@@ -175,7 +175,6 @@ struct cortex_m_common {
|
||||
int fp_code_available;
|
||||
int fp_rev;
|
||||
int fpb_enabled;
|
||||
int auto_bp_type;
|
||||
struct cortex_m_fp_comparator *fp_comparator_list;
|
||||
|
||||
/* Data Watchpoint and Trace (DWT) */
|
||||
|
||||
+28
-7
@@ -271,7 +271,10 @@ static int hl_target_request_data(struct target *target,
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < (size * 4); i++) {
|
||||
hl_dcc_read(hl_if, &data, &ctrl);
|
||||
int err = hl_dcc_read(hl_if, &data, &ctrl);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
buffer[i] = data;
|
||||
}
|
||||
|
||||
@@ -281,6 +284,8 @@ static int hl_target_request_data(struct target *target,
|
||||
static int hl_handle_target_request(void *priv)
|
||||
{
|
||||
struct target *target = priv;
|
||||
int err;
|
||||
|
||||
if (!target_was_examined(target))
|
||||
return ERROR_OK;
|
||||
struct hl_interface_s *hl_if = target_to_adapter(target);
|
||||
@@ -292,7 +297,9 @@ static int hl_handle_target_request(void *priv)
|
||||
uint8_t data;
|
||||
uint8_t ctrl;
|
||||
|
||||
hl_dcc_read(hl_if, &data, &ctrl);
|
||||
err = hl_dcc_read(hl_if, &data, &ctrl);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
/* check if we have data */
|
||||
if (ctrl & (1 << 0)) {
|
||||
@@ -300,11 +307,20 @@ static int hl_handle_target_request(void *priv)
|
||||
|
||||
/* we assume target is quick enough */
|
||||
request = data;
|
||||
hl_dcc_read(hl_if, &data, &ctrl);
|
||||
err = hl_dcc_read(hl_if, &data, &ctrl);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
request |= (data << 8);
|
||||
hl_dcc_read(hl_if, &data, &ctrl);
|
||||
err = hl_dcc_read(hl_if, &data, &ctrl);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
request |= (data << 16);
|
||||
hl_dcc_read(hl_if, &data, &ctrl);
|
||||
err = hl_dcc_read(hl_if, &data, &ctrl);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
request |= (data << 24);
|
||||
target_request(target, request);
|
||||
}
|
||||
@@ -349,12 +365,16 @@ static int adapter_target_create(struct target *target,
|
||||
Jim_Interp *interp)
|
||||
{
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
struct adiv5_private_config *pc = target->private_config;
|
||||
struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
|
||||
|
||||
if (!cortex_m)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (pc != NULL && pc->ap_num > 0) {
|
||||
LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
adapter_init_arch_info(target, cortex_m, target->tap);
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -785,6 +805,7 @@ struct target_type hla_target = {
|
||||
.init_target = adapter_init_target,
|
||||
.deinit_target = cortex_m_deinit_target,
|
||||
.target_create = adapter_target_create,
|
||||
.target_jim_configure = adiv5_jim_configure,
|
||||
.examine = cortex_m_examine,
|
||||
.commands = adapter_command_handlers,
|
||||
|
||||
|
||||
+298
-264
@@ -121,8 +121,9 @@ static int image_ihex_buffer_complete_inner(struct image *image,
|
||||
{
|
||||
struct image_ihex *ihex = image->type_private;
|
||||
struct fileio *fileio = ihex->fileio;
|
||||
uint32_t full_address = 0x0;
|
||||
uint32_t full_address;
|
||||
uint32_t cooked_bytes;
|
||||
bool end_rec = false;
|
||||
int i;
|
||||
|
||||
/* we can't determine the number of sections that we'll have to create ahead of time,
|
||||
@@ -137,175 +138,190 @@ static int image_ihex_buffer_complete_inner(struct image *image,
|
||||
ihex->buffer = malloc(filesize >> 1);
|
||||
cooked_bytes = 0x0;
|
||||
image->num_sections = 0;
|
||||
section[image->num_sections].private = &ihex->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address = 0x0;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
|
||||
while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) {
|
||||
uint32_t count;
|
||||
uint32_t address;
|
||||
uint32_t record_type;
|
||||
uint32_t checksum;
|
||||
uint8_t cal_checksum = 0;
|
||||
size_t bytes_read = 0;
|
||||
while (!fileio_feof(fileio)) {
|
||||
full_address = 0x0;
|
||||
section[image->num_sections].private = &ihex->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address = 0x0;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
|
||||
if (lpszLine[0] == '#')
|
||||
continue;
|
||||
while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) {
|
||||
uint32_t count;
|
||||
uint32_t address;
|
||||
uint32_t record_type;
|
||||
uint32_t checksum;
|
||||
uint8_t cal_checksum = 0;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count,
|
||||
&address, &record_type) != 3)
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
bytes_read += 9;
|
||||
/* skip comments and blank lines */
|
||||
if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0))
|
||||
continue;
|
||||
|
||||
cal_checksum += (uint8_t)count;
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
cal_checksum += (uint8_t)record_type;
|
||||
if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count,
|
||||
&address, &record_type) != 3)
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
bytes_read += 9;
|
||||
|
||||
if (record_type == 0) { /* Data Record */
|
||||
if ((full_address & 0xffff) != address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
cal_checksum += (uint8_t)count;
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
cal_checksum += (uint8_t)record_type;
|
||||
|
||||
if (record_type == 0) { /* Data Record */
|
||||
if ((full_address & 0xffff) != address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff0000) | address;
|
||||
full_address = (full_address & 0xffff0000) | address;
|
||||
}
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff0000) | address;
|
||||
full_address = (full_address & 0xffff0000) | address;
|
||||
}
|
||||
|
||||
while (count-- > 0) {
|
||||
unsigned value;
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &value);
|
||||
ihex->buffer[cooked_bytes] = (uint8_t)value;
|
||||
cal_checksum += (uint8_t)ihex->buffer[cooked_bytes];
|
||||
bytes_read += 2;
|
||||
cooked_bytes += 1;
|
||||
section[image->num_sections].size += 1;
|
||||
full_address++;
|
||||
}
|
||||
} else if (record_type == 1) { /* End of File Record */
|
||||
/* finish the current section */
|
||||
image->num_sections++;
|
||||
while (count-- > 0) {
|
||||
unsigned value;
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &value);
|
||||
ihex->buffer[cooked_bytes] = (uint8_t)value;
|
||||
cal_checksum += (uint8_t)ihex->buffer[cooked_bytes];
|
||||
bytes_read += 2;
|
||||
cooked_bytes += 1;
|
||||
section[image->num_sections].size += 1;
|
||||
full_address++;
|
||||
}
|
||||
} else if (record_type == 1) { /* End of File Record */
|
||||
/* finish the current section */
|
||||
image->num_sections++;
|
||||
|
||||
/* copy section information */
|
||||
image->sections = malloc(sizeof(struct imagesection) * image->num_sections);
|
||||
for (i = 0; i < image->num_sections; i++) {
|
||||
image->sections[i].private = section[i].private;
|
||||
image->sections[i].base_address = section[i].base_address;
|
||||
image->sections[i].size = section[i].size;
|
||||
image->sections[i].flags = section[i].flags;
|
||||
}
|
||||
/* copy section information */
|
||||
image->sections = malloc(sizeof(struct imagesection) * image->num_sections);
|
||||
for (i = 0; i < image->num_sections; i++) {
|
||||
image->sections[i].private = section[i].private;
|
||||
image->sections[i].base_address = section[i].base_address;
|
||||
image->sections[i].size = section[i].size;
|
||||
image->sections[i].flags = section[i].flags;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
} else if (record_type == 2) { /* Linear Address Record */
|
||||
uint16_t upper_address;
|
||||
end_rec = true;
|
||||
break;
|
||||
} else if (record_type == 2) { /* Linear Address Record */
|
||||
uint16_t upper_address;
|
||||
|
||||
sscanf(&lpszLine[bytes_read], "%4hx", &upper_address);
|
||||
cal_checksum += (uint8_t)(upper_address >> 8);
|
||||
cal_checksum += (uint8_t)upper_address;
|
||||
bytes_read += 4;
|
||||
sscanf(&lpszLine[bytes_read], "%4hx", &upper_address);
|
||||
cal_checksum += (uint8_t)(upper_address >> 8);
|
||||
cal_checksum += (uint8_t)upper_address;
|
||||
bytes_read += 4;
|
||||
|
||||
if ((full_address >> 4) != upper_address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
if ((full_address >> 4) != upper_address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff) | (upper_address << 4);
|
||||
full_address = (full_address & 0xffff) | (upper_address << 4);
|
||||
}
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff) | (upper_address << 4);
|
||||
full_address = (full_address & 0xffff) | (upper_address << 4);
|
||||
}
|
||||
} else if (record_type == 3) { /* Start Segment Address Record */
|
||||
uint32_t dummy;
|
||||
} else if (record_type == 3) { /* Start Segment Address Record */
|
||||
uint32_t dummy;
|
||||
|
||||
/* "Start Segment Address Record" will not be supported
|
||||
* but we must consume it, and do not create an error. */
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy);
|
||||
cal_checksum += (uint8_t)dummy;
|
||||
bytes_read += 2;
|
||||
}
|
||||
} else if (record_type == 4) { /* Extended Linear Address Record */
|
||||
uint16_t upper_address;
|
||||
/* "Start Segment Address Record" will not be supported
|
||||
* but we must consume it, and do not create an error. */
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy);
|
||||
cal_checksum += (uint8_t)dummy;
|
||||
bytes_read += 2;
|
||||
}
|
||||
} else if (record_type == 4) { /* Extended Linear Address Record */
|
||||
uint16_t upper_address;
|
||||
|
||||
sscanf(&lpszLine[bytes_read], "%4hx", &upper_address);
|
||||
cal_checksum += (uint8_t)(upper_address >> 8);
|
||||
cal_checksum += (uint8_t)upper_address;
|
||||
bytes_read += 4;
|
||||
sscanf(&lpszLine[bytes_read], "%4hx", &upper_address);
|
||||
cal_checksum += (uint8_t)(upper_address >> 8);
|
||||
cal_checksum += (uint8_t)upper_address;
|
||||
bytes_read += 4;
|
||||
|
||||
if ((full_address >> 16) != upper_address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
if ((full_address >> 16) != upper_address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
if (image->num_sections >= IMAGE_MAX_SECTIONS) {
|
||||
/* too many sections */
|
||||
LOG_ERROR("Too many sections found in IHEX file");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
}
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&ihex->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff) | (upper_address << 16);
|
||||
full_address = (full_address & 0xffff) | (upper_address << 16);
|
||||
}
|
||||
section[image->num_sections].base_address =
|
||||
(full_address & 0xffff) | (upper_address << 16);
|
||||
full_address = (full_address & 0xffff) | (upper_address << 16);
|
||||
} else if (record_type == 5) { /* Start Linear Address Record */
|
||||
uint32_t start_address;
|
||||
|
||||
sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address);
|
||||
cal_checksum += (uint8_t)(start_address >> 24);
|
||||
cal_checksum += (uint8_t)(start_address >> 16);
|
||||
cal_checksum += (uint8_t)(start_address >> 8);
|
||||
cal_checksum += (uint8_t)start_address;
|
||||
bytes_read += 8;
|
||||
|
||||
image->start_address_set = 1;
|
||||
image->start_address = be_to_h_u32((uint8_t *)&start_address);
|
||||
} else {
|
||||
LOG_ERROR("unhandled IHEX record type: %i", (int)record_type);
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
} else if (record_type == 5) { /* Start Linear Address Record */
|
||||
uint32_t start_address;
|
||||
|
||||
sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address);
|
||||
cal_checksum += (uint8_t)(start_address >> 24);
|
||||
cal_checksum += (uint8_t)(start_address >> 16);
|
||||
cal_checksum += (uint8_t)(start_address >> 8);
|
||||
cal_checksum += (uint8_t)start_address;
|
||||
bytes_read += 8;
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum);
|
||||
|
||||
image->start_address_set = 1;
|
||||
image->start_address = be_to_h_u32((uint8_t *)&start_address);
|
||||
} else {
|
||||
LOG_ERROR("unhandled IHEX record type: %i", (int)record_type);
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) {
|
||||
/* checksum failed */
|
||||
LOG_ERROR("incorrect record checksum found in IHEX file");
|
||||
return ERROR_IMAGE_CHECKSUM;
|
||||
}
|
||||
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum);
|
||||
|
||||
if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) {
|
||||
/* checksum failed */
|
||||
LOG_ERROR("incorrect record checksum found in IHEX file");
|
||||
return ERROR_IMAGE_CHECKSUM;
|
||||
if (end_rec) {
|
||||
end_rec = false;
|
||||
LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR("premature end of IHEX file, no end-of-file record found");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
if (end_rec)
|
||||
return ERROR_OK;
|
||||
else {
|
||||
LOG_ERROR("premature end of IHEX file, no matching end-of-file record found");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -510,8 +526,9 @@ static int image_mot_buffer_complete_inner(struct image *image,
|
||||
{
|
||||
struct image_mot *mot = image->type_private;
|
||||
struct fileio *fileio = mot->fileio;
|
||||
uint32_t full_address = 0x0;
|
||||
uint32_t full_address;
|
||||
uint32_t cooked_bytes;
|
||||
bool end_rec = false;
|
||||
int i;
|
||||
|
||||
/* we can't determine the number of sections that we'll have to create ahead of time,
|
||||
@@ -526,140 +543,158 @@ static int image_mot_buffer_complete_inner(struct image *image,
|
||||
mot->buffer = malloc(filesize >> 1);
|
||||
cooked_bytes = 0x0;
|
||||
image->num_sections = 0;
|
||||
section[image->num_sections].private = &mot->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address = 0x0;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
|
||||
while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) {
|
||||
uint32_t count;
|
||||
uint32_t address;
|
||||
uint32_t record_type;
|
||||
uint32_t checksum;
|
||||
uint8_t cal_checksum = 0;
|
||||
uint32_t bytes_read = 0;
|
||||
while (!fileio_feof(fileio)) {
|
||||
full_address = 0x0;
|
||||
section[image->num_sections].private = &mot->buffer[cooked_bytes];
|
||||
section[image->num_sections].base_address = 0x0;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
|
||||
/* get record type and record length */
|
||||
if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type,
|
||||
&count) != 2)
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) {
|
||||
uint32_t count;
|
||||
uint32_t address;
|
||||
uint32_t record_type;
|
||||
uint32_t checksum;
|
||||
uint8_t cal_checksum = 0;
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
bytes_read += 4;
|
||||
cal_checksum += (uint8_t)count;
|
||||
/* skip comments and blank lines */
|
||||
if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0))
|
||||
continue;
|
||||
|
||||
/* skip checksum byte */
|
||||
count -= 1;
|
||||
/* get record type and record length */
|
||||
if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type,
|
||||
&count) != 2)
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
|
||||
if (record_type == 0) {
|
||||
/* S0 - starting record (optional) */
|
||||
int iValue;
|
||||
bytes_read += 4;
|
||||
cal_checksum += (uint8_t)count;
|
||||
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &iValue);
|
||||
cal_checksum += (uint8_t)iValue;
|
||||
bytes_read += 2;
|
||||
}
|
||||
} else if (record_type >= 1 && record_type <= 3) {
|
||||
switch (record_type) {
|
||||
case 1:
|
||||
/* S1 - 16 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 4;
|
||||
count -= 2;
|
||||
break;
|
||||
/* skip checksum byte */
|
||||
count -= 1;
|
||||
|
||||
case 2:
|
||||
/* S2 - 24 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 16);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 6;
|
||||
count -= 3;
|
||||
break;
|
||||
if (record_type == 0) {
|
||||
/* S0 - starting record (optional) */
|
||||
int iValue;
|
||||
|
||||
case 3:
|
||||
/* S3 - 32 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 24);
|
||||
cal_checksum += (uint8_t)(address >> 16);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 8;
|
||||
count -= 4;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (full_address != address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&mot->buffer[cooked_bytes];
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &iValue);
|
||||
cal_checksum += (uint8_t)iValue;
|
||||
bytes_read += 2;
|
||||
}
|
||||
section[image->num_sections].base_address = address;
|
||||
full_address = address;
|
||||
} else if (record_type >= 1 && record_type <= 3) {
|
||||
switch (record_type) {
|
||||
case 1:
|
||||
/* S1 - 16 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 4;
|
||||
count -= 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* S2 - 24 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 16);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 6;
|
||||
count -= 3;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* S3 - 32 bit address data record */
|
||||
sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address);
|
||||
cal_checksum += (uint8_t)(address >> 24);
|
||||
cal_checksum += (uint8_t)(address >> 16);
|
||||
cal_checksum += (uint8_t)(address >> 8);
|
||||
cal_checksum += (uint8_t)address;
|
||||
bytes_read += 8;
|
||||
count -= 4;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (full_address != address) {
|
||||
/* we encountered a nonconsecutive location, create a new section,
|
||||
* unless the current section has zero size, in which case this specifies
|
||||
* the current section's base address
|
||||
*/
|
||||
if (section[image->num_sections].size != 0) {
|
||||
image->num_sections++;
|
||||
section[image->num_sections].size = 0x0;
|
||||
section[image->num_sections].flags = 0;
|
||||
section[image->num_sections].private =
|
||||
&mot->buffer[cooked_bytes];
|
||||
}
|
||||
section[image->num_sections].base_address = address;
|
||||
full_address = address;
|
||||
}
|
||||
|
||||
while (count-- > 0) {
|
||||
unsigned value;
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &value);
|
||||
mot->buffer[cooked_bytes] = (uint8_t)value;
|
||||
cal_checksum += (uint8_t)mot->buffer[cooked_bytes];
|
||||
bytes_read += 2;
|
||||
cooked_bytes += 1;
|
||||
section[image->num_sections].size += 1;
|
||||
full_address++;
|
||||
}
|
||||
} else if (record_type == 5) {
|
||||
/* S5 is the data count record, we ignore it */
|
||||
uint32_t dummy;
|
||||
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy);
|
||||
cal_checksum += (uint8_t)dummy;
|
||||
bytes_read += 2;
|
||||
}
|
||||
} else if (record_type >= 7 && record_type <= 9) {
|
||||
/* S7, S8, S9 - ending records for 32, 24 and 16bit */
|
||||
image->num_sections++;
|
||||
|
||||
/* copy section information */
|
||||
image->sections = malloc(sizeof(struct imagesection) * image->num_sections);
|
||||
for (i = 0; i < image->num_sections; i++) {
|
||||
image->sections[i].private = section[i].private;
|
||||
image->sections[i].base_address = section[i].base_address;
|
||||
image->sections[i].size = section[i].size;
|
||||
image->sections[i].flags = section[i].flags;
|
||||
}
|
||||
|
||||
end_rec = true;
|
||||
break;
|
||||
} else {
|
||||
LOG_ERROR("unhandled S19 record type: %i", (int)(record_type));
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
while (count-- > 0) {
|
||||
unsigned value;
|
||||
sscanf(&lpszLine[bytes_read], "%2x", &value);
|
||||
mot->buffer[cooked_bytes] = (uint8_t)value;
|
||||
cal_checksum += (uint8_t)mot->buffer[cooked_bytes];
|
||||
bytes_read += 2;
|
||||
cooked_bytes += 1;
|
||||
section[image->num_sections].size += 1;
|
||||
full_address++;
|
||||
}
|
||||
} else if (record_type == 5) {
|
||||
/* S5 is the data count record, we ignore it */
|
||||
uint32_t dummy;
|
||||
/* account for checksum, will always be 0xFF */
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum);
|
||||
cal_checksum += (uint8_t)checksum;
|
||||
|
||||
while (count-- > 0) {
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy);
|
||||
cal_checksum += (uint8_t)dummy;
|
||||
bytes_read += 2;
|
||||
}
|
||||
} else if (record_type >= 7 && record_type <= 9) {
|
||||
/* S7, S8, S9 - ending records for 32, 24 and 16bit */
|
||||
image->num_sections++;
|
||||
|
||||
/* copy section information */
|
||||
image->sections = malloc(sizeof(struct imagesection) * image->num_sections);
|
||||
for (i = 0; i < image->num_sections; i++) {
|
||||
image->sections[i].private = section[i].private;
|
||||
image->sections[i].base_address = section[i].base_address;
|
||||
image->sections[i].size = section[i].size;
|
||||
image->sections[i].flags = section[i].flags;
|
||||
if (cal_checksum != 0xFF) {
|
||||
/* checksum failed */
|
||||
LOG_ERROR("incorrect record checksum found in S19 file");
|
||||
return ERROR_IMAGE_CHECKSUM;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
LOG_ERROR("unhandled S19 record type: %i", (int)(record_type));
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
/* account for checksum, will always be 0xFF */
|
||||
sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum);
|
||||
cal_checksum += (uint8_t)checksum;
|
||||
|
||||
if (cal_checksum != 0xFF) {
|
||||
/* checksum failed */
|
||||
LOG_ERROR("incorrect record checksum found in S19 file");
|
||||
return ERROR_IMAGE_CHECKSUM;
|
||||
if (end_rec) {
|
||||
end_rec = false;
|
||||
LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR("premature end of S19 file, no end-of-file record found");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
if (end_rec)
|
||||
return ERROR_OK;
|
||||
else {
|
||||
LOG_ERROR("premature end of S19 file, no matching end-of-file record found");
|
||||
return ERROR_IMAGE_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1013,8 +1048,7 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu
|
||||
static bool first_init;
|
||||
if (!first_init) {
|
||||
/* Initialize the CRC table and the decoding table. */
|
||||
int i, j;
|
||||
unsigned int c;
|
||||
unsigned int i, j, c;
|
||||
for (i = 0; i < 256; i++) {
|
||||
/* as per gdb */
|
||||
for (c = i << 24, j = 8; j > 0; --j)
|
||||
|
||||
+11
-6
@@ -827,7 +827,8 @@ int mips32_checksum_memory(struct target *target, target_addr_t address,
|
||||
|
||||
/** Checks whether a memory region is erased. */
|
||||
int mips32_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
struct target_memory_check_block *blocks, int num_blocks,
|
||||
uint8_t erased_value)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
@@ -866,16 +867,16 @@ int mips32_blank_check_memory(struct target *target,
|
||||
int retval = target_write_buffer(target, erase_check_algorithm->address,
|
||||
sizeof(erase_check_code), erase_check_code_8);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
goto cleanup;
|
||||
|
||||
mips32_info.common_magic = MIPS32_COMMON_MAGIC;
|
||||
mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32;
|
||||
|
||||
init_reg_param(®_params[0], "r4", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address);
|
||||
|
||||
init_reg_param(®_params[1], "r5", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size);
|
||||
|
||||
init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
@@ -884,15 +885,19 @@ int mips32_blank_check_memory(struct target *target,
|
||||
erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
cleanup:
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return retval;
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return 1; /* only one block has been checked */
|
||||
}
|
||||
|
||||
static int mips32_verify_pointer(struct command_context *cmd_ctx,
|
||||
|
||||
+1
-1
@@ -428,6 +428,6 @@ int mips32_get_gdb_reg_list(struct target *target,
|
||||
int mips32_checksum_memory(struct target *target, target_addr_t address,
|
||||
uint32_t count, uint32_t *checksum);
|
||||
int mips32_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
|
||||
|
||||
#endif /* OPENOCD_TARGET_MIPS32_H */
|
||||
|
||||
@@ -344,6 +344,8 @@ static int mips_m4k_assert_reset(struct target *target)
|
||||
jtag_add_reset(1, 1);
|
||||
else if (!srst_asserted)
|
||||
jtag_add_reset(0, 1);
|
||||
} else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
|
||||
target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
|
||||
} else {
|
||||
if (mips_m4k->is_pic32mx) {
|
||||
LOG_DEBUG("Using MTAP reset to reset processor...");
|
||||
|
||||
+36
-37
@@ -2339,63 +2339,66 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
|
||||
fileio_info->identifier = NULL;
|
||||
}
|
||||
|
||||
uint32_t reg_r0, reg_r1, reg_r2;
|
||||
nds32_get_mapped_reg(nds32, R0, ®_r0);
|
||||
nds32_get_mapped_reg(nds32, R1, ®_r1);
|
||||
nds32_get_mapped_reg(nds32, R2, ®_r2);
|
||||
|
||||
switch (syscall_id) {
|
||||
case NDS32_SYSCALL_EXIT:
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "exit");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_OPEN:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "open");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_4));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
fileio_info->param_4 = reg_r2;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_CLOSE:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "close");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_READ:
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "read");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_WRITE:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "write");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_LSEEK:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "lseek");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_UNLINK:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "unlink");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
@@ -2404,61 +2407,57 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "rename");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
/* reserve fileio_info->param_4 for length of new path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_3,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r1, 256, filename);
|
||||
fileio_info->param_4 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_FSTAT:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "fstat");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
break;
|
||||
case NDS32_SYSCALL_STAT:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "stat");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_GETTIMEOFDAY:
|
||||
fileio_info->identifier = malloc(13);
|
||||
sprintf(fileio_info->identifier, "gettimeofday");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
break;
|
||||
case NDS32_SYSCALL_ISATTY:
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "isatty");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_SYSTEM:
|
||||
{
|
||||
uint8_t command[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "system");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, command);
|
||||
target->type->read_buffer(target, reg_r0, 256, command);
|
||||
fileio_info->param_2 = strlen((char *)command) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -242,3 +242,7 @@ int jsp_register_commands(struct command_context *cmd_ctx)
|
||||
return register_commands(cmd_ctx, NULL, jsp_command_handlers);
|
||||
}
|
||||
|
||||
void jsp_service_free(void)
|
||||
{
|
||||
free(jsp_port);
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@ struct jsp_service {
|
||||
|
||||
int jsp_init(struct or1k_jtag *jtag_info, char *banner);
|
||||
int jsp_register_commands(struct command_context *cmd_ctx);
|
||||
void jsp_service_free(void);
|
||||
|
||||
#endif /* OPENOCD_TARGET_OPENRISC_JSP_SERVER_H */
|
||||
|
||||
@@ -25,12 +25,14 @@
|
||||
struct target;
|
||||
|
||||
enum reg_type {
|
||||
REG_TYPE_BOOL,
|
||||
REG_TYPE_INT,
|
||||
REG_TYPE_INT8,
|
||||
REG_TYPE_INT16,
|
||||
REG_TYPE_INT32,
|
||||
REG_TYPE_INT64,
|
||||
REG_TYPE_INT128,
|
||||
REG_TYPE_UINT,
|
||||
REG_TYPE_UINT8,
|
||||
REG_TYPE_UINT16,
|
||||
REG_TYPE_UINT32,
|
||||
@@ -66,6 +68,7 @@ struct reg_data_type_union {
|
||||
struct reg_data_type_bitfield {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
enum reg_type type;
|
||||
};
|
||||
|
||||
struct reg_data_type_struct_field {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
noinst_LTLIBRARIES += %D%/libriscv.la
|
||||
%C%_libriscv_la_SOURCES = \
|
||||
%D%/asm.h \
|
||||
%D%/batch.h \
|
||||
%D%/debug_defines.h \
|
||||
%D%/encoding.h \
|
||||
%D%/gdb_regs.h \
|
||||
%D%/opcodes.h \
|
||||
%D%/program.h \
|
||||
%D%/riscv.h \
|
||||
%D%/batch.c \
|
||||
%D%/program.c \
|
||||
%D%/riscv-011.c \
|
||||
%D%/riscv-013.c \
|
||||
%D%/riscv.c \
|
||||
%D%/riscv_semihosting.c
|
||||
@@ -160,11 +160,10 @@ void dump_field(const struct scan_field *field)
|
||||
|
||||
log_printf_lf(LOG_LVL_DEBUG,
|
||||
__FILE__, __LINE__, __PRETTY_FUNCTION__,
|
||||
"%db %s %08x @%02x -> %s %08x @%02x [0x%p -> 0x%p]",
|
||||
"%db %s %08x @%02x -> %s %08x @%02x",
|
||||
field->num_bits,
|
||||
op_string[out_op], out_data, out_address,
|
||||
status_string[in_op], in_data, in_address,
|
||||
field->out_value, field->in_value);
|
||||
status_string[in_op], in_data, in_address);
|
||||
} else {
|
||||
log_printf_lf(LOG_LVL_DEBUG,
|
||||
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?",
|
||||
|
||||
+205
-163
@@ -229,7 +229,8 @@
|
||||
* Explains why Debug Mode was entered.
|
||||
*
|
||||
* When there are multiple reasons to enter Debug Mode in a single
|
||||
* cycle, the cause with the highest priority is the one written.
|
||||
* cycle, hardware should set \Fcause to the cause with the highest
|
||||
* priority.
|
||||
*
|
||||
* 1: An {\tt ebreak} instruction was executed. (priority 3)
|
||||
*
|
||||
@@ -245,6 +246,15 @@
|
||||
#define CSR_DCSR_CAUSE_LENGTH 3
|
||||
#define CSR_DCSR_CAUSE (0x7U << CSR_DCSR_CAUSE_OFFSET)
|
||||
/*
|
||||
* When 1, \Fmprv in \Rmstatus takes effect during debug mode.
|
||||
* When 0, it is ignored during debug mode.
|
||||
* Implementing this bit is optional.
|
||||
* If not implemented it should be tied to 0.
|
||||
*/
|
||||
#define CSR_DCSR_MPRVEN_OFFSET 4
|
||||
#define CSR_DCSR_MPRVEN_LENGTH 1
|
||||
#define CSR_DCSR_MPRVEN (0x1U << CSR_DCSR_MPRVEN_OFFSET)
|
||||
/*
|
||||
* When set, there is a Non-Maskable-Interrupt (NMI) pending for the hart.
|
||||
*
|
||||
* Since an NMI can indicate a hardware error condition,
|
||||
@@ -279,14 +289,14 @@
|
||||
#define CSR_DCSR_PRV (0x3U << CSR_DCSR_PRV_OFFSET)
|
||||
#define CSR_DPC 0x7b1
|
||||
#define CSR_DPC_DPC_OFFSET 0
|
||||
#define CSR_DPC_DPC_LENGTH XLEN
|
||||
#define CSR_DPC_DPC (((1L<<XLEN)-1) << CSR_DPC_DPC_OFFSET)
|
||||
#define CSR_DPC_DPC_LENGTH MXLEN
|
||||
#define CSR_DPC_DPC (((1L<<MXLEN)-1) << CSR_DPC_DPC_OFFSET)
|
||||
#define CSR_DSCRATCH0 0x7b2
|
||||
#define CSR_DSCRATCH1 0x7b3
|
||||
#define CSR_TSELECT 0x7a0
|
||||
#define CSR_TSELECT_INDEX_OFFSET 0
|
||||
#define CSR_TSELECT_INDEX_LENGTH XLEN
|
||||
#define CSR_TSELECT_INDEX (((1L<<XLEN)-1) << CSR_TSELECT_INDEX_OFFSET)
|
||||
#define CSR_TSELECT_INDEX_LENGTH MXLEN
|
||||
#define CSR_TSELECT_INDEX (((1L<<MXLEN)-1) << CSR_TSELECT_INDEX_OFFSET)
|
||||
#define CSR_TDATA1 0x7a1
|
||||
/*
|
||||
* 0: There is no trigger at this \Rtselect.
|
||||
@@ -300,12 +310,22 @@
|
||||
* 3: The trigger is an instruction count trigger. The remaining bits
|
||||
* in this register act as described in \Ricount.
|
||||
*
|
||||
* 4: The trigger is an interrupt trigger. The remaining bits
|
||||
* in this register act as described in \Ritrigger.
|
||||
*
|
||||
* 5: The trigger is an exception trigger. The remaining bits
|
||||
* in this register act as described in \Retrigger.
|
||||
*
|
||||
* 15: This trigger exists (so enumeration shouldn't terminate), but
|
||||
* is not currently available.
|
||||
*
|
||||
* Other values are reserved for future use.
|
||||
*
|
||||
* When this field is written to an unsupported value, it takes on its
|
||||
* reset value instead. The reset value is any one of the types
|
||||
* supported by the trigger selected by \Rtselect.
|
||||
*/
|
||||
#define CSR_TDATA1_TYPE_OFFSET (XLEN-4)
|
||||
#define CSR_TDATA1_TYPE_OFFSET (MXLEN-4)
|
||||
#define CSR_TDATA1_TYPE_LENGTH 4
|
||||
#define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET)
|
||||
/*
|
||||
@@ -317,39 +337,57 @@
|
||||
*
|
||||
* This bit is only writable from Debug Mode.
|
||||
*/
|
||||
#define CSR_TDATA1_DMODE_OFFSET (XLEN-5)
|
||||
#define CSR_TDATA1_DMODE_OFFSET (MXLEN-5)
|
||||
#define CSR_TDATA1_DMODE_LENGTH 1
|
||||
#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET)
|
||||
/*
|
||||
* Trigger-specific data.
|
||||
*/
|
||||
#define CSR_TDATA1_DATA_OFFSET 0
|
||||
#define CSR_TDATA1_DATA_LENGTH (XLEN - 5)
|
||||
#define CSR_TDATA1_DATA (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
|
||||
#define CSR_TDATA1_DATA_LENGTH (MXLEN - 5)
|
||||
#define CSR_TDATA1_DATA (((1L<<MXLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
|
||||
#define CSR_TDATA2 0x7a2
|
||||
#define CSR_TDATA2_DATA_OFFSET 0
|
||||
#define CSR_TDATA2_DATA_LENGTH XLEN
|
||||
#define CSR_TDATA2_DATA (((1L<<XLEN)-1) << CSR_TDATA2_DATA_OFFSET)
|
||||
#define CSR_TDATA2_DATA_LENGTH MXLEN
|
||||
#define CSR_TDATA2_DATA (((1L<<MXLEN)-1) << CSR_TDATA2_DATA_OFFSET)
|
||||
#define CSR_TDATA3 0x7a3
|
||||
#define CSR_TDATA3_DATA_OFFSET 0
|
||||
#define CSR_TDATA3_DATA_LENGTH XLEN
|
||||
#define CSR_TDATA3_DATA (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET)
|
||||
#define CSR_TDATA3_DATA_LENGTH MXLEN
|
||||
#define CSR_TDATA3_DATA (((1L<<MXLEN)-1) << CSR_TDATA3_DATA_OFFSET)
|
||||
#define CSR_TINFO 0x7a4
|
||||
/*
|
||||
* One bit for each possible \Ftype enumerated in \Rtdataone. Bit N
|
||||
* corresponds to type N. If the bit is set, then that type is
|
||||
* supported by the currently selected trigger.
|
||||
*
|
||||
* If the currently selected trigger doesn't exist, this field
|
||||
* contains 1.
|
||||
*
|
||||
* If \Ftype is not writable, this register may be unimplemented, in
|
||||
* which case reading it causes an illegal instruction exception. In
|
||||
* this case the debugger can read the only supported type from
|
||||
* \Rtdataone.
|
||||
*/
|
||||
#define CSR_TINFO_INFO_OFFSET 0
|
||||
#define CSR_TINFO_INFO_LENGTH 16
|
||||
#define CSR_TINFO_INFO (0xffffULL << CSR_TINFO_INFO_OFFSET)
|
||||
#define CSR_MCONTROL 0x7a1
|
||||
#define CSR_MCONTROL_TYPE_OFFSET (XLEN-4)
|
||||
#define CSR_MCONTROL_TYPE_OFFSET (MXLEN-4)
|
||||
#define CSR_MCONTROL_TYPE_LENGTH 4
|
||||
#define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET)
|
||||
#define CSR_MCONTROL_DMODE_OFFSET (XLEN-5)
|
||||
#define CSR_MCONTROL_DMODE_OFFSET (MXLEN-5)
|
||||
#define CSR_MCONTROL_DMODE_LENGTH 1
|
||||
#define CSR_MCONTROL_DMODE (0x1ULL << CSR_MCONTROL_DMODE_OFFSET)
|
||||
/*
|
||||
* Specifies the largest naturally aligned powers-of-two (NAPOT) range
|
||||
* supported by the hardware. The value is the logarithm base 2 of the
|
||||
* supported by the hardware when \Fmatch is 1. The value is the
|
||||
* logarithm base 2 of the
|
||||
* number of bytes in that range. A value of 0 indicates that only
|
||||
* exact value matches are supported (one byte range). A value of 63
|
||||
* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
|
||||
* size.
|
||||
*/
|
||||
#define CSR_MCONTROL_MASKMAX_OFFSET (XLEN-11)
|
||||
#define CSR_MCONTROL_MASKMAX_OFFSET (MXLEN-11)
|
||||
#define CSR_MCONTROL_MASKMAX_LENGTH 6
|
||||
#define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET)
|
||||
/*
|
||||
@@ -400,22 +438,8 @@
|
||||
#define CSR_MCONTROL_TIMING_LENGTH 1
|
||||
#define CSR_MCONTROL_TIMING (0x1ULL << CSR_MCONTROL_TIMING_OFFSET)
|
||||
/*
|
||||
* Determines what happens when this trigger matches.
|
||||
*
|
||||
* 0: Raise a breakpoint exception. (Used when software wants to use
|
||||
* the trigger module without an external debugger attached.)
|
||||
*
|
||||
* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.)
|
||||
*
|
||||
* 2: Start tracing.
|
||||
*
|
||||
* 3: Stop tracing.
|
||||
*
|
||||
* 4: Emit trace data for this match. If it is a data access match,
|
||||
* emit appropriate Load/Store Address/Data. If it is an instruction
|
||||
* execution, emit its PC.
|
||||
*
|
||||
* Other values are reserved for future use.
|
||||
* The action to take when the trigger fires. The values are explained
|
||||
* in Table~\ref{tab:action}.
|
||||
*/
|
||||
#define CSR_MCONTROL_ACTION_OFFSET 12
|
||||
#define CSR_MCONTROL_ACTION_LENGTH 6
|
||||
@@ -425,6 +449,18 @@
|
||||
*
|
||||
* 1: While this trigger does not match, it prevents the trigger with
|
||||
* the next index from matching.
|
||||
*
|
||||
* Because \Fchain affects the next trigger, hardware must zero it in
|
||||
* writes to \Rmcontrol that set \Fdmode to 0 if the next trigger has
|
||||
* \Fdmode of 1.
|
||||
* In addition hardware should ignore writes to \Rmcontrol that set
|
||||
* \Fdmode to 1 if the previous trigger has both \Fdmode of 0 and
|
||||
* \Fchain of 1. Debuggers must avoid the latter case by checking
|
||||
* \Fchain on the previous trigger if they're writing \Rmcontrol.
|
||||
*
|
||||
* Implementations that wish to limit the maximum length of a trigger
|
||||
* chain (eg. to meet timing requirements) may do so by zeroing
|
||||
* \Fchain in writes to \Rmcontrol that would make the chain too long.
|
||||
*/
|
||||
#define CSR_MCONTROL_CHAIN_OFFSET 11
|
||||
#define CSR_MCONTROL_CHAIN_LENGTH 1
|
||||
@@ -433,7 +469,7 @@
|
||||
* 0: Matches when the value equals \Rtdatatwo.
|
||||
*
|
||||
* 1: Matches when the top M bits of the value match the top M bits of
|
||||
* \Rtdatatwo. M is XLEN-1 minus the index of the least-significant
|
||||
* \Rtdatatwo. M is MXLEN-1 minus the index of the least-significant
|
||||
* bit containing 0 in \Rtdatatwo.
|
||||
*
|
||||
* 2: Matches when the value is greater than (unsigned) or equal to
|
||||
@@ -492,10 +528,10 @@
|
||||
#define CSR_MCONTROL_LOAD_LENGTH 1
|
||||
#define CSR_MCONTROL_LOAD (0x1ULL << CSR_MCONTROL_LOAD_OFFSET)
|
||||
#define CSR_ICOUNT 0x7a1
|
||||
#define CSR_ICOUNT_TYPE_OFFSET (XLEN-4)
|
||||
#define CSR_ICOUNT_TYPE_OFFSET (MXLEN-4)
|
||||
#define CSR_ICOUNT_TYPE_LENGTH 4
|
||||
#define CSR_ICOUNT_TYPE (0xfULL << CSR_ICOUNT_TYPE_OFFSET)
|
||||
#define CSR_ICOUNT_DMODE_OFFSET (XLEN-5)
|
||||
#define CSR_ICOUNT_DMODE_OFFSET (MXLEN-5)
|
||||
#define CSR_ICOUNT_DMODE_LENGTH 1
|
||||
#define CSR_ICOUNT_DMODE (0x1ULL << CSR_ICOUNT_DMODE_OFFSET)
|
||||
/*
|
||||
@@ -539,26 +575,102 @@
|
||||
#define CSR_ICOUNT_U_LENGTH 1
|
||||
#define CSR_ICOUNT_U (0x1ULL << CSR_ICOUNT_U_OFFSET)
|
||||
/*
|
||||
* Determines what happens when this trigger matches.
|
||||
*
|
||||
* 0: Raise a breakpoint exception. (Used when software wants to use the
|
||||
* trigger module without an external debugger attached.)
|
||||
*
|
||||
* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.)
|
||||
*
|
||||
* 2: Start tracing.
|
||||
*
|
||||
* 3: Stop tracing.
|
||||
*
|
||||
* 4: Emit trace data for this match. If it is a data access match,
|
||||
* emit appropriate Load/Store Address/Data. If it is an instruction
|
||||
* execution, emit its PC.
|
||||
*
|
||||
* Other values are reserved for future use.
|
||||
* The action to take when the trigger fires. The values are explained
|
||||
* in Table~\ref{tab:action}.
|
||||
*/
|
||||
#define CSR_ICOUNT_ACTION_OFFSET 0
|
||||
#define CSR_ICOUNT_ACTION_LENGTH 6
|
||||
#define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET)
|
||||
#define CSR_ITRIGGER 0x7a1
|
||||
#define CSR_ITRIGGER_TYPE_OFFSET (MXLEN-4)
|
||||
#define CSR_ITRIGGER_TYPE_LENGTH 4
|
||||
#define CSR_ITRIGGER_TYPE (0xfULL << CSR_ITRIGGER_TYPE_OFFSET)
|
||||
#define CSR_ITRIGGER_DMODE_OFFSET (MXLEN-5)
|
||||
#define CSR_ITRIGGER_DMODE_LENGTH 1
|
||||
#define CSR_ITRIGGER_DMODE (0x1ULL << CSR_ITRIGGER_DMODE_OFFSET)
|
||||
/*
|
||||
* If this optional bit is implemented, the hardware sets it when this
|
||||
* trigger matches. The trigger's user can set or clear it at any
|
||||
* time. The trigger's user can use this bit to determine which
|
||||
* trigger(s) matched. If the bit is not implemented, it is always 0
|
||||
* and writing it has no effect.
|
||||
*/
|
||||
#define CSR_ITRIGGER_HIT_OFFSET (MXLEN-6)
|
||||
#define CSR_ITRIGGER_HIT_LENGTH 1
|
||||
#define CSR_ITRIGGER_HIT (0x1ULL << CSR_ITRIGGER_HIT_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for interrupts that are taken from M
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ITRIGGER_M_OFFSET 9
|
||||
#define CSR_ITRIGGER_M_LENGTH 1
|
||||
#define CSR_ITRIGGER_M (0x1ULL << CSR_ITRIGGER_M_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for interrupts that are taken from S
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ITRIGGER_S_OFFSET 7
|
||||
#define CSR_ITRIGGER_S_LENGTH 1
|
||||
#define CSR_ITRIGGER_S (0x1ULL << CSR_ITRIGGER_S_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for interrupts that are taken from U
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ITRIGGER_U_OFFSET 6
|
||||
#define CSR_ITRIGGER_U_LENGTH 1
|
||||
#define CSR_ITRIGGER_U (0x1ULL << CSR_ITRIGGER_U_OFFSET)
|
||||
/*
|
||||
* The action to take when the trigger fires. The values are explained
|
||||
* in Table~\ref{tab:action}.
|
||||
*/
|
||||
#define CSR_ITRIGGER_ACTION_OFFSET 0
|
||||
#define CSR_ITRIGGER_ACTION_LENGTH 6
|
||||
#define CSR_ITRIGGER_ACTION (0x3fULL << CSR_ITRIGGER_ACTION_OFFSET)
|
||||
#define CSR_ETRIGGER 0x7a1
|
||||
#define CSR_ETRIGGER_TYPE_OFFSET (MXLEN-4)
|
||||
#define CSR_ETRIGGER_TYPE_LENGTH 4
|
||||
#define CSR_ETRIGGER_TYPE (0xfULL << CSR_ETRIGGER_TYPE_OFFSET)
|
||||
#define CSR_ETRIGGER_DMODE_OFFSET (MXLEN-5)
|
||||
#define CSR_ETRIGGER_DMODE_LENGTH 1
|
||||
#define CSR_ETRIGGER_DMODE (0x1ULL << CSR_ETRIGGER_DMODE_OFFSET)
|
||||
/*
|
||||
* If this optional bit is implemented, the hardware sets it when this
|
||||
* trigger matches. The trigger's user can set or clear it at any
|
||||
* time. The trigger's user can use this bit to determine which
|
||||
* trigger(s) matched. If the bit is not implemented, it is always 0
|
||||
* and writing it has no effect.
|
||||
*/
|
||||
#define CSR_ETRIGGER_HIT_OFFSET (MXLEN-6)
|
||||
#define CSR_ETRIGGER_HIT_LENGTH 1
|
||||
#define CSR_ETRIGGER_HIT (0x1ULL << CSR_ETRIGGER_HIT_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for exceptions that are taken from M
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ETRIGGER_M_OFFSET 9
|
||||
#define CSR_ETRIGGER_M_LENGTH 1
|
||||
#define CSR_ETRIGGER_M (0x1ULL << CSR_ETRIGGER_M_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for exceptions that are taken from S
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ETRIGGER_S_OFFSET 7
|
||||
#define CSR_ETRIGGER_S_LENGTH 1
|
||||
#define CSR_ETRIGGER_S (0x1ULL << CSR_ETRIGGER_S_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger for exceptions that are taken from U
|
||||
* mode.
|
||||
*/
|
||||
#define CSR_ETRIGGER_U_OFFSET 6
|
||||
#define CSR_ETRIGGER_U_LENGTH 1
|
||||
#define CSR_ETRIGGER_U (0x1ULL << CSR_ETRIGGER_U_OFFSET)
|
||||
/*
|
||||
* The action to take when the trigger fires. The values are explained
|
||||
* in Table~\ref{tab:action}.
|
||||
*/
|
||||
#define CSR_ETRIGGER_ACTION_OFFSET 0
|
||||
#define CSR_ETRIGGER_ACTION_LENGTH 6
|
||||
#define CSR_ETRIGGER_ACTION (0x3fULL << CSR_ETRIGGER_ACTION_OFFSET)
|
||||
#define DMI_DMSTATUS 0x11
|
||||
/*
|
||||
* If 1, then there is an implicit {\tt ebreak} instruction at the
|
||||
@@ -667,6 +779,14 @@
|
||||
#define DMI_DMSTATUS_AUTHBUSY_LENGTH 1
|
||||
#define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET)
|
||||
/*
|
||||
* 1 if this Debug Module supports halt-on-reset functionality
|
||||
* controllable by the \Fsetresethaltreq and \Fclrresethaltreq bits.
|
||||
* 0 otherwise.
|
||||
*/
|
||||
#define DMI_DMSTATUS_HASRESETHALTREQ_OFFSET 5
|
||||
#define DMI_DMSTATUS_HASRESETHALTREQ_LENGTH 1
|
||||
#define DMI_DMSTATUS_HASRESETHALTREQ (0x1U << DMI_DMSTATUS_HASRESETHALTREQ_OFFSET)
|
||||
/*
|
||||
* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which
|
||||
* is not relevant to the Device Tree.
|
||||
*
|
||||
@@ -772,6 +892,29 @@
|
||||
#define DMI_DMCONTROL_HARTSELHI_LENGTH 10
|
||||
#define DMI_DMCONTROL_HARTSELHI (0x3ffU << DMI_DMCONTROL_HARTSELHI_OFFSET)
|
||||
/*
|
||||
* This optional field writes the halt-on-reset request bit for all
|
||||
* currently selected harts.
|
||||
* When set to 1, each selected hart will halt upon the next deassertion
|
||||
* of its reset. The halt-on-reset request bit is not automatically
|
||||
* cleared. The debugger must write to \Fclrresethaltreq to clear it.
|
||||
*
|
||||
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
||||
*
|
||||
* If \Fhasresethaltreq is 0, this field is not implemented.
|
||||
*/
|
||||
#define DMI_DMCONTROL_SETRESETHALTREQ_OFFSET 3
|
||||
#define DMI_DMCONTROL_SETRESETHALTREQ_LENGTH 1
|
||||
#define DMI_DMCONTROL_SETRESETHALTREQ (0x1U << DMI_DMCONTROL_SETRESETHALTREQ_OFFSET)
|
||||
/*
|
||||
* This optional field clears the halt-on-reset request bit for all
|
||||
* currently selected harts.
|
||||
*
|
||||
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
||||
*/
|
||||
#define DMI_DMCONTROL_CLRRESETHALTREQ_OFFSET 2
|
||||
#define DMI_DMCONTROL_CLRRESETHALTREQ_LENGTH 1
|
||||
#define DMI_DMCONTROL_CLRRESETHALTREQ (0x1U << DMI_DMCONTROL_CLRRESETHALTREQ_OFFSET)
|
||||
/*
|
||||
* This bit controls the reset signal from the DM to the rest of the
|
||||
* system. The signal should reset every part of the system, including
|
||||
* every hart, except for the DM and any logic required to access the
|
||||
@@ -796,7 +939,7 @@
|
||||
* Debug Module after power up, including the platform's system reset
|
||||
* or Debug Transport reset signals.
|
||||
*
|
||||
* A debugger may pulse this bit low to get the debug module into a
|
||||
* A debugger may pulse this bit low to get the Debug Module into a
|
||||
* known state.
|
||||
*
|
||||
* Implementations may use this bit to aid debugging, for example by
|
||||
@@ -818,7 +961,7 @@
|
||||
#define DMI_HARTINFO_NSCRATCH (0xfU << DMI_HARTINFO_NSCRATCH_OFFSET)
|
||||
/*
|
||||
* 0: The {\tt data} registers are shadowed in the hart by CSR
|
||||
* registers. Each CSR register is XLEN bits in size, and corresponds
|
||||
* registers. Each CSR register is MXLEN bits in size, and corresponds
|
||||
* to a single argument, per Table~\ref{tab:datareg}.
|
||||
*
|
||||
* 1: The {\tt data} registers are shadowed in the hart's memory map.
|
||||
@@ -1009,7 +1152,7 @@
|
||||
* it's explicitly cleared by the debugger.
|
||||
*
|
||||
* While this field is non-zero, no more system bus accesses can be
|
||||
* initiated by the debug module.
|
||||
* initiated by the Debug Module.
|
||||
*/
|
||||
#define DMI_SBCS_SBBUSYERROR_OFFSET 22
|
||||
#define DMI_SBCS_SBBUSYERROR_LENGTH 1
|
||||
@@ -1020,8 +1163,9 @@
|
||||
* bit goes high immediately when a read or write is requested for any
|
||||
* reason, and does not go low until the access is fully completed.
|
||||
*
|
||||
* To avoid race conditions, debuggers must not try to clear \Fsberror
|
||||
* until they read \Fsbbusy as 0.
|
||||
* Writes to \Rsbcs while \Fsbbusy is high result in undefined
|
||||
* behavior. A debugger must not write to \Rsbcs until it reads
|
||||
* \Fsbbusy as 0.
|
||||
*/
|
||||
#define DMI_SBCS_SBBUSY_OFFSET 21
|
||||
#define DMI_SBCS_SBBUSY_LENGTH 1
|
||||
@@ -1067,11 +1211,13 @@
|
||||
#define DMI_SBCS_SBREADONDATA_LENGTH 1
|
||||
#define DMI_SBCS_SBREADONDATA (0x1U << DMI_SBCS_SBREADONDATA_OFFSET)
|
||||
/*
|
||||
* When the debug module's system bus
|
||||
* When the Debug Module's system bus
|
||||
* master causes a bus error, this field gets set. The bits in this
|
||||
* field remain set until they are cleared by writing 1 to them.
|
||||
* While this field is non-zero, no more system bus accesses can be
|
||||
* initiated by the debug module.
|
||||
* initiated by the Debug Module.
|
||||
*
|
||||
* An implementation may report "Other" (7) for any error condition.
|
||||
*
|
||||
* An implementation may report "Other" (7) for any error condition.
|
||||
*
|
||||
@@ -1268,107 +1414,3 @@
|
||||
#define VIRT_PRIV_PRV_OFFSET 0
|
||||
#define VIRT_PRIV_PRV_LENGTH 2
|
||||
#define VIRT_PRIV_PRV (0x3U << VIRT_PRIV_PRV_OFFSET)
|
||||
#define DMI_SERCS 0x34
|
||||
/*
|
||||
* Number of supported serial ports.
|
||||
*/
|
||||
#define DMI_SERCS_SERIALCOUNT_OFFSET 28
|
||||
#define DMI_SERCS_SERIALCOUNT_LENGTH 4
|
||||
#define DMI_SERCS_SERIALCOUNT (0xfU << DMI_SERCS_SERIALCOUNT_OFFSET)
|
||||
/*
|
||||
* Select which serial port is accessed by \Rserrx and \Rsertx.
|
||||
*/
|
||||
#define DMI_SERCS_SERIAL_OFFSET 24
|
||||
#define DMI_SERCS_SERIAL_LENGTH 3
|
||||
#define DMI_SERCS_SERIAL (0x7U << DMI_SERCS_SERIAL_OFFSET)
|
||||
#define DMI_SERCS_ERROR7_OFFSET 23
|
||||
#define DMI_SERCS_ERROR7_LENGTH 1
|
||||
#define DMI_SERCS_ERROR7 (0x1U << DMI_SERCS_ERROR7_OFFSET)
|
||||
#define DMI_SERCS_VALID7_OFFSET 22
|
||||
#define DMI_SERCS_VALID7_LENGTH 1
|
||||
#define DMI_SERCS_VALID7 (0x1U << DMI_SERCS_VALID7_OFFSET)
|
||||
#define DMI_SERCS_FULL7_OFFSET 21
|
||||
#define DMI_SERCS_FULL7_LENGTH 1
|
||||
#define DMI_SERCS_FULL7 (0x1U << DMI_SERCS_FULL7_OFFSET)
|
||||
#define DMI_SERCS_ERROR6_OFFSET 20
|
||||
#define DMI_SERCS_ERROR6_LENGTH 1
|
||||
#define DMI_SERCS_ERROR6 (0x1U << DMI_SERCS_ERROR6_OFFSET)
|
||||
#define DMI_SERCS_VALID6_OFFSET 19
|
||||
#define DMI_SERCS_VALID6_LENGTH 1
|
||||
#define DMI_SERCS_VALID6 (0x1U << DMI_SERCS_VALID6_OFFSET)
|
||||
#define DMI_SERCS_FULL6_OFFSET 18
|
||||
#define DMI_SERCS_FULL6_LENGTH 1
|
||||
#define DMI_SERCS_FULL6 (0x1U << DMI_SERCS_FULL6_OFFSET)
|
||||
#define DMI_SERCS_ERROR5_OFFSET 17
|
||||
#define DMI_SERCS_ERROR5_LENGTH 1
|
||||
#define DMI_SERCS_ERROR5 (0x1U << DMI_SERCS_ERROR5_OFFSET)
|
||||
#define DMI_SERCS_VALID5_OFFSET 16
|
||||
#define DMI_SERCS_VALID5_LENGTH 1
|
||||
#define DMI_SERCS_VALID5 (0x1U << DMI_SERCS_VALID5_OFFSET)
|
||||
#define DMI_SERCS_FULL5_OFFSET 15
|
||||
#define DMI_SERCS_FULL5_LENGTH 1
|
||||
#define DMI_SERCS_FULL5 (0x1U << DMI_SERCS_FULL5_OFFSET)
|
||||
#define DMI_SERCS_ERROR4_OFFSET 14
|
||||
#define DMI_SERCS_ERROR4_LENGTH 1
|
||||
#define DMI_SERCS_ERROR4 (0x1U << DMI_SERCS_ERROR4_OFFSET)
|
||||
#define DMI_SERCS_VALID4_OFFSET 13
|
||||
#define DMI_SERCS_VALID4_LENGTH 1
|
||||
#define DMI_SERCS_VALID4 (0x1U << DMI_SERCS_VALID4_OFFSET)
|
||||
#define DMI_SERCS_FULL4_OFFSET 12
|
||||
#define DMI_SERCS_FULL4_LENGTH 1
|
||||
#define DMI_SERCS_FULL4 (0x1U << DMI_SERCS_FULL4_OFFSET)
|
||||
#define DMI_SERCS_ERROR3_OFFSET 11
|
||||
#define DMI_SERCS_ERROR3_LENGTH 1
|
||||
#define DMI_SERCS_ERROR3 (0x1U << DMI_SERCS_ERROR3_OFFSET)
|
||||
#define DMI_SERCS_VALID3_OFFSET 10
|
||||
#define DMI_SERCS_VALID3_LENGTH 1
|
||||
#define DMI_SERCS_VALID3 (0x1U << DMI_SERCS_VALID3_OFFSET)
|
||||
#define DMI_SERCS_FULL3_OFFSET 9
|
||||
#define DMI_SERCS_FULL3_LENGTH 1
|
||||
#define DMI_SERCS_FULL3 (0x1U << DMI_SERCS_FULL3_OFFSET)
|
||||
#define DMI_SERCS_ERROR2_OFFSET 8
|
||||
#define DMI_SERCS_ERROR2_LENGTH 1
|
||||
#define DMI_SERCS_ERROR2 (0x1U << DMI_SERCS_ERROR2_OFFSET)
|
||||
#define DMI_SERCS_VALID2_OFFSET 7
|
||||
#define DMI_SERCS_VALID2_LENGTH 1
|
||||
#define DMI_SERCS_VALID2 (0x1U << DMI_SERCS_VALID2_OFFSET)
|
||||
#define DMI_SERCS_FULL2_OFFSET 6
|
||||
#define DMI_SERCS_FULL2_LENGTH 1
|
||||
#define DMI_SERCS_FULL2 (0x1U << DMI_SERCS_FULL2_OFFSET)
|
||||
#define DMI_SERCS_ERROR1_OFFSET 5
|
||||
#define DMI_SERCS_ERROR1_LENGTH 1
|
||||
#define DMI_SERCS_ERROR1 (0x1U << DMI_SERCS_ERROR1_OFFSET)
|
||||
#define DMI_SERCS_VALID1_OFFSET 4
|
||||
#define DMI_SERCS_VALID1_LENGTH 1
|
||||
#define DMI_SERCS_VALID1 (0x1U << DMI_SERCS_VALID1_OFFSET)
|
||||
#define DMI_SERCS_FULL1_OFFSET 3
|
||||
#define DMI_SERCS_FULL1_LENGTH 1
|
||||
#define DMI_SERCS_FULL1 (0x1U << DMI_SERCS_FULL1_OFFSET)
|
||||
/*
|
||||
* 1 when the debugger-to-core queue for serial port 0 has
|
||||
* over or underflowed. This bit will remain set until it is reset by
|
||||
* writing 1 to this bit.
|
||||
*/
|
||||
#define DMI_SERCS_ERROR0_OFFSET 2
|
||||
#define DMI_SERCS_ERROR0_LENGTH 1
|
||||
#define DMI_SERCS_ERROR0 (0x1U << DMI_SERCS_ERROR0_OFFSET)
|
||||
/*
|
||||
* 1 when the core-to-debugger queue for serial port 0 is not empty.
|
||||
*/
|
||||
#define DMI_SERCS_VALID0_OFFSET 1
|
||||
#define DMI_SERCS_VALID0_LENGTH 1
|
||||
#define DMI_SERCS_VALID0 (0x1U << DMI_SERCS_VALID0_OFFSET)
|
||||
/*
|
||||
* 1 when the debugger-to-core queue for serial port 0 is full.
|
||||
*/
|
||||
#define DMI_SERCS_FULL0_OFFSET 0
|
||||
#define DMI_SERCS_FULL0_LENGTH 1
|
||||
#define DMI_SERCS_FULL0 (0x1U << DMI_SERCS_FULL0_OFFSET)
|
||||
#define DMI_SERTX 0x35
|
||||
#define DMI_SERTX_DATA_OFFSET 0
|
||||
#define DMI_SERTX_DATA_LENGTH 32
|
||||
#define DMI_SERTX_DATA (0xffffffffU << DMI_SERTX_DATA_OFFSET)
|
||||
#define DMI_SERRX 0x36
|
||||
#define DMI_SERRX_DATA_OFFSET 0
|
||||
#define DMI_SERRX_DATA_LENGTH 32
|
||||
#define DMI_SERRX_DATA (0xffffffffU << DMI_SERRX_DATA_OFFSET)
|
||||
|
||||
+13
-11
@@ -1,4 +1,4 @@
|
||||
// See LICENSE for license details.
|
||||
/* See LICENSE for license details. */
|
||||
|
||||
#ifndef RISCV_CSR_ENCODING_H
|
||||
#define RISCV_CSR_ENCODING_H
|
||||
@@ -156,16 +156,16 @@
|
||||
#define EXT_IO_BASE 0x40000000
|
||||
#define DRAM_BASE 0x80000000
|
||||
|
||||
// page table entry (PTE) fields
|
||||
#define PTE_V 0x001 // Valid
|
||||
#define PTE_R 0x002 // Read
|
||||
#define PTE_W 0x004 // Write
|
||||
#define PTE_X 0x008 // Execute
|
||||
#define PTE_U 0x010 // User
|
||||
#define PTE_G 0x020 // Global
|
||||
#define PTE_A 0x040 // Accessed
|
||||
#define PTE_D 0x080 // Dirty
|
||||
#define PTE_SOFT 0x300 // Reserved for Software
|
||||
/* page table entry (PTE) fields */
|
||||
#define PTE_V 0x001 /* Valid */
|
||||
#define PTE_R 0x002 /* Read */
|
||||
#define PTE_W 0x004 /* Write */
|
||||
#define PTE_X 0x008 /* Execute */
|
||||
#define PTE_U 0x010 /* User */
|
||||
#define PTE_G 0x020 /* Global */
|
||||
#define PTE_A 0x040 /* Accessed */
|
||||
#define PTE_D 0x080 /* Dirty */
|
||||
#define PTE_SOFT 0x300 /* Reserved for Software */
|
||||
|
||||
#define PTE_PPN_SHIFT 10
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
/*
|
||||
#define read_csr(reg) ({ unsigned long __tmp; \
|
||||
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
|
||||
__tmp; })
|
||||
@@ -209,6 +210,7 @@
|
||||
#define clear_csr(reg, bit) ({ unsigned long __tmp; \
|
||||
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
|
||||
__tmp; })
|
||||
*/
|
||||
|
||||
#define rdtime() read_csr(time)
|
||||
#define rdcycle() read_csr(cycle)
|
||||
|
||||
@@ -240,6 +240,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot)
|
||||
case SLOT1: return 5;
|
||||
case SLOT_LAST: return info->dramsize-1;
|
||||
}
|
||||
break;
|
||||
case 64:
|
||||
switch (slot) {
|
||||
case SLOT0: return 4;
|
||||
@@ -455,12 +456,12 @@ static uint64_t dbus_read(struct target *target, uint16_t address)
|
||||
uint64_t value;
|
||||
dbus_status_t status;
|
||||
uint16_t address_in;
|
||||
|
||||
|
||||
/* If the previous read/write was to the same address, we will get the read data
|
||||
* from the previous access.
|
||||
* While somewhat nonintuitive, this is an efficient way to get the data.
|
||||
*/
|
||||
|
||||
|
||||
unsigned i = 0;
|
||||
do {
|
||||
status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0);
|
||||
@@ -680,7 +681,7 @@ static bits_t read_bits(struct target *target)
|
||||
}
|
||||
increase_dbus_busy_delay(target);
|
||||
} else if (status == DBUS_STATUS_FAILED) {
|
||||
// TODO: return an actual error
|
||||
/* TODO: return an actual error */
|
||||
return err_result;
|
||||
}
|
||||
} while (status == DBUS_STATUS_BUSY && i++ < 256);
|
||||
@@ -1407,12 +1408,6 @@ static int strict_step(struct target *target, bool announce)
|
||||
|
||||
LOG_DEBUG("enter");
|
||||
|
||||
struct breakpoint *breakpoint = target->breakpoints;
|
||||
while (breakpoint) {
|
||||
riscv_remove_breakpoint(target, breakpoint);
|
||||
breakpoint = breakpoint->next;
|
||||
}
|
||||
|
||||
struct watchpoint *watchpoint = target->watchpoints;
|
||||
while (watchpoint) {
|
||||
riscv_remove_watchpoint(target, watchpoint);
|
||||
@@ -1423,12 +1418,6 @@ static int strict_step(struct target *target, bool announce)
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
breakpoint = target->breakpoints;
|
||||
while (breakpoint) {
|
||||
riscv_add_breakpoint(target, breakpoint);
|
||||
breakpoint = breakpoint->next;
|
||||
}
|
||||
|
||||
watchpoint = target->watchpoints;
|
||||
while (watchpoint) {
|
||||
riscv_add_watchpoint(target, watchpoint);
|
||||
@@ -1572,11 +1561,11 @@ static int examine(struct target *target)
|
||||
}
|
||||
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
|
||||
|
||||
if (read_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
|
||||
if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
|
||||
const unsigned old_csr_misa = 0xf10;
|
||||
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
|
||||
old_csr_misa);
|
||||
if (read_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
|
||||
if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
|
||||
/* Maybe this is an old core that still has $misa at the old
|
||||
* address. */
|
||||
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
|
||||
@@ -1598,7 +1587,7 @@ static int examine(struct target *target)
|
||||
for (size_t i = 0; i < 32; ++i)
|
||||
reg_cache_set(target, i, -1);
|
||||
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
|
||||
riscv_xlen(target), r->misa);
|
||||
riscv_xlen(target), r->misa[0]);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1787,6 +1776,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
LOG_ERROR("Got invalid register result %d", result);
|
||||
goto error;
|
||||
}
|
||||
if (riscv_xlen(target) == 32) {
|
||||
reg_cache_set(target, reg, data & 0xffffffff);
|
||||
@@ -1847,7 +1838,7 @@ static int handle_halt(struct target *target, bool announce)
|
||||
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||
break;
|
||||
case DCSR_CAUSE_HWBP:
|
||||
target->debug_reason = DBG_REASON_WPTANDBKPT;
|
||||
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||
/* If we halted because of a data trigger, gdb doesn't know to do
|
||||
* the disable-breakpoints-step-enable-breakpoints dance. */
|
||||
info->need_strict_step = true;
|
||||
@@ -1873,6 +1864,12 @@ static int handle_halt(struct target *target, bool announce)
|
||||
riscv_enumerate_triggers(target);
|
||||
}
|
||||
|
||||
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||
int retval;
|
||||
if (riscv_semihosting(target, &retval) != 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (announce)
|
||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
|
||||
|
||||
+338
-219
File diff suppressed because it is too large
Load Diff
+453
-142
File diff suppressed because it is too large
Load Diff
+21
-11
@@ -7,7 +7,7 @@ struct riscv_program;
|
||||
#include "opcodes.h"
|
||||
#include "gdb_regs.h"
|
||||
|
||||
/* The register cache is staticly allocated. */
|
||||
/* The register cache is statically allocated. */
|
||||
#define RISCV_MAX_HARTS 32
|
||||
#define RISCV_MAX_REGISTERS 5000
|
||||
#define RISCV_MAX_TRIGGERS 32
|
||||
@@ -31,13 +31,17 @@ enum riscv_halt_reason {
|
||||
RISCV_HALT_BREAKPOINT,
|
||||
RISCV_HALT_SINGLESTEP,
|
||||
RISCV_HALT_TRIGGER,
|
||||
RISCV_HALT_UNKNOWN
|
||||
RISCV_HALT_UNKNOWN,
|
||||
RISCV_HALT_ERROR
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned dtm_version;
|
||||
struct target *target;
|
||||
unsigned custom_number;
|
||||
} riscv_reg_info_t;
|
||||
|
||||
riscv_reg_t misa;
|
||||
typedef struct {
|
||||
unsigned dtm_version;
|
||||
|
||||
struct command_context *cmd_ctx;
|
||||
void *version_specific;
|
||||
@@ -59,7 +63,9 @@ typedef struct {
|
||||
uint64_t saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
||||
bool valid_saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
||||
|
||||
/* The register cache points into here. */
|
||||
/* OpenOCD's register cache points into here. This is not per-hart because
|
||||
* we just invalidate the entire cache when we change which hart is
|
||||
* selected. */
|
||||
uint64_t reg_cache_values[RISCV_MAX_REGISTERS];
|
||||
|
||||
/* Single buffer that contains all register names, instead of calling
|
||||
@@ -68,6 +74,7 @@ typedef struct {
|
||||
|
||||
/* It's possible that each core has a different supported ISA set. */
|
||||
int xlen[RISCV_MAX_HARTS];
|
||||
riscv_reg_t misa[RISCV_MAX_HARTS];
|
||||
|
||||
/* The number of triggers per hart. */
|
||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
||||
@@ -87,13 +94,15 @@ typedef struct {
|
||||
/* This hart contains an implicit ebreak at the end of the program buffer. */
|
||||
bool impebreak;
|
||||
|
||||
bool triggers_enumerated;
|
||||
|
||||
/* Helper functions that target the various RISC-V debug spec
|
||||
* implementations. */
|
||||
int (*get_register)(struct target *target,
|
||||
riscv_reg_t *value, int hid, int rid);
|
||||
int (*set_register)(struct target *, int hartid, int regid,
|
||||
uint64_t value);
|
||||
void (*select_current_hart)(struct target *);
|
||||
int (*select_current_hart)(struct target *);
|
||||
bool (*is_halted)(struct target *target);
|
||||
int (*halt_current_hart)(struct target *);
|
||||
int (*resume_current_hart)(struct target *target);
|
||||
@@ -128,9 +137,6 @@ extern int riscv_command_timeout_sec;
|
||||
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
||||
extern int riscv_reset_timeout_sec;
|
||||
|
||||
extern bool riscv_use_scratch_ram;
|
||||
extern uint64_t riscv_scratch_ram_address;
|
||||
|
||||
extern bool riscv_prefer_sba;
|
||||
|
||||
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
||||
@@ -187,7 +193,7 @@ int riscv_resume_one_hart(struct target *target, int hartid);
|
||||
* then the only hart. */
|
||||
int riscv_step_rtos_hart(struct target *target);
|
||||
|
||||
bool riscv_supports_extension(struct target *target, char letter);
|
||||
bool riscv_supports_extension(struct target *target, int hartid, char letter);
|
||||
|
||||
/* Returns XLEN for the given (or current) hart. */
|
||||
int riscv_xlen(const struct target *target);
|
||||
@@ -197,7 +203,7 @@ bool riscv_rtos_enabled(const struct target *target);
|
||||
|
||||
/* Sets the current hart, which is the hart that will actually be used when
|
||||
* issuing debug commands. */
|
||||
void riscv_set_current_hartid(struct target *target, int hartid);
|
||||
int riscv_set_current_hartid(struct target *target, int hartid);
|
||||
int riscv_current_hartid(const struct target *target);
|
||||
|
||||
/*** Support functions for the RISC-V 'RTOS', which provides multihart support
|
||||
@@ -256,7 +262,11 @@ int riscv_remove_breakpoint(struct target *target,
|
||||
int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint);
|
||||
int riscv_remove_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint);
|
||||
int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_wp_address);
|
||||
|
||||
int riscv_init_registers(struct target *target);
|
||||
|
||||
void riscv_semihosting_init(struct target *target);
|
||||
int riscv_semihosting(struct target *target, int *retval);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* ilg@livius.net *
|
||||
* *
|
||||
* Copyright (C) 2009 by Marvell Technology Group Ltd. *
|
||||
* Written by Nicolas Pitre <nico@marvell.com> *
|
||||
* *
|
||||
* Copyright (C) 2010 by Spencer Oliver *
|
||||
* spen@spen-soft.co.uk *
|
||||
* *
|
||||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hold RISC-V semihosting support.
|
||||
*
|
||||
* The RISC-V code is inspired from ARM semihosting.
|
||||
*
|
||||
* Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf
|
||||
* from ARM Ltd.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include "target/target.h"
|
||||
#include "target/semihosting_common.h"
|
||||
#include "riscv.h"
|
||||
|
||||
static int riscv_semihosting_setup(struct target *target, int enable);
|
||||
static int riscv_semihosting_post_result(struct target *target);
|
||||
|
||||
/**
|
||||
* Initialize RISC-V semihosting. Use common ARM code.
|
||||
*/
|
||||
void riscv_semihosting_init(struct target *target)
|
||||
{
|
||||
semihosting_common_init(target, riscv_semihosting_setup,
|
||||
riscv_semihosting_post_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and process a semihosting request using the ARM protocol). This
|
||||
* is meant to be called when the target is stopped due to a debug mode entry.
|
||||
* If the value 0 is returned then there was nothing to process. A non-zero
|
||||
* return value signifies that a request was processed and the target resumed,
|
||||
* or an error was encountered, in which case the caller must return
|
||||
* immediately.
|
||||
*
|
||||
* @param target Pointer to the target to process.
|
||||
* @param retval Pointer to a location where the return code will be stored
|
||||
* @return non-zero value if a request was processed or an error encountered
|
||||
*/
|
||||
int riscv_semihosting(struct target *target, int *retval)
|
||||
{
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
if (!semihosting)
|
||||
return 0;
|
||||
|
||||
if (!semihosting->is_active)
|
||||
return 0;
|
||||
|
||||
riscv_reg_t dpc;
|
||||
int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC);
|
||||
if (result != ERROR_OK)
|
||||
return 0;
|
||||
|
||||
uint8_t tmp[12];
|
||||
|
||||
/* Read the current instruction, including the bracketing */
|
||||
*retval = target_read_memory(target, dpc - 4, 2, 6, tmp);
|
||||
if (*retval != ERROR_OK)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The instructions that trigger a semihosting call,
|
||||
* always uncompressed, should look like:
|
||||
*
|
||||
* 01f01013 slli zero,zero,0x1f
|
||||
* 00100073 ebreak
|
||||
* 40705013 srai zero,zero,0x7
|
||||
*/
|
||||
uint32_t pre = target_buffer_get_u32(target, tmp);
|
||||
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
||||
uint32_t post = target_buffer_get_u32(target, tmp + 8);
|
||||
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc);
|
||||
|
||||
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
|
||||
|
||||
/* Not the magic sequence defining semihosting. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform semihosting call if we are not waiting on a fileio
|
||||
* operation to complete.
|
||||
*/
|
||||
if (!semihosting->hit_fileio) {
|
||||
|
||||
/* RISC-V uses A0 and A1 to pass function arguments */
|
||||
riscv_reg_t r0;
|
||||
riscv_reg_t r1;
|
||||
|
||||
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
|
||||
if (result != ERROR_OK)
|
||||
return 0;
|
||||
|
||||
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
|
||||
if (result != ERROR_OK)
|
||||
return 0;
|
||||
|
||||
semihosting->op = r0;
|
||||
semihosting->param = r1;
|
||||
semihosting->word_size_bytes = riscv_xlen(target) / 8;
|
||||
|
||||
/* Check for ARM operation numbers. */
|
||||
if (0 <= semihosting->op && semihosting->op <= 0x31) {
|
||||
*retval = semihosting_common(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Unknown operation number, not a semihosting call. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume target if we are not waiting on a fileio
|
||||
* operation to complete.
|
||||
*/
|
||||
if (semihosting->is_resumable && !semihosting->hit_fileio) {
|
||||
/* Resume right after the EBREAK 4 bytes instruction. */
|
||||
*retval = target_resume(target, 0, dpc+4, 0, 0);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to resume target");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Local functions. */
|
||||
|
||||
/**
|
||||
* Called via semihosting->setup() later, after the target is known,
|
||||
* usually on the first semihosting command.
|
||||
*/
|
||||
static int riscv_semihosting_setup(struct target *target, int enable)
|
||||
{
|
||||
LOG_DEBUG("enable=%d", enable);
|
||||
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
if (semihosting)
|
||||
semihosting->setup_time = clock();
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int riscv_semihosting_post_result(struct target *target)
|
||||
{
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
if (!semihosting) {
|
||||
/* If not enabled, silently ignored. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DEBUG("0x%" PRIx64, semihosting->result);
|
||||
riscv_set_register(target, GDB_REGNO_A0, semihosting->result);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* Copyright (C) 2009 by Marvell Technology Group Ltd. *
|
||||
* Written by Nicolas Pitre <nico@marvell.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H
|
||||
#define OPENOCD_TARGET_SEMIHOSTING_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* According to:
|
||||
* "Semihosting for AArch32 and AArch64, Release 2.0"
|
||||
* https://static.docs.arm.com/100863/0200/semihosting.pdf
|
||||
* from ARM Ltd.
|
||||
*
|
||||
* The available semihosting operation numbers passed in R0 are allocated
|
||||
* as follows:
|
||||
* - 0x00-0x31 Used by ARM.
|
||||
* - 0x32-0xFF Reserved for future use by ARM.
|
||||
* - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
|
||||
* However, if you are writing your own SVC operations, you are advised
|
||||
* to use a different SVC number rather than using the semihosted
|
||||
* SVC number and these operation type numbers.
|
||||
* - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
|
||||
* that you do not use these.
|
||||
*/
|
||||
|
||||
enum semihosting_operation_numbers {
|
||||
/*
|
||||
* ARM semihosting operations, in lexicographic order.
|
||||
*/
|
||||
SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */
|
||||
|
||||
SEMIHOSTING_SYS_CLOSE = 0x02,
|
||||
SEMIHOSTING_SYS_CLOCK = 0x10,
|
||||
SEMIHOSTING_SYS_ELAPSED = 0x30,
|
||||
SEMIHOSTING_SYS_ERRNO = 0x13,
|
||||
SEMIHOSTING_SYS_EXIT = 0x18,
|
||||
SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20,
|
||||
SEMIHOSTING_SYS_FLEN = 0x0C,
|
||||
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
|
||||
SEMIHOSTING_SYS_HEAPINFO = 0x16,
|
||||
SEMIHOSTING_SYS_ISERROR = 0x08,
|
||||
SEMIHOSTING_SYS_ISTTY = 0x09,
|
||||
SEMIHOSTING_SYS_OPEN = 0x01,
|
||||
SEMIHOSTING_SYS_READ = 0x06,
|
||||
SEMIHOSTING_SYS_READC = 0x07,
|
||||
SEMIHOSTING_SYS_REMOVE = 0x0E,
|
||||
SEMIHOSTING_SYS_RENAME = 0x0F,
|
||||
SEMIHOSTING_SYS_SEEK = 0x0A,
|
||||
SEMIHOSTING_SYS_SYSTEM = 0x12,
|
||||
SEMIHOSTING_SYS_TICKFREQ = 0x31,
|
||||
SEMIHOSTING_SYS_TIME = 0x11,
|
||||
SEMIHOSTING_SYS_TMPNAM = 0x0D,
|
||||
SEMIHOSTING_SYS_WRITE = 0x05,
|
||||
SEMIHOSTING_SYS_WRITEC = 0x03,
|
||||
SEMIHOSTING_SYS_WRITE0 = 0x04,
|
||||
};
|
||||
|
||||
/*
|
||||
* Codes used by SEMIHOSTING_SYS_EXIT (formerly
|
||||
* SEMIHOSTING_REPORT_EXCEPTION).
|
||||
* On 64-bits, the exit code is passed explicitly.
|
||||
*/
|
||||
enum semihosting_reported_exceptions {
|
||||
/* On 32 bits, use it for exit(0) */
|
||||
ADP_STOPPED_APPLICATION_EXIT = ((2 << 16) + 38),
|
||||
/* On 32 bits, use it for exit(1) */
|
||||
ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35),
|
||||
};
|
||||
|
||||
struct target;
|
||||
|
||||
/*
|
||||
* A pointer to this structure was added to the target structure.
|
||||
*/
|
||||
struct semihosting {
|
||||
|
||||
/** A flag reporting whether semihosting is active. */
|
||||
bool is_active;
|
||||
|
||||
/** A flag reporting whether semihosting fileio is active. */
|
||||
bool is_fileio;
|
||||
|
||||
/** A flag reporting whether semihosting fileio operation is active. */
|
||||
bool hit_fileio;
|
||||
|
||||
/** Most are resumable, except the two exit calls. */
|
||||
bool is_resumable;
|
||||
|
||||
/**
|
||||
* When SEMIHOSTING_SYS_EXIT is called outside a debug session,
|
||||
* things are simple, the openocd process calls exit() and passes
|
||||
* the value returned by the target.
|
||||
* When SEMIHOSTING_SYS_EXIT is called during a debug session,
|
||||
* by default execution returns to the debugger, leaving the
|
||||
* debugger in a HALT state, similar to the state entered when
|
||||
* encountering a break.
|
||||
* In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT
|
||||
* return normally, as any semihosting call, and do not break
|
||||
* to the debugger.
|
||||
* The standard allows this to happen, but the condition
|
||||
* to trigger it is a bit obscure ("by performing an RDI_Execute
|
||||
* request or equivalent").
|
||||
*
|
||||
* To make the SEMIHOSTING_SYS_EXIT call return normally, enable
|
||||
* this variable via the dedicated command (default: disabled).
|
||||
*/
|
||||
bool has_resumable_exit;
|
||||
|
||||
/** The Target (hart) word size; 8 for 64-bits targets. */
|
||||
size_t word_size_bytes;
|
||||
|
||||
/** The current semihosting operation (R0 on ARM). */
|
||||
int op;
|
||||
|
||||
/** The current semihosting parameter (R1 or ARM). */
|
||||
uint64_t param;
|
||||
|
||||
/**
|
||||
* The current semihosting result to be returned to the application.
|
||||
* Usually 0 for success, -1 for error,
|
||||
* but sometimes a useful value, even a pointer.
|
||||
*/
|
||||
int64_t result;
|
||||
|
||||
/** The value to be returned by semihosting SYS_ERRNO request. */
|
||||
int sys_errno;
|
||||
|
||||
/** The semihosting command line to be passed to the target. */
|
||||
char *cmdline;
|
||||
|
||||
/** The current time when 'execution starts' */
|
||||
clock_t setup_time;
|
||||
|
||||
int (*setup)(struct target *target, int enable);
|
||||
int (*post_result)(struct target *target);
|
||||
};
|
||||
|
||||
int semihosting_common_init(struct target *target, void *setup,
|
||||
void *post_result);
|
||||
int semihosting_common(struct target *target);
|
||||
|
||||
#endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */
|
||||
@@ -203,6 +203,7 @@ proc init_target_events {} {
|
||||
foreach t $targets {
|
||||
set_default_target_event $t gdb-flash-erase-start "reset init"
|
||||
set_default_target_event $t gdb-flash-write-end "reset halt"
|
||||
set_default_target_event $t gdb-attach "halt"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -477,7 +477,8 @@ static int stm8_examine_debug_reason(struct target *target)
|
||||
uint8_t csr1, csr2;
|
||||
|
||||
retval = stm8_read_dm_csrx(target, &csr1, &csr2);
|
||||
LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2);
|
||||
if (retval == ERROR_OK)
|
||||
LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2);
|
||||
|
||||
if ((target->debug_reason != DBG_REASON_DBGRQ)
|
||||
&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
|
||||
@@ -1749,7 +1750,7 @@ static int stm8_examine(struct target *target)
|
||||
|
||||
/** Checks whether a memory region is erased. */
|
||||
static int stm8_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[2];
|
||||
@@ -1777,10 +1778,10 @@ static int stm8_blank_check_memory(struct target *target,
|
||||
stm8_info.common_magic = STM8_COMMON_MAGIC;
|
||||
|
||||
init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT);
|
||||
buf_set_u32(mem_params[0].value, 0, 24, address);
|
||||
buf_set_u32(mem_params[0].value, 0, 24, blocks[0].address);
|
||||
|
||||
init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT);
|
||||
buf_set_u32(mem_params[1].value, 0, 24, count);
|
||||
buf_set_u32(mem_params[1].value, 0, 24, blocks[0].size);
|
||||
|
||||
init_reg_param(®_params[0], "a", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, erased_value);
|
||||
@@ -1794,7 +1795,7 @@ static int stm8_blank_check_memory(struct target *target,
|
||||
10000, &stm8_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = (*(reg_params[0].value) == 0xff);
|
||||
blocks[0].result = (*(reg_params[0].value) == 0xff);
|
||||
|
||||
destroy_mem_param(&mem_params[0]);
|
||||
destroy_mem_param(&mem_params[1]);
|
||||
@@ -1802,7 +1803,10 @@ static int stm8_blank_check_memory(struct target *target,
|
||||
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return retval;
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return 1; /* only one block has been checked */
|
||||
}
|
||||
|
||||
static int stm8_checksum_memory(struct target *target, target_addr_t address,
|
||||
|
||||
+139
-45
@@ -54,6 +54,7 @@
|
||||
#include "image.h"
|
||||
#include "rtos/rtos.h"
|
||||
#include "transport/transport.h"
|
||||
#include "arm_cti.h"
|
||||
|
||||
/* default halt wait timeout (ms) */
|
||||
#define DEFAULT_HALT_TIMEOUT 5000
|
||||
@@ -512,7 +513,9 @@ struct target *get_target_by_num(int num)
|
||||
|
||||
struct target *get_current_target(struct command_context *cmd_ctx)
|
||||
{
|
||||
struct target *target = get_target_by_num(cmd_ctx->current_target);
|
||||
struct target *target = cmd_ctx->current_target_override
|
||||
? cmd_ctx->current_target_override
|
||||
: cmd_ctx->current_target;
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("BUG: current_target out of bounds");
|
||||
@@ -810,8 +813,7 @@ done:
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a target-specific native code algorithm to the target,
|
||||
* executes and leaves it running.
|
||||
* Executes a target-specific native code algorithm and leaves it running.
|
||||
*
|
||||
* @param target used to run the algorithm
|
||||
* @param arch_info target-specific description of the algorithm.
|
||||
@@ -884,12 +886,45 @@ done:
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a target-specific native code algorithm in the target.
|
||||
* It differs from target_run_algorithm in that the algorithm is asynchronous.
|
||||
* Because of this it requires an compliant algorithm:
|
||||
* see contrib/loaders/flash/stm32f1x.S for example.
|
||||
* Streams data to a circular buffer on target intended for consumption by code
|
||||
* running asynchronously on target.
|
||||
*
|
||||
* This is intended for applications where target-specific native code runs
|
||||
* on the target, receives data from the circular buffer, does something with
|
||||
* it (most likely writing it to a flash memory), and advances the circular
|
||||
* buffer pointer.
|
||||
*
|
||||
* This assumes that the helper algorithm has already been loaded to the target,
|
||||
* but has not been started yet. Given memory and register parameters are passed
|
||||
* to the algorithm.
|
||||
*
|
||||
* The buffer is defined by (buffer_start, buffer_size) arguments and has the
|
||||
* following format:
|
||||
*
|
||||
* [buffer_start + 0, buffer_start + 4):
|
||||
* Write Pointer address (aka head). Written and updated by this
|
||||
* routine when new data is written to the circular buffer.
|
||||
* [buffer_start + 4, buffer_start + 8):
|
||||
* Read Pointer address (aka tail). Updated by code running on the
|
||||
* target after it consumes data.
|
||||
* [buffer_start + 8, buffer_start + buffer_size):
|
||||
* Circular buffer contents.
|
||||
*
|
||||
* See contrib/loaders/flash/stm32f1x.S for an example.
|
||||
*
|
||||
* @param target used to run the algorithm
|
||||
* @param buffer address on the host where data to be sent is located
|
||||
* @param count number of blocks to send
|
||||
* @param block_size size in bytes of each block
|
||||
* @param num_mem_params count of memory-based params to pass to algorithm
|
||||
* @param mem_params memory-based params to pass to algorithm
|
||||
* @param num_reg_params count of register-based params to pass to algorithm
|
||||
* @param reg_params memory-based params to pass to algorithm
|
||||
* @param buffer_start address on the target of the circular buffer structure
|
||||
* @param buffer_size size of the circular buffer structure
|
||||
* @param entry_point address on the target to execute to start the algorithm
|
||||
* @param exit_point address at which to set a breakpoint to catch the
|
||||
* end of the algorithm; can be 0 if target triggers a breakpoint itself
|
||||
*/
|
||||
|
||||
int target_run_flash_async_algorithm(struct target *target,
|
||||
@@ -1860,8 +1895,41 @@ static void target_destroy(struct target *target)
|
||||
if (target->type->deinit_target)
|
||||
target->type->deinit_target(target);
|
||||
|
||||
if (target->semihosting)
|
||||
free(target->semihosting);
|
||||
|
||||
jtag_unregister_event_callback(jtag_enable_callback, target);
|
||||
|
||||
struct target_event_action *teap = target->event_action;
|
||||
while (teap) {
|
||||
struct target_event_action *next = teap->next;
|
||||
Jim_DecrRefCount(teap->interp, teap->body);
|
||||
free(teap);
|
||||
teap = next;
|
||||
}
|
||||
|
||||
target_free_all_working_areas(target);
|
||||
/* Now we have none or only one working area marked as free */
|
||||
if (target->working_areas) {
|
||||
free(target->working_areas->backup);
|
||||
free(target->working_areas);
|
||||
}
|
||||
|
||||
/* release the targets SMP list */
|
||||
if (target->smp) {
|
||||
struct target_list *head = target->head;
|
||||
while (head != NULL) {
|
||||
struct target_list *pos = head->next;
|
||||
head->target->smp = 0;
|
||||
free(head);
|
||||
head = pos;
|
||||
}
|
||||
target->smp = 0;
|
||||
}
|
||||
|
||||
free(target->type);
|
||||
free(target->trace_info);
|
||||
free(target->fileio_info);
|
||||
free(target->cmd_name);
|
||||
free(target);
|
||||
}
|
||||
@@ -2188,21 +2256,19 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_
|
||||
return retval;
|
||||
}
|
||||
|
||||
int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank,
|
||||
int target_blank_check_memory(struct target *target,
|
||||
struct target_memory_check_block *blocks, int num_blocks,
|
||||
uint8_t erased_value)
|
||||
{
|
||||
int retval;
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (target->type->blank_check_memory == 0)
|
||||
if (target->type->blank_check_memory == NULL)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target->type->blank_check_memory(target, address, size, blank, erased_value);
|
||||
|
||||
return retval;
|
||||
return target->type->blank_check_memory(target, blocks, num_blocks, erased_value);
|
||||
}
|
||||
|
||||
int target_read_u64(struct target *target, target_addr_t address, uint64_t *value)
|
||||
@@ -2475,7 +2541,10 @@ static int find_target(struct command_context *cmd_ctx, const char *name)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
cmd_ctx->current_target = target->target_number;
|
||||
cmd_ctx->current_target = target;
|
||||
if (cmd_ctx->current_target_override)
|
||||
cmd_ctx->current_target_override = target;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -2503,7 +2572,7 @@ COMMAND_HANDLER(handle_targets_command)
|
||||
else
|
||||
state = "tap-disabled";
|
||||
|
||||
if (CMD_CTX->current_target == target->target_number)
|
||||
if (CMD_CTX->current_target == target)
|
||||
marker = '*';
|
||||
|
||||
/* keep columns lined up to match the headers above */
|
||||
@@ -2920,6 +2989,9 @@ COMMAND_HANDLER(handle_halt_command)
|
||||
LOG_DEBUG("-");
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
target->verbose_halt_msg = true;
|
||||
|
||||
int retval = target_halt(target);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
@@ -4074,8 +4146,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
|
||||
* argv[3] = memory address
|
||||
* argv[4] = count of times to read
|
||||
*/
|
||||
|
||||
if (argc < 4 || argc > 5) {
|
||||
Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]");
|
||||
Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
|
||||
return JIM_ERR;
|
||||
}
|
||||
varname = Jim_GetString(argv[0], &len);
|
||||
@@ -4424,17 +4497,28 @@ void target_handle_event(struct target *target, enum target_event e)
|
||||
|
||||
for (teap = target->event_action; teap != NULL; teap = teap->next) {
|
||||
if (teap->event == e) {
|
||||
LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
|
||||
LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s",
|
||||
target->target_number,
|
||||
target_name(target),
|
||||
target_type_name(target),
|
||||
e,
|
||||
Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
|
||||
Jim_GetString(teap->body, NULL));
|
||||
|
||||
/* Override current target by the target an event
|
||||
* is issued from (lot of scripts need it).
|
||||
* Return back to previous override as soon
|
||||
* as the handler processing is done */
|
||||
struct command_context *cmd_ctx = current_command_context(teap->interp);
|
||||
struct target *saved_target_override = cmd_ctx->current_target_override;
|
||||
cmd_ctx->current_target_override = target;
|
||||
|
||||
if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) {
|
||||
Jim_MakeErrorMessage(teap->interp);
|
||||
command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL));
|
||||
}
|
||||
|
||||
cmd_ctx->current_target_override = saved_target_override;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4464,7 +4548,6 @@ enum target_cfg_param {
|
||||
TCFG_COREID,
|
||||
TCFG_CHAIN_POSITION,
|
||||
TCFG_DBGBASE,
|
||||
TCFG_CTIBASE,
|
||||
TCFG_RTOS,
|
||||
TCFG_DEFER_EXAMINE,
|
||||
};
|
||||
@@ -4480,7 +4563,6 @@ static Jim_Nvp nvp_config_opts[] = {
|
||||
{ .name = "-coreid", .value = TCFG_COREID },
|
||||
{ .name = "-chain-position", .value = TCFG_CHAIN_POSITION },
|
||||
{ .name = "-dbgbase", .value = TCFG_DBGBASE },
|
||||
{ .name = "-ctibase", .value = TCFG_CTIBASE },
|
||||
{ .name = "-rtos", .value = TCFG_RTOS },
|
||||
{ .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE },
|
||||
{ .name = NULL, .value = -1 }
|
||||
@@ -4717,6 +4799,13 @@ no_params:
|
||||
if (goi->isconfigure) {
|
||||
Jim_Obj *o_t;
|
||||
struct jtag_tap *tap;
|
||||
|
||||
if (target->has_dap) {
|
||||
Jim_SetResultString(goi->interp,
|
||||
"target requires -dap parameter instead of -chain-position!", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
target_free_all_working_areas(target);
|
||||
e = Jim_GetOpt_Obj(goi, &o_t);
|
||||
if (e != JIM_OK)
|
||||
@@ -4724,8 +4813,8 @@ no_params:
|
||||
tap = jtag_tap_by_jim_obj(goi->interp, o_t);
|
||||
if (tap == NULL)
|
||||
return JIM_ERR;
|
||||
/* make this exactly 1 or 0 */
|
||||
target->tap = tap;
|
||||
target->tap_configured = true;
|
||||
} else {
|
||||
if (goi->argc != 0)
|
||||
goto no_params;
|
||||
@@ -4747,20 +4836,6 @@ no_params:
|
||||
Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase));
|
||||
/* loop for more */
|
||||
break;
|
||||
case TCFG_CTIBASE:
|
||||
if (goi->isconfigure) {
|
||||
e = Jim_GetOpt_Wide(goi, &w);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
target->ctibase = (uint32_t)w;
|
||||
target->ctibase_set = true;
|
||||
} else {
|
||||
if (goi->argc != 0)
|
||||
goto no_params;
|
||||
}
|
||||
Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->ctibase));
|
||||
/* loop for more */
|
||||
break;
|
||||
case TCFG_RTOS:
|
||||
/* RTOS */
|
||||
{
|
||||
@@ -5377,21 +5452,19 @@ static const struct command_registration target_instance_command_handlers[] = {
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_examine,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "arp_examine ['allow-defer']",
|
||||
.usage = "['allow-defer']",
|
||||
},
|
||||
{
|
||||
.name = "was_examined",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_was_examined,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "was_examined",
|
||||
},
|
||||
{
|
||||
.name = "examine_deferred",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_examine_deferred,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "examine_deferred",
|
||||
},
|
||||
{
|
||||
.name = "arp_halt_gdb",
|
||||
@@ -5512,7 +5585,7 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||
target = calloc(1, sizeof(struct target));
|
||||
/* set target number */
|
||||
target->target_number = new_target_number();
|
||||
cmd_ctx->current_target = target->target_number;
|
||||
cmd_ctx->current_target = target;
|
||||
|
||||
/* allocate memory for each unique target type */
|
||||
target->type = calloc(1, sizeof(struct target_type));
|
||||
@@ -5538,7 +5611,7 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||
target->next = NULL;
|
||||
target->arch_info = NULL;
|
||||
|
||||
target->display = 1;
|
||||
target->verbose_halt_msg = true;
|
||||
|
||||
target->halt_issued = false;
|
||||
|
||||
@@ -5557,9 +5630,21 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||
goi->isconfigure = 1;
|
||||
e = target_configure(goi, target);
|
||||
|
||||
if (target->tap == NULL) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1);
|
||||
e = JIM_ERR;
|
||||
if (e == JIM_OK) {
|
||||
if (target->has_dap) {
|
||||
if (!target->dap_configured) {
|
||||
Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1);
|
||||
e = JIM_ERR;
|
||||
}
|
||||
} else {
|
||||
if (!target->tap_configured) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1);
|
||||
e = JIM_ERR;
|
||||
}
|
||||
}
|
||||
/* tap must be set after target was configured */
|
||||
if (target->tap == NULL)
|
||||
e = JIM_ERR;
|
||||
}
|
||||
|
||||
if (e != JIM_OK) {
|
||||
@@ -5576,14 +5661,23 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
target->cmd_name = strdup(cp);
|
||||
|
||||
if (target->type->target_create) {
|
||||
e = (*(target->type->target_create))(target, goi->interp);
|
||||
if (e != ERROR_OK) {
|
||||
LOG_DEBUG("target_create failed");
|
||||
free(target->type);
|
||||
free(target->cmd_name);
|
||||
free(target);
|
||||
return JIM_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* create the target specific commands */
|
||||
if (target->type->commands) {
|
||||
e = register_commands(cmd_ctx, NULL, target->type->commands);
|
||||
if (ERROR_OK != e)
|
||||
LOG_ERROR("unable to register '%s' commands", cp);
|
||||
}
|
||||
if (target->type->target_create)
|
||||
(*(target->type->target_create))(target, goi->interp);
|
||||
|
||||
/* append to end of list */
|
||||
{
|
||||
@@ -6337,7 +6431,7 @@ static const struct command_registration target_exec_command_handlers[] = {
|
||||
.handler = handle_bp_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "list or set hardware or software breakpoint",
|
||||
.usage = "<address> [<asid>]<length> ['hw'|'hw_ctx']",
|
||||
.usage = "<address> [<asid>] <length> ['hw'|'hw_ctx']",
|
||||
},
|
||||
{
|
||||
.name = "rbp",
|
||||
|
||||
+21
-18
@@ -153,7 +153,7 @@ struct target {
|
||||
struct target_event_action *event_action;
|
||||
|
||||
int reset_halt; /* attempt resetting the CPU into the halted mode? */
|
||||
uint32_t working_area; /* working area (initialised RAM). Evaluated
|
||||
target_addr_t working_area; /* working area (initialised RAM). Evaluated
|
||||
* upon first allocation from virtual/physical address. */
|
||||
bool working_area_virt_spec; /* virtual address specified? */
|
||||
target_addr_t working_area_virt; /* virtual address */
|
||||
@@ -176,20 +176,21 @@ struct target {
|
||||
void *private_config; /* pointer to target specific config data (for jim_configure hook) */
|
||||
struct target *next; /* next target in list */
|
||||
|
||||
int display; /* display async info in telnet session. Do not display
|
||||
bool verbose_halt_msg; /* display async info in telnet session. Do not display
|
||||
* lots of halted/resumed info when stepping in debugger. */
|
||||
bool halt_issued; /* did we transition to halted state? */
|
||||
int64_t halt_issued_time; /* Note time when halt was issued */
|
||||
|
||||
/* ARM v7/v8 targets with ADIv5 interface */
|
||||
bool dbgbase_set; /* By default the debug base is not set */
|
||||
uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no
|
||||
* system in place to support target specific options
|
||||
* currently. */
|
||||
bool has_dap; /* set to true if target has ADIv5 support */
|
||||
bool dap_configured; /* set to true if ADIv5 DAP is configured */
|
||||
bool tap_configured; /* set to true if JTAG tap has been configured
|
||||
* through -chain-position */
|
||||
|
||||
bool ctibase_set; /* By default the debug base is not set */
|
||||
uint32_t ctibase; /* Really a Cortex-A specific option, but there is no
|
||||
* system in place to support target specific options
|
||||
* currently. */
|
||||
struct rtos *rtos; /* Instance of Real Time Operating System support */
|
||||
bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto"
|
||||
* and must be detected when symbols are offered */
|
||||
@@ -205,13 +206,8 @@ struct target {
|
||||
/* file-I/O information for host to do syscall */
|
||||
struct gdb_fileio_info *fileio_info;
|
||||
|
||||
/**
|
||||
* When true, send gdb an error result when reading/writing a register
|
||||
* fails. This must be false for some ARM targets (Cortex-M3), where a 'g'
|
||||
* packet results in an attempt to read 'r0', which fails, which causes gdb
|
||||
* to close the connection.
|
||||
*/
|
||||
bool propagate_register_errors;
|
||||
/* The semihosting information, extracted from the target. */
|
||||
struct semihosting *semihosting;
|
||||
};
|
||||
|
||||
struct target_list {
|
||||
@@ -221,10 +217,10 @@ struct target_list {
|
||||
|
||||
struct gdb_fileio_info {
|
||||
char *identifier;
|
||||
uint32_t param_1;
|
||||
uint32_t param_2;
|
||||
uint32_t param_3;
|
||||
uint32_t param_4;
|
||||
uint64_t param_1;
|
||||
uint64_t param_2;
|
||||
uint64_t param_3;
|
||||
uint64_t param_4;
|
||||
};
|
||||
|
||||
/** Returns the instance-specific name of the specified target. */
|
||||
@@ -319,6 +315,12 @@ struct target_timer_callback {
|
||||
struct target_timer_callback *next;
|
||||
};
|
||||
|
||||
struct target_memory_check_block {
|
||||
target_addr_t address;
|
||||
uint32_t size;
|
||||
uint32_t result;
|
||||
};
|
||||
|
||||
int target_register_commands(struct command_context *cmd_ctx);
|
||||
int target_examine(void);
|
||||
|
||||
@@ -592,7 +594,8 @@ int target_read_buffer(struct target *target,
|
||||
int target_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t size, uint32_t *crc);
|
||||
int target_blank_check_memory(struct target *target,
|
||||
target_addr_t address, uint32_t size, uint32_t *blank, uint8_t erased_value);
|
||||
struct target_memory_check_block *blocks, int num_blocks,
|
||||
uint8_t erased_value);
|
||||
int target_wait_state(struct target *target, enum target_state state, int ms);
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,8 +130,9 @@ struct target_type {
|
||||
|
||||
int (*checksum_memory)(struct target *target, target_addr_t address,
|
||||
uint32_t count, uint32_t *checksum);
|
||||
int (*blank_check_memory)(struct target *target, target_addr_t address,
|
||||
uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
int (*blank_check_memory)(struct target *target,
|
||||
struct target_memory_check_block *blocks, int num_blocks,
|
||||
uint8_t erased_value);
|
||||
|
||||
/*
|
||||
* target break-/watchpoint control
|
||||
|
||||
Reference in New Issue
Block a user