+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2016 Chengyu Zheng *
* chengyu.zheng@polimi.it : watchpoint support *
* *
- * 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/>. *
- * *
* Cortex-A8(tm) TRM, ARM DDI 0344H *
* Cortex-A9(tm) TRM, ARM DDI 0407F *
* Cortex-A4(tm) TRM, ARM DDI 0363E *
#include "transport/transport.h"
#include "smp.h"
#include <helper/bits.h>
+#include <helper/nvp.h>
#include <helper/time_support.h>
static int cortex_a_poll(struct target *target);
return retval;
}
+static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm,
+ uint32_t opcode, uint64_t data)
+{
+ struct cortex_a_common *a = dpm_to_a(dpm);
+ uint32_t dscr = DSCR_INSTR_COMP;
+ int retval;
+
+ retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* then the opcode, taking data from R0, R1 */
+ retval = cortex_a_exec_opcode(a->armv7a_common.arm.target,
+ opcode,
+ &dscr);
+ return retval;
+}
+
static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm)
{
struct target *target = dpm->arm->target;
return cortex_a_instr_read_data_rt_dcc(dpm, 0, data);
}
+static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm,
+ uint32_t opcode, uint64_t *data)
+{
+ uint32_t lo, hi;
+ int retval;
+
+ /* the opcode, writing data to RO, R1 */
+ retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = lo;
+
+ /* write R1 to DCC */
+ retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data |= (uint64_t)hi << 32;
+
+ return retval;
+}
+
static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t,
uint32_t addr, uint32_t control)
{
dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc;
dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0;
+ dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1;
dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync;
dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc;
dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0;
+ dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1;
dpm->bpwp_enable = cortex_a_bpwp_enable;
dpm->bpwp_disable = cortex_a_bpwp_disable;
armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = true;
/* Make sure we are in Thumb mode */
- buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32,
- buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0,
+ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32,
+ buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0,
32) | (1 << 24));
- armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = true;
- armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = true;
+ armv7m->core_cache->reg_list[ARMV7M_XPSR].dirty = true;
+ armv7m->core_cache->reg_list[ARMV7M_XPSR].valid = true;
}
#endif
int retval;
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
}
/* registers are now invalid */
- if (target_was_examined(target))
+ if (armv7a->arm.core_cache)
register_cache_invalidate(armv7a->arm.core_cache);
target->state = TARGET_RESET;
LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32,
address, size, count);
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Switch to non-blocking mode if not already in that mode. */
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
/* Mark R0 as dirty. */
arm_reg_current(arm, 0)->dirty = true;
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
/* Get the memory address into R0. */
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DTRRX, address);
if (retval != ERROR_OK)
- goto out;
+ return retval;
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
if (size == 4 && (address % 4) == 0) {
/* We are doing a word-aligned transfer, so use fast mode. */
retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr);
}
-out:
final_retval = retval;
/* Switch to non-blocking mode if not already in that mode. */
LOG_DEBUG("Reading CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32,
address, size, count);
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Switch to non-blocking mode if not already in that mode. */
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
/* Mark R0 as dirty. */
arm_reg_current(arm, 0)->dirty = true;
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
/* Get the memory address into R0. */
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DTRRX, address);
if (retval != ERROR_OK)
- goto out;
+ return retval;
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
if (retval != ERROR_OK)
- goto out;
+ return retval;
if (size == 4 && (address % 4) == 0) {
/* We are doing a word-aligned transfer, so use fast mode. */
retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr);
}
-out:
final_retval = retval;
/* Switch to non-blocking mode if not already in that mode. */
int retval = ERROR_OK;
uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1;
- if (pc->ap_num == DP_APSEL_INVALID) {
- /* 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) {
- LOG_ERROR("Could not find APB-AP for debug access");
- return retval;
+ if (!armv7a->debug_ap) {
+ if (pc->ap_num == DP_APSEL_INVALID) {
+ /* Search for the APB-AP - it is needed for access to debug registers */
+ retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not find APB-AP for debug access");
+ return retval;
+ }
+ } else {
+ armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num);
+ if (!armv7a->debug_ap) {
+ LOG_ERROR("Cannot get AP");
+ return ERROR_FAIL;
+ }
}
- } else {
- armv7a->debug_ap = dap_ap(swjdp, pc->ap_num);
}
retval = mem_ap_init(armv7a->debug_ap);
armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg);
+ LOG_TARGET_DEBUG(target, "DBGPRSR 0x%" PRIx32, dbg_osreg);
if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) {
- LOG_ERROR("target->coreid %" PRId32 " powered down!", target->coreid);
+ LOG_TARGET_ERROR(target, "powered down!");
target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */
return ERROR_TARGET_INIT_FAILED;
}
if (dbg_osreg & PRSR_STICKY_RESET_STATUS)
- LOG_DEBUG("target->coreid %" PRId32 " was reset!", target->coreid);
+ LOG_TARGET_DEBUG(target, "was reset!");
/* Read DBGOSLSR and check if OSLK is implemented */
retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("target->coreid %" PRId32 " DBGOSLSR 0x%" PRIx32, target->coreid, dbg_osreg);
+ LOG_TARGET_DEBUG(target, "DBGOSLSR 0x%" PRIx32, dbg_osreg);
/* check if OS Lock is implemented */
if ((dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM0 || (dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM1) {
/* check if OS Lock is set */
if (dbg_osreg & OSLSR_OSLK) {
- LOG_DEBUG("target->coreid %" PRId32 " OSLock set! Trying to unlock", target->coreid);
+ LOG_TARGET_DEBUG(target, "OSLock set! Trying to unlock");
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_OSLAR,
/* if we fail to access the register or cannot reset the OSLK bit, bail out */
if (retval != ERROR_OK || (dbg_osreg & OSLSR_OSLK) != 0) {
- LOG_ERROR("target->coreid %" PRId32 " OSLock sticky, core not powered?",
- target->coreid);
+ LOG_TARGET_ERROR(target, "OSLock sticky, core not powered?");
target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */
return ERROR_TARGET_INIT_FAILED;
}
return retval;
if (dbg_idpfr1 & 0x000000f0) {
- LOG_DEBUG("target->coreid %" PRId32 " has security extensions",
- target->coreid);
+ LOG_TARGET_DEBUG(target, "has security extensions");
armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT;
}
if (dbg_idpfr1 & 0x0000f000) {
- LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions",
- target->coreid);
+ LOG_TARGET_DEBUG(target, "has virtualization extensions");
/*
* overwrite and simplify the checks.
* virtualization extensions require implementation of security extension
dscr & ~DSCR_HALT_DBG_MODE);
}
+ if (armv7a->debug_ap)
+ dap_put_ap(armv7a->debug_ap);
+
free(cortex_a->wrp_list);
free(cortex_a->brp_list);
arm_free_reg_cache(dpm->arm);
struct armv7a_common *armv7a = target_to_armv7a(target);
if (target->state != TARGET_HALTED) {
- LOG_ERROR("%s: target not halted", __func__);
- return ERROR_TARGET_INVALID;
+ LOG_TARGET_ERROR(target, "not halted");
+ return ERROR_TARGET_NOT_HALTED;
}
if (armv7a->is_armv7r)
struct target *target = get_current_target(CMD_CTX);
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
- static const struct jim_nvp nvp_maskisr_modes[] = {
+ static const struct nvp nvp_maskisr_modes[] = {
{ .name = "off", .value = CORTEX_A_ISRMASK_OFF },
{ .name = "on", .value = CORTEX_A_ISRMASK_ON },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]);
if (!n->name) {
LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
cortex_a->isrmasking_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode);
+ n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode);
command_print(CMD, "cortex_a interrupt mask %s", n->name);
return ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
- static const struct jim_nvp nvp_dacrfixup_modes[] = {
+ static const struct nvp nvp_dacrfixup_modes[] = {
{ .name = "off", .value = CORTEX_A_DACRFIXUP_OFF },
{ .name = "on", .value = CORTEX_A_DACRFIXUP_ON },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]);
if (!n->name)
return ERROR_COMMAND_SYNTAX_ERROR;
cortex_a->dacrfixup_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
+ n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
command_print(CMD, "cortex_a domain access control fixup %s", n->name);
return ERROR_OK;