openocd/src/target/arm720t.c
Andreas Fritiofson 5c2f920cc7 [RFC] target: Move bulk_write_memory to arm7_9
The only remaining user is arm7_9 so remove it from the target API and add
it to struct arm7_9_common to support all its variants with minimal
changes. Many of the variants are likely not correct in the cache/mmu
handling when the bulk write is triggered. This patch does nothing to
change that, except for arm946e, where it was easier to do what might be
the right thing.

Change-Id: Ie73ac07507ff0936fefdb90760046cc8810ed182
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1220
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2013-09-13 19:33:28 +00:00

590 lines
16 KiB
C

/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2009 by Øyvind Harboe *
* oyvind.harboe@zylin.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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm720t.h"
#include <helper/time_support.h>
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* ARM720 is an ARM7TDMI-S with MMU and ETM7. For information, see
* ARM DDI 0229C especially Chapter 9 about debug support.
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
static int arm720t_scan_cp15(struct target *target,
uint32_t out, uint32_t *in, int instruction, int clock_arg)
{
int retval;
struct arm720t_common *arm720t = target_to_arm720(target);
struct arm_jtag *jtag_info;
struct scan_field fields[2];
uint8_t out_buf[4];
uint8_t instruction_buf = instruction;
jtag_info = &arm720t->arm7_9_common.jtag_info;
buf_set_u32(out_buf, 0, 32, flip_u32(out, 32));
retval = arm_jtag_scann(jtag_info, 0xf, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 1;
fields[0].out_value = &instruction_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 32;
fields[1].out_value = out_buf;
fields[1].in_value = NULL;
if (in) {
fields[1].in_value = (uint8_t *)in;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
jtag_add_callback(arm7flip32, (jtag_callback_data_t)in);
} else
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
if (clock_arg)
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
else
LOG_DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock_arg);
#else
LOG_DEBUG("out: %8.8" PRIx32 ", instruction: %i, clock: %i", out, instruction, clock_arg);
#endif
return ERROR_OK;
}
static int arm720t_read_cp15(struct target *target, uint32_t opcode, uint32_t *value)
{
/* fetch CP15 opcode */
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
/* "DECODE" stage */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
/* "EXECUTE" stage (1) */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (2) */
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (3), CDATA is read */
arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1);
return ERROR_OK;
}
static int arm720t_write_cp15(struct target *target, uint32_t opcode, uint32_t value)
{
/* fetch CP15 opcode */
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
/* "DECODE" stage */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
/* "EXECUTE" stage (1) */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (2) */
arm720t_scan_cp15(target, value, NULL, 0, 1);
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
return ERROR_OK;
}
static int arm720t_get_ttb(struct target *target, uint32_t *result)
{
uint32_t ttb = 0x0;
int retval;
retval = arm720t_read_cp15(target, 0xee120f10, &ttb);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
ttb &= 0xffffc000;
*result = ttb;
return ERROR_OK;
}
static int arm720t_disable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache)
{
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu)
cp15_control &= ~0x1U;
if (d_u_cache || i_cache)
cp15_control &= ~0x4U;
retval = arm720t_write_cp15(target, 0xee010f10, cp15_control);
return retval;
}
static int arm720t_enable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache)
{
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu)
cp15_control |= 0x1U;
if (d_u_cache || i_cache)
cp15_control |= 0x4U;
retval = arm720t_write_cp15(target, 0xee010f10, cp15_control);
return retval;
}
static int arm720t_post_debug_entry(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
int retval;
/* examine cp15 control reg */
retval = arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg);
arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0;
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0;
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
/* save i/d fault status and address register */
retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg);
if (retval != ERROR_OK)
return retval;
retval = arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
return retval;
}
static void arm720t_pre_restore_context(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
/* restore i/d fault status and address register */
arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg);
arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg);
}
static int arm720t_verify_pointer(struct command_context *cmd_ctx,
struct arm720t_common *arm720t)
{
if (arm720t->common_magic != ARM720T_COMMON_MAGIC) {
command_print(cmd_ctx, "target is not an ARM720");
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
static int arm720t_arch_state(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
static const char *state[] = {
"disabled", "enabled"
};
arm_arch_state(target);
LOG_USER("MMU: %s, Cache: %s",
state[arm720t->armv4_5_mmu.mmu_enabled],
state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
return ERROR_OK;
}
static int arm720_mmu(struct target *target, int *enabled)
{
if (target->state != TARGET_HALTED) {
LOG_ERROR("%s: target not halted", __func__);
return ERROR_TARGET_INVALID;
}
*enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled;
return ERROR_OK;
}
static int arm720_virt2phys(struct target *target,
uint32_t virtual, uint32_t *physical)
{
uint32_t cb;
struct arm720t_common *arm720t = target_to_arm720(target);
uint32_t ret;
int retval = armv4_5_mmu_translate_va(target,
&arm720t->armv4_5_mmu, virtual, &cb, &ret);
if (retval != ERROR_OK)
return retval;
*physical = ret;
return ERROR_OK;
}
static int arm720t_read_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval;
struct arm720t_common *arm720t = target_to_arm720(target);
/* disable cache, but leave MMU enabled */
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) {
retval = arm720t_disable_mmu_caches(target, 0, 1, 0);
if (retval != ERROR_OK)
return retval;
}
retval = arm7_9_read_memory(target, address, size, count, buffer);
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) {
retval = arm720t_enable_mmu_caches(target, 0, 1, 0);
if (retval != ERROR_OK)
return retval;
}
return retval;
}
static int arm720t_read_phys_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
struct arm720t_common *arm720t = target_to_arm720(target);
return armv4_5_mmu_read_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer);
}
static int arm720t_write_phys_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
{
struct arm720t_common *arm720t = target_to_arm720(target);
return armv4_5_mmu_write_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer);
}
static int arm720t_soft_reset_halt(struct target *target)
{
int retval = ERROR_OK;
struct arm720t_common *arm720t = target_to_arm720(target);
struct reg *dbg_stat = &arm720t->arm7_9_common
.eice_cache->reg_list[EICE_DBG_STAT];
struct arm *arm = &arm720t->arm7_9_common.arm;
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
long long then = timeval_ms();
int timeout;
while (!(timeout = ((timeval_ms()-then) > 1000))) {
if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) {
embeddedice_read_reg(dbg_stat);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
} else
break;
if (debug_level >= 3)
alive_sleep(100);
else
keep_alive();
}
if (timeout) {
LOG_ERROR("Failed to halt CPU after 1 sec");
return ERROR_TARGET_TIMEOUT;
}
target->state = TARGET_HALTED;
/* SVC, ARM state, IRQ and FIQ disabled */
uint32_t cpsr;
cpsr = buf_get_u32(arm->cpsr->value, 0, 32);
cpsr &= ~0xff;
cpsr |= 0xd3;
arm_set_cpsr(arm, cpsr);
arm->cpsr->dirty = 1;
/* start fetching from 0x0 */
buf_set_u32(arm->pc->value, 0, 32, 0x0);
arm->pc->dirty = 1;
arm->pc->valid = 1;
retval = arm720t_disable_mmu_caches(target, 1, 1, 1);
if (retval != ERROR_OK)
return retval;
arm720t->armv4_5_mmu.mmu_enabled = 0;
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int arm720t_init_target(struct command_context *cmd_ctx, struct target *target)
{
return arm7tdmi_init_target(cmd_ctx, target);
}
/* FIXME remove forward decls */
static int arm720t_mrc(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t *value);
static int arm720t_mcr(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t value);
static int arm720t_init_arch_info(struct target *target,
struct arm720t_common *arm720t, struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm720t->arm7_9_common;
arm7_9->arm.mrc = arm720t_mrc;
arm7_9->arm.mcr = arm720t_mcr;
arm7tdmi_init_arch_info(target, arm7_9, tap);
arm720t->common_magic = ARM720T_COMMON_MAGIC;
arm7_9->post_debug_entry = arm720t_post_debug_entry;
arm7_9->pre_restore_context = arm720t_pre_restore_context;
arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1;
arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb;
arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory;
arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory;
arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches;
arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches;
arm720t->armv4_5_mmu.has_tiny_pages = 0;
arm720t->armv4_5_mmu.mmu_enabled = 0;
return ERROR_OK;
}
static int arm720t_target_create(struct target *target, Jim_Interp *interp)
{
struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t));
arm720t->arm7_9_common.arm.is_armv4 = true;
return arm720t_init_arch_info(target, arm720t, target->tap);
}
COMMAND_HANDLER(arm720t_handle_cp15_command)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm720t_common *arm720t = target_to_arm720(target);
retval = arm720t_verify_pointer(CMD_CTX, arm720t);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (CMD_ARGC >= 1) {
uint32_t opcode;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode);
if (CMD_ARGC == 1) {
uint32_t value;
retval = arm720t_read_cp15(target, opcode, &value);
if (retval != ERROR_OK) {
command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
return ERROR_OK;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
} else if (CMD_ARGC == 2) {
uint32_t value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
retval = arm720t_write_cp15(target, opcode, value);
if (retval != ERROR_OK) {
command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
return ERROR_OK;
}
command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
}
}
return ERROR_OK;
}
static int arm720t_mrc(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t *value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
/* read "to" r0 */
return arm720t_read_cp15(target,
ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2),
value);
}
static int arm720t_mcr(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
/* write "from" r0 */
return arm720t_write_cp15(target,
ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
value);
}
static const struct command_registration arm720t_exec_command_handlers[] = {
{
.name = "cp15",
.handler = arm720t_handle_cp15_command,
.mode = COMMAND_EXEC,
/* prefer using less error-prone "arm mcr" or "arm mrc" */
.help = "display/modify cp15 register using ARM opcode"
" (DEPRECATED)",
.usage = "instruction [value]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration arm720t_command_handlers[] = {
{
.chain = arm7_9_command_handlers,
},
{
.name = "arm720t",
.mode = COMMAND_ANY,
.help = "arm720t command group",
.usage = "",
.chain = arm720t_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM720 targets. */
struct target_type arm720t_target = {
.name = "arm720t",
.poll = arm7_9_poll,
.arch_state = arm720t_arch_state,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm720t_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm720t_read_memory,
.write_memory = arm7_9_write_memory_opt,
.read_phys_memory = arm720t_read_phys_memory,
.write_phys_memory = arm720t_write_phys_memory,
.mmu = arm720_mmu,
.virt2phys = arm720_virt2phys,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm720t_command_handlers,
.target_create = arm720t_target_create,
.init_target = arm720t_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};