- prepare OpenOCD for branching, created ./trunk/

git-svn-id: svn://svn.berlios.de/openocd/trunk@64 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
drath
2006-06-02 10:36:31 +00:00
commit 8b4e882a16
93 changed files with 25116 additions and 0 deletions

7
src/target/Makefile.am Normal file
View File

@@ -0,0 +1,7 @@
INCLUDES = -I$(top_srcdir)/src/gdb -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/xsvf $(all_includes)
METASOURCES = AUTO
noinst_LIBRARIES = libtarget.a
libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c
noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h

54
src/target/algorithm.c Normal file
View File

@@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "algorithm.h"
#include "log.h"
#include "configuration.h"
#include "binarybuffer.h"
#include <stdlib.h>
void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction)
{
param->address = address;
param->size = size;
param->value = malloc(size);
param->direction = direction;
}
void destroy_mem_param(mem_param_t *param)
{
free(param->value);
}
void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction)
{
param->reg_name = reg_name;
param->size = size;
param->value = malloc(CEIL(size, 8));
param->direction = direction;
}
void destroy_reg_param(reg_param_t *param)
{
free(param->value);
}

53
src/target/algorithm.h Normal file
View File

@@ -0,0 +1,53 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ALGORITHM_H
#define ALGORITHM_H
#include "types.h"
enum param_direction
{
PARAM_IN,
PARAM_OUT,
PARAM_IN_OUT
};
typedef struct mem_param_s
{
u32 address;
u32 size;
u8 *value;
enum param_direction direction;
} mem_param_t;
typedef struct reg_param_s
{
char *reg_name;
u32 size;
u8 *value;
enum param_direction direction;
} reg_param_t;
extern void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction);
extern void destroy_mem_param(mem_param_t *param);
extern void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction);
extern void destroy_reg_param(reg_param_t *param);
#endif /* ALGORITHM_H */

625
src/target/arm720t.c Normal file
View File

@@ -0,0 +1,625 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "arm720t.h"
#include "jtag.h"
#include "log.h"
#include <stdlib.h>
#include <string.h>
#if 1
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
/* cli handling */
int arm720t_register_commands(struct command_context_s *cmd_ctx);
int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
/* forward declarations */
int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
int arm720t_quit();
int arm720t_arch_state(struct target_s *target, char *buf, int buf_size);
int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm720t_soft_reset_halt(struct target_s *target);
target_type_t 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 = armv4_5_get_gdb_reg_list,
.read_memory = arm720t_read_memory,
.write_memory = arm720t_write_memory,
.bulk_write_memory = arm7_9_bulk_write_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,
.register_commands = arm720t_register_commands,
.target_command = arm720t_target_command,
.init_target = arm720t_init_target,
.quit = arm720t_quit
};
int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
scan_field_t fields[2];
u8 out_buf[4];
u8 instruction_buf = instruction;
out = flip_u32(out, 32);
buf_set_u32(out_buf, 0, 32, out);
jtag_add_end_state(TAP_PD);
arm_jtag_scann(jtag_info, 0xf);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &instruction_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = out_buf;
fields[1].out_mask = NULL;
if (in)
{
fields[1].in_value = (u8*)in;
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
fields[1].in_handler_priv = in;
} else
{
fields[1].in_value = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
}
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
jtag_add_dr_scan(2, fields, -1);
if (clock)
jtag_add_runtest(0, -1);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
jtag_execute_queue();
if (in)
DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
else
DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock);
#else
DEBUG("out: %8.8x, instruction: %i, clock: %i", in, out, instruction, clock);
#endif
return ERROR_OK;
}
int arm720t_read_cp15(target_t *target, u32 opcode, u32 *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;
}
int arm720t_write_cp15(target_t *target, u32 opcode, u32 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;
}
u32 arm720t_get_ttb(target_t *target)
{
u32 ttb = 0x0;
arm720t_read_cp15(target, 0xee120f10, &ttb);
jtag_execute_queue();
ttb &= 0xffffc000;
return ttb;
}
void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
{
u32 cp15_control;
/* read cp15 control register */
arm720t_read_cp15(target, 0xee110f10, &cp15_control);
jtag_execute_queue();
if (mmu)
cp15_control &= ~0x1U;
if (d_u_cache || i_cache)
cp15_control &= ~0x4U;
arm720t_write_cp15(target, 0xee010f10, cp15_control);
}
void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
{
u32 cp15_control;
/* read cp15 control register */
arm720t_read_cp15(target, 0xee110f10, &cp15_control);
jtag_execute_queue();
if (mmu)
cp15_control |= 0x1U;
if (d_u_cache || i_cache)
cp15_control |= 0x4U;
arm720t_write_cp15(target, 0xee010f10, cp15_control);
}
void arm720t_post_debug_entry(target_t *target)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
arm720t_common_t *arm720t = arm7tdmi->arch_info;
/* examine cp15 control reg */
arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
jtag_execute_queue();
DEBUG("cp15_control_reg: %8.8x", 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 */
arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr);
arm720t_read_cp15(target, 0xee160f10, &arm720t->far);
jtag_execute_queue();
}
void arm720t_pre_restore_context(target_t *target)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
arm720t_common_t *arm720t = arm7tdmi->arch_info;
/* restore i/d fault status and address register */
arm720t_write_cp15(target, 0xee050f10, arm720t->fsr);
arm720t_write_cp15(target, 0xee060f10, arm720t->far);
}
int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9;
arm7tdmi_common_t *arm7tdmi;
arm720t_common_t *arm720t;
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
return -1;
}
arm7_9 = armv4_5->arch_info;
if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
{
return -1;
}
arm7tdmi = arm7_9->arch_info;
if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC)
{
return -1;
}
arm720t = arm7tdmi->arch_info;
if (arm720t->common_magic != ARM720T_COMMON_MAGIC)
{
return -1;
}
*armv4_5_p = armv4_5;
*arm7_9_p = arm7_9;
*arm7tdmi_p = arm7tdmi;
*arm720t_p = arm720t;
return ERROR_OK;
}
int arm720t_arch_state(struct target_s *target, char *buf, int buf_size)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
arm720t_common_t *arm720t = arm7tdmi->arch_info;
char *state[] =
{
"disabled", "enabled"
};
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
ERROR("BUG: called for a non-ARMv4/5 target");
exit(-1);
}
snprintf(buf, buf_size,
"target halted in %s state due to %s, current mode: %s\n"
"cpsr: 0x%8.8x pc: 0x%8.8x\n"
"MMU: %s, Cache: %s",
armv4_5_state_strings[armv4_5->core_state],
target_debug_reason_strings[target->debug_reason],
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
state[arm720t->armv4_5_mmu.mmu_enabled],
state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
return ERROR_OK;
}
int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
arm720t_common_t *arm720t = arm7tdmi->arch_info;
/* disable cache, but leave MMU enabled */
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
arm720t_disable_mmu_caches(target, 0, 1, 0);
retval = arm7_9_read_memory(target, address, size, count, buffer);
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
arm720t_enable_mmu_caches(target, 0, 1, 0);
return retval;
}
int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
return retval;
return retval;
}
int arm720t_soft_reset_halt(struct target_s *target)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
arm720t_common_t *arm720t = arm7tdmi->arch_info;
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
if (target->state == TARGET_RUNNING)
{
target->type->halt(target);
}
while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
{
embeddedice_read_reg(dbg_stat);
jtag_execute_queue();
}
target->state = TARGET_HALTED;
/* SVC, ARM state, IRQ and FIQ disabled */
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
/* start fetching from 0x0 */
buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
armv4_5->core_cache->reg_list[15].dirty = 1;
armv4_5->core_cache->reg_list[15].valid = 1;
armv4_5->core_mode = ARMV4_5_MODE_SVC;
armv4_5->core_state = ARMV4_5_STATE_ARM;
arm720t_disable_mmu_caches(target, 1, 1, 1);
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;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
return ERROR_OK;
}
int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
arm7tdmi_init_target(cmd_ctx, target);
return ERROR_OK;
}
int arm720t_quit()
{
return ERROR_OK;
}
int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant)
{
arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common;
arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common;
arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
arm7tdmi->arch_info = arm720t;
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;
}
int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
{
int chain_pos;
char *variant = NULL;
arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t));
if (argc < 4)
{
ERROR("'target arm720t' requires at least one additional argument");
exit(-1);
}
chain_pos = strtoul(args[3], NULL, 0);
if (argc >= 5)
variant = strdup(args[4]);
DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
arm720t_init_arch_info(target, arm720t, chain_pos, variant);
return ERROR_OK;
}
int arm720t_register_commands(struct command_context_s *cmd_ctx)
{
int retval;
command_t *arm720t_cmd;
retval = arm7tdmi_register_commands(cmd_ctx);
arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, NULL);
register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode> [value]");
register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
return ERROR_OK;
}
int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
int retval;
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm7tdmi_common_t *arm7tdmi;
arm720t_common_t *arm720t;
arm_jtag_t *jtag_info;
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM720t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (argc >= 1)
{
u32 opcode = strtoul(args[0], NULL, 0);
if (argc == 1)
{
u32 value;
if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
return ERROR_OK;
}
jtag_execute_queue();
command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
}
else if (argc == 2)
{
u32 value = strtoul(args[1], NULL, 0);
if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
return ERROR_OK;
}
command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
}
}
return ERROR_OK;
}
int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm7tdmi_common_t *arm7tdmi;
arm720t_common_t *arm720t;
arm_jtag_t *jtag_info;
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM720t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
}
int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm7tdmi_common_t *arm7tdmi;
arm720t_common_t *arm720t;
arm_jtag_t *jtag_info;
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM720t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
}
int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm7tdmi_common_t *arm7tdmi;
arm720t_common_t *arm720t;
arm_jtag_t *jtag_info;
if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM720t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
}

43
src/target/arm720t.h Normal file
View File

@@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM720T_H
#define ARM720T_H
#include "target.h"
#include "register.h"
#include "embeddedice.h"
#include "arm_jtag.h"
#include "arm7tdmi.h"
#include "armv4_5_mmu.h"
#include "armv4_5_cache.h"
#define ARM720T_COMMON_MAGIC 0xa720a720
typedef struct arm720t_common_s
{
int common_magic;
armv4_5_mmu_common_t armv4_5_mmu;
arm7tdmi_common_t arm7tdmi_common;
u32 cp15_control_reg;
u32 fsr;
u32 far;
} arm720t_common_t;
#endif /* ARM720T_H */

2339
src/target/arm7_9_common.c Normal file

File diff suppressed because it is too large Load Diff

129
src/target/arm7_9_common.h Normal file
View File

@@ -0,0 +1,129 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM7_9_COMMON_H
#define ARM7_9_COMMON_H
#include "armv4_5.h"
#include "arm_jtag.h"
#include "breakpoints.h"
#include "target.h"
#define ARM7_9_COMMON_MAGIC 0x0a790a79
typedef struct arm7_9_common_s
{
int common_magic;
arm_jtag_t jtag_info;
reg_cache_t *eice_cache;
reg_cache_t *etm_cache;
u32 arm_bkpt;
u16 thumb_bkpt;
int sw_bkpts_use_wp;
int wp_available;
int wp0_used;
int wp1_used;
int sw_bkpts_enabled;
int force_hw_bkpts;
int dbgreq_adjust_pc;
int use_dbgrq;
int has_etm;
int reinit_embeddedice;
struct working_area_s *dcc_working_area;
int fast_memory_writes;
int dcc_downloads;
int (*examine_debug_reason)(target_t *target);
void (*change_to_arm)(target_t *target, u32 *r0, u32 *pc);
void (*read_core_regs)(target_t *target, u32 mask, u32* core_regs[16]);
void (*read_xpsr)(target_t *target, u32 *xpsr, int spsr);
void (*write_xpsr)(target_t *target, u32 xpsr, int spsr);
void (*write_xpsr_im8)(target_t *target, u8 xpsr_im, int rot, int spsr);
void (*write_core_regs)(target_t *target, u32 mask, u32 core_regs[16]);
void (*load_word_regs)(target_t *target, u32 mask);
void (*load_hword_reg)(target_t *target, int num);
void (*load_byte_reg)(target_t *target, int num);
void (*store_word_regs)(target_t *target, u32 mask);
void (*store_hword_reg)(target_t *target, int num);
void (*store_byte_reg)(target_t *target, int num);
void (*write_pc)(target_t *target, u32 pc);
void (*branch_resume)(target_t *target);
void (*branch_resume_thumb)(target_t *target);
void (*enable_single_step)(target_t *target);
void (*disable_single_step)(target_t *target);
void (*pre_debug_entry)(target_t *target);
void (*post_debug_entry)(target_t *target);
void (*pre_restore_context)(target_t *target);
void (*post_restore_context)(target_t *target);
armv4_5_common_t armv4_5_common;
void *arch_info;
} arm7_9_common_t;
int arm7_9_register_commands(struct command_context_s *cmd_ctx);
enum target_state arm7_9_poll(target_t *target);
int arm7_9_assert_reset(target_t *target);
int arm7_9_deassert_reset(target_t *target);
int arm7_9_reset_request_halt(target_t *target);
int arm7_9_early_halt(target_t *target);
int arm7_9_soft_reset_halt(struct target_s *target);
int arm7_9_halt(target_t *target);
int arm7_9_debug_entry(target_t *target);
int arm7_9_full_context(target_t *target);
int arm7_9_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
int arm7_9_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
int arm7_9_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode);
int arm7_9_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm7_9_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm7_9_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer);
int arm7_9_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_prams, reg_param_t *reg_param, u32 entry_point, void *arch_info);
int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
int arm7_9_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
int arm7_9_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
void arm7_9_enable_eice_step(target_t *target);
void arm7_9_disable_eice_step(target_t *target);
int arm7_9_execute_sys_speed(struct target_s *target);
int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9);
#endif /* ARM7_9_COMMON_H */

780
src/target/arm7tdmi.c Normal file
View File

@@ -0,0 +1,780 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "arm7tdmi.h"
#include "arm7_9_common.h"
#include "register.h"
#include "target.h"
#include "armv4_5.h"
#include "embeddedice.h"
#include "etm.h"
#include "log.h"
#include "jtag.h"
#include "arm_jtag.h"
#include <stdlib.h>
#include <string.h>
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
/* cli handling */
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
/* forward declarations */
int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
int arm7tdmi_quit();
/* target function declarations */
enum target_state arm7tdmi_poll(struct target_s *target);
int arm7tdmi_halt(target_t *target);
int arm7tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
target_type_t arm7tdmi_target =
{
.name = "arm7tdmi",
.poll = arm7_9_poll,
.arch_state = armv4_5_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 = arm7_9_soft_reset_halt,
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = arm7_9_bulk_write_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,
.register_commands = arm7tdmi_register_commands,
.target_command = arm7tdmi_target_command,
.init_target = arm7tdmi_init_target,
.quit = arm7tdmi_quit
};
int arm7tdmi_examine_debug_reason(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
/* only check the debug reason if we don't know it already */
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP))
{
scan_field_t fields[2];
u8 databus[4];
u8 breakpoint;
jtag_add_end_state(TAP_PD);
fields[0].device = arm7_9->jtag_info.chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = NULL;
fields[0].out_mask = NULL;
fields[0].in_value = &breakpoint;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = arm7_9->jtag_info.chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].out_mask = NULL;
fields[1].in_value = databus;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
arm_jtag_scann(&arm7_9->jtag_info, 0x1);
arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
jtag_add_dr_scan(2, fields, TAP_PD);
jtag_execute_queue();
fields[0].in_value = NULL;
fields[0].out_value = &breakpoint;
fields[1].in_value = NULL;
fields[1].out_value = databus;
jtag_add_dr_scan(2, fields, TAP_PD);
if (breakpoint & 1)
target->debug_reason = DBG_REASON_WATCHPOINT;
else
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */
int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint)
{
scan_field_t fields[2];
u8 out_buf[4];
u8 breakpoint_buf;
out = flip_u32(out, 32);
buf_set_u32(out_buf, 0, 32, out);
buf_set_u32(&breakpoint_buf, 0, 1, breakpoint);
jtag_add_end_state(TAP_PD);
arm_jtag_scann(jtag_info, 0x1);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &breakpoint_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = out_buf;
fields[1].out_mask = NULL;
if (in)
{
fields[1].in_value = (u8*)in;
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
fields[1].in_handler_priv = in;
} else
{
fields[1].in_value = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
}
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
jtag_add_dr_scan(2, fields, -1);
jtag_add_runtest(0, -1);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
char* in_string;
jtag_execute_queue();
if (in)
{
in_string = buf_to_char((u8*)in, 32);
DEBUG("out: 0x%8.8x, in: %s", flip_u32(out, 32), in_string);
free(in_string);
}
else
DEBUG("out: 0x%8.8x", flip_u32(out, 32));
}
#endif
return ERROR_OK;
}
/* put an instruction in the ARM7TDMI pipeline, and optionally read data */
int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
{
scan_field_t fields[2];
jtag_add_end_state(TAP_PD);
arm_jtag_scann(jtag_info, 0x1);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = NULL;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].out_mask = NULL;
fields[1].in_value = (u8*)in;
fields[1].in_handler = arm_jtag_buf_to_u32_flip;
fields[1].in_handler_priv = in;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
jtag_add_dr_scan(2, fields, -1);
jtag_add_runtest(0, -1);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
char* in_string;
jtag_execute_queue();
if (in)
{
in_string = buf_to_char((u8*)in, 32);
DEBUG("in: %s", in_string);
free(in_string);
}
}
#endif
return ERROR_OK;
}
void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* save r0 before using it and put system in ARM state
* to allow common handling of ARM and THUMB debugging */
/* fetch STR r0, [r0] */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, STR r0, [r0] in Execute (2) */
arm7tdmi_clock_data_in(jtag_info, r0);
/* MOV r0, r15 fetched, STR in Decode */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, STR r0, [r0] in Execute (2) */
arm7tdmi_clock_data_in(jtag_info, pc);
/* fetch MOV */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
/* fetch BX */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
/* NOP fetched, BX in Decode, MOV in Execute */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* NOP fetched, BX in Execute (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
jtag_execute_queue();
/* fix program counter:
* MOV r0, r15 was the 4th instruction (+6)
* reading PC in Thumb state gives address of instruction + 4
*/
*pc -= 0xa;
}
void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
{
int i;
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
for (i = 0; i <= 15; i++)
{
if (mask & (1 << i))
/* nothing fetched, STM still in EXECUTE (1+i cycle) */
arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
}
}
void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* MRS r0, cpsr */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
/* STR r0, [r15] */
arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
/* fetch NOP, STR in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, STR still in EXECUTE (2nd cycle) */
arm7tdmi_clock_data_in(jtag_info, xpsr);
}
void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
/* MSR1 fetched */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
/* MSR2 fetched, MSR1 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR4 in EXECUTE (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR4 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
/* MSR fetched */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
/* NOP fetched, MSR in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR in EXECUTE (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
{
int i;
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
for (i = 0; i <= 15; i++)
{
if (mask & (1 << i))
/* nothing fetched, LDM still in EXECUTE (1+i cycle) */
arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0);
}
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
void arm7tdmi_load_word_regs(target_t *target, u32 mask)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load-multiple into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
}
void arm7tdmi_load_hword_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load half-word into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
}
void arm7tdmi_load_byte_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load byte into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
}
void arm7tdmi_store_word_regs(target_t *target, u32 mask)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store-multiple into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
}
void arm7tdmi_store_hword_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store half-word into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
}
void arm7tdmi_store_byte_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store byte into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
}
void arm7tdmi_write_pc(target_t *target, u32 pc)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
arm7tdmi_clock_out(jtag_info, pc, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
void arm7tdmi_branch_resume(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0);
}
void arm7tdmi_branch_resume_thumb(target_t *target)
{
DEBUG("");
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
/* LDMIA r0, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* Branch and eXchange */
arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* clean r0 bits to avoid alignment problems */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
/* load r0 value, MOV_IM in Decode*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), NULL, 0);
/* fetch NOP, LDR in Decode, MOV_IM in Execute */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* fetch NOP, LDR in Execute */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
embeddedice_read_reg(dbg_stat);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), NULL, 0);
}
void arm7tdmi_build_reg_cache(target_t *target)
{
reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
arm7tdmi_common_t *arch_info = arm7_9->arch_info;
(*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
armv4_5->core_cache = (*cache_p);
(*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
arm7_9->eice_cache = (*cache_p)->next;
if (arm7_9->has_etm)
{
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
arm7_9->etm_cache = (*cache_p)->next->next;
}
if (arch_info->has_monitor_mode)
(*cache_p)->next->reg_list[0].size = 6;
else
(*cache_p)->next->reg_list[0].size = 3;
(*cache_p)->next->reg_list[1].size = 5;
}
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
arm7tdmi_build_reg_cache(target);
return ERROR_OK;
}
int arm7tdmi_quit()
{
return ERROR_OK;
}
int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant)
{
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
int has_etm = 0;
arm7_9 = &arm7tdmi->arm7_9_common;
armv4_5 = &arm7_9->armv4_5_common;
/* prepare JTAG information for the new target */
arm7_9->jtag_info.chain_pos = chain_pos;
arm7_9->jtag_info.scann_size = 4;
/* register arch-specific functions */
arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
arm7_9->change_to_arm = arm7tdmi_change_to_arm;
arm7_9->read_core_regs = arm7tdmi_read_core_regs;
arm7_9->read_xpsr = arm7tdmi_read_xpsr;
arm7_9->write_xpsr = arm7tdmi_write_xpsr;
arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
arm7_9->write_core_regs = arm7tdmi_write_core_regs;
arm7_9->load_word_regs = arm7tdmi_load_word_regs;
arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
arm7_9->store_word_regs = arm7tdmi_store_word_regs;
arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
arm7_9->write_pc = arm7tdmi_write_pc;
arm7_9->branch_resume = arm7tdmi_branch_resume;
arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
arm7_9->enable_single_step = arm7_9_enable_eice_step;
arm7_9->disable_single_step = arm7_9_disable_eice_step;
arm7_9->pre_debug_entry = NULL;
arm7_9->post_debug_entry = NULL;
arm7_9->pre_restore_context = NULL;
arm7_9->post_restore_context = NULL;
/* initialize arch-specific breakpoint handling */
buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
arm7_9->sw_bkpts_use_wp = 1;
arm7_9->sw_bkpts_enabled = 0;
arm7_9->dbgreq_adjust_pc = 2;
arm7_9->arch_info = arm7tdmi;
arm7tdmi->has_monitor_mode = 0;
arm7tdmi->arch_info = NULL;
arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC;
if (variant)
{
if (strcmp(variant, "arm7tdmi-s_r4") == 0)
arm7tdmi->has_monitor_mode = 1;
else if (strcmp(variant, "arm7tdmi_r4") == 0)
arm7tdmi->has_monitor_mode = 1;
else if (strcmp(variant, "lpc2000") == 0)
{
arm7tdmi->has_monitor_mode = 1;
has_etm = 1;
}
arm7tdmi->variant = strdup(variant);
}
else
arm7tdmi->variant = strdup("");
arm7_9_init_arch_info(target, arm7_9);
arm7_9->has_etm = has_etm;
return ERROR_OK;
}
/* target arm7tdmi <endianess> <startup_mode> <chain_pos> <variant> */
int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
{
int chain_pos;
char *variant = NULL;
arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t));
if (argc < 4)
{
ERROR("'target arm7tdmi' requires at least one additional argument");
exit(-1);
}
chain_pos = strtoul(args[2], NULL, 0);
if (argc >= 5)
variant = args[4];
arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
return ERROR_OK;
}
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx)
{
int retval;
retval = arm7_9_register_commands(cmd_ctx);
return ERROR_OK;
}

46
src/target/arm7tdmi.h Normal file
View File

@@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM7TDMI_H
#define ARM7TDMI_H
#include "target.h"
#include "register.h"
#include "armv4_5.h"
#include "embeddedice.h"
#include "arm_jtag.h"
#include "arm7_9_common.h"
#define ARM7TDMI_COMMON_MAGIC 0x00a700a7
typedef struct arm7tdmi_common_s
{
int common_magic;
char *variant;
int has_monitor_mode;
void *arch_info;
arm7_9_common_t arm7_9_common;
} arm7tdmi_common_t;
int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant);
int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
#endif /* ARM7TDMI_H */

967
src/target/arm920t.c Normal file
View File

@@ -0,0 +1,967 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "arm920t.h"
#include "jtag.h"
#include "log.h"
#include <stdlib.h>
#include <string.h>
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
/* cli handling */
int arm920t_register_commands(struct command_context_s *cmd_ctx);
int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
/* forward declarations */
int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
int arm920t_quit();
int arm920t_arch_state(struct target_s *target, char *buf, int buf_size);
int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int arm920t_soft_reset_halt(struct target_s *target);
target_type_t arm920t_target =
{
.name = "arm920t",
.poll = arm7_9_poll,
.arch_state = arm920t_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 = arm920t_soft_reset_halt,
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
.read_memory = arm920t_read_memory,
.write_memory = arm920t_write_memory,
.bulk_write_memory = arm7_9_bulk_write_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,
.register_commands = arm920t_register_commands,
.target_command = arm920t_target_command,
.init_target = arm920t_init_target,
.quit = arm920t_quit
};
int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
scan_field_t fields[4];
u8 access_type_buf = 1;
u8 reg_addr_buf = reg_addr & 0x3f;
u8 nr_w_buf = 0;
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(jtag_info, 0xf);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &access_type_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 6;
fields[2].out_value = &reg_addr_buf;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
fields[3].device = jtag_info->chain_pos;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].out_mask = NULL;
fields[3].in_value = NULL;
fields[3].in_check_value = NULL;
fields[3].in_check_mask = NULL;
fields[3].in_handler = NULL;
fields[3].in_handler_priv = NULL;
jtag_add_dr_scan(4, fields, -1);
fields[1].in_value = (u8*)value;
jtag_add_dr_scan(4, fields, -1);
return ERROR_OK;
}
int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
scan_field_t fields[4];
u8 access_type_buf = 1;
u8 reg_addr_buf = reg_addr & 0x3f;
u8 nr_w_buf = 1;
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(jtag_info, 0xf);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &access_type_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = (u8*)&value;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 6;
fields[2].out_value = &reg_addr_buf;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
fields[3].device = jtag_info->chain_pos;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].out_mask = NULL;
fields[3].in_value = NULL;
fields[3].in_check_value = NULL;
fields[3].in_check_mask = NULL;
fields[3].in_handler = NULL;
fields[3].in_handler_priv = NULL;
jtag_add_dr_scan(4, fields, -1);
return ERROR_OK;
}
int arm920t_read_cp15_interpreted(target_t *target, u32 opcode, u32 *value)
{
u32 cp15c15 = 0x0;
scan_field_t fields[4];
u8 access_type_buf = 0; /* interpreted access */
u8 reg_addr_buf = 0x0;
u8 nr_w_buf = 0;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
u32* context_p[1];
/* read-modify-write CP15 test state register
* to enable interpreted access mode */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 |= 1; /* set interpret mode */
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(jtag_info, 0xf);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &access_type_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = (u8*)&opcode;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 6;
fields[2].out_value = &reg_addr_buf;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
fields[3].device = jtag_info->chain_pos;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].out_mask = NULL;
fields[3].in_value = NULL;
fields[3].in_check_value = NULL;
fields[3].in_check_mask = NULL;
fields[3].in_handler = NULL;
fields[3].in_handler_priv = NULL;
jtag_add_dr_scan(4, fields, -1);
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDR(0, 15), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
arm7_9_execute_sys_speed(target);
jtag_execute_queue();
/* read-modify-write CP15 test state register
* to disable interpreted access mode */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 &= ~1U; /* clear interpret mode */
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
context_p[0] = value;
arm9tdmi_read_core_regs(target, 0x1, context_p);
jtag_execute_queue();
DEBUG("opcode: %8.8x, value: %8.8x", opcode, *value);
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15).dirty = 1;
return ERROR_OK;
}
int arm920t_write_cp15_interpreted(target_t *target, u32 opcode, u32 value, u32 address)
{
u32 cp15c15 = 0x0;
scan_field_t fields[4];
u8 access_type_buf = 0; /* interpreted access */
u8 reg_addr_buf = 0x0;
u8 nr_w_buf = 0;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
u32 regs[2];
regs[0] = value;
regs[1] = address;
arm9tdmi_write_core_regs(target, 0x3, regs);
/* read-modify-write CP15 test state register
* to enable interpreted access mode */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 |= 1; /* set interpret mode */
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(jtag_info, 0xf);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 1;
fields[0].out_value = &access_type_buf;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 32;
fields[1].out_value = (u8*)&opcode;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 6;
fields[2].out_value = &reg_addr_buf;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
fields[3].device = jtag_info->chain_pos;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].out_mask = NULL;
fields[3].in_value = NULL;
fields[3].in_check_value = NULL;
fields[3].in_check_mask = NULL;
fields[3].in_handler = NULL;
fields[3].in_handler_priv = NULL;
jtag_add_dr_scan(4, fields, -1);
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
arm7_9_execute_sys_speed(target);
jtag_execute_queue();
/* read-modify-write CP15 test state register
* to disable interpreted access mode */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 &= ~1U; /* set interpret mode */
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
DEBUG("opcode: %8.8x, value: %8.8x, address: %8.8x", opcode, value, address);
return ERROR_OK;
}
u32 arm920t_get_ttb(target_t *target)
{
int retval;
u32 ttb = 0x0;
if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, &ttb)) != ERROR_OK)
return retval;
return ttb;
}
void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
{
u32 cp15_control;
/* read cp15 control register */
arm920t_read_cp15_physical(target, 0x2, &cp15_control);
jtag_execute_queue();
if (mmu)
cp15_control &= ~0x1U;
if (d_u_cache)
cp15_control &= ~0x4U;
if (i_cache)
cp15_control &= ~0x1000U;
arm920t_write_cp15_physical(target, 0x2, cp15_control);
}
void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
{
u32 cp15_control;
/* read cp15 control register */
arm920t_read_cp15_physical(target, 0x2, &cp15_control);
jtag_execute_queue();
if (mmu)
cp15_control |= 0x1U;
if (d_u_cache)
cp15_control |= 0x4U;
if (i_cache)
cp15_control |= 0x1000U;
arm920t_write_cp15_physical(target, 0x2, cp15_control);
}
void arm920t_post_debug_entry(target_t *target)
{
u32 cp15c15;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
arm920t_common_t *arm920t = arm9tdmi->arch_info;
/* examine cp15 control reg */
arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg);
jtag_execute_queue();
DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg);
if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1)
{
u32 cache_type_reg;
/* identify caches */
arm920t_read_cp15_physical(target, 0x1, &cache_type_reg);
jtag_execute_queue();
armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache);
}
arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0;
arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0;
arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0;
/* save i/d fault status and address register */
arm920t_read_cp15_interpreted(target, 0xee150f10, &arm920t->d_fsr);
arm920t_read_cp15_interpreted(target, 0xee150f30, &arm920t->i_fsr);
arm920t_read_cp15_interpreted(target, 0xee160f10, &arm920t->d_far);
arm920t_read_cp15_interpreted(target, 0xee160f30, &arm920t->i_far);
/* read-modify-write CP15 test state register
* to disable I/D-cache linefills */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 |= 0x600;
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
}
void arm920t_pre_restore_context(target_t *target)
{
u32 cp15c15;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
arm920t_common_t *arm920t = arm9tdmi->arch_info;
/* restore i/d fault status and address register */
arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0);
arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0);
arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0);
arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0);
/* read-modify-write CP15 test state register
* to reenable I/D-cache linefills */
arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
jtag_execute_queue();
cp15c15 &= ~0x600U;
arm920t_write_cp15_physical(target, 0x1e, cp15c15);
}
int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
return -1;
}
arm7_9 = armv4_5->arch_info;
if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
{
return -1;
}
arm9tdmi = arm7_9->arch_info;
if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
{
return -1;
}
arm920t = arm9tdmi->arch_info;
if (arm920t->common_magic != ARM920T_COMMON_MAGIC)
{
return -1;
}
*armv4_5_p = armv4_5;
*arm7_9_p = arm7_9;
*arm9tdmi_p = arm9tdmi;
*arm920t_p = arm920t;
return ERROR_OK;
}
int arm920t_arch_state(struct target_s *target, char *buf, int buf_size)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
arm920t_common_t *arm920t = arm9tdmi->arch_info;
char *state[] =
{
"disabled", "enabled"
};
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
ERROR("BUG: called for a non-ARMv4/5 target");
exit(-1);
}
snprintf(buf, buf_size,
"target halted in %s state due to %s, current mode: %s\n"
"cpsr: 0x%8.8x pc: 0x%8.8x\n"
"MMU: %s, D-Cache: %s, I-Cache: %s",
armv4_5_state_strings[armv4_5->core_state],
target_debug_reason_strings[target->debug_reason],
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
state[arm920t->armv4_5_mmu.mmu_enabled],
state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
return ERROR_OK;
}
int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
retval = arm7_9_read_memory(target, address, size, count, buffer);
return retval;
}
int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
arm920t_common_t *arm920t = arm9tdmi->arch_info;
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
return retval;
if (((size == 4) || (size == 2)) && (count == 1))
{
if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
{
DEBUG("D-Cache enabled, writing through to main memory");
u32 pa, cb, ap;
int type, domain;
pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap);
if (type == -1)
return ERROR_OK;
/* cacheable & bufferable means write-back region */
if (cb == 3)
armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer);
}
if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
{
DEBUG("I-Cache enabled, invalidating affected I-Cache line");
arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address);
}
}
return retval;
}
int arm920t_soft_reset_halt(struct target_s *target)
{
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
arm920t_common_t *arm920t = arm9tdmi->arch_info;
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
if (target->state == TARGET_RUNNING)
{
target->type->halt(target);
}
while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
{
embeddedice_read_reg(dbg_stat);
jtag_execute_queue();
}
target->state = TARGET_HALTED;
/* SVC, ARM state, IRQ and FIQ disabled */
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
/* start fetching from 0x0 */
buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
armv4_5->core_cache->reg_list[15].dirty = 1;
armv4_5->core_cache->reg_list[15].valid = 1;
armv4_5->core_mode = ARMV4_5_MODE_SVC;
armv4_5->core_state = ARMV4_5_STATE_ARM;
arm920t_disable_mmu_caches(target, 1, 1, 1);
arm920t->armv4_5_mmu.mmu_enabled = 0;
arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
return ERROR_OK;
}
int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
arm9tdmi_init_target(cmd_ctx, target);
return ERROR_OK;
}
int arm920t_quit()
{
return ERROR_OK;
}
int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant)
{
arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common;
arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
arm9tdmi->arch_info = arm920t;
arm920t->common_magic = ARM920T_COMMON_MAGIC;
arm7_9->post_debug_entry = arm920t_post_debug_entry;
arm7_9->pre_restore_context = arm920t_pre_restore_context;
arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1;
arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb;
arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory;
arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory;
arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches;
arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches;
arm920t->armv4_5_mmu.has_tiny_pages = 1;
arm920t->armv4_5_mmu.mmu_enabled = 0;
arm9tdmi->has_single_step = 1;
return ERROR_OK;
}
int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
{
int chain_pos;
char *variant = NULL;
arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t));
if (argc < 4)
{
ERROR("'target arm920t' requires at least one additional argument");
exit(-1);
}
chain_pos = strtoul(args[3], NULL, 0);
if (argc >= 5)
variant = strdup(args[4]);
DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
arm920t_init_arch_info(target, arm920t, chain_pos, variant);
return ERROR_OK;
}
int arm920t_register_commands(struct command_context_s *cmd_ctx)
{
int retval;
command_t *arm920t_cmd;
retval = arm9tdmi_register_commands(cmd_ctx);
arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands");
register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]");
register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) <opcode> [value] [address]");
register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches");
register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
return ERROR_OK;
}
int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
int retval;
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
arm_jtag_t *jtag_info;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (argc >= 1)
{
int address = strtoul(args[0], NULL, 0);
if (argc == 1)
{
u32 value;
if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't access reg %i", address);
return ERROR_OK;
}
jtag_execute_queue();
command_print(cmd_ctx, "%i: %8.8x", address, value);
}
else if (argc == 2)
{
u32 value = strtoul(args[1], NULL, 0);
if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't access reg %i", address);
return ERROR_OK;
}
command_print(cmd_ctx, "%i: %8.8x", address, value);
}
}
return ERROR_OK;
}
int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
int retval;
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
arm_jtag_t *jtag_info;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (argc >= 1)
{
u32 opcode = strtoul(args[0], NULL, 0);
if (argc == 1)
{
u32 value;
if ((retval = arm920t_read_cp15_interpreted(target, opcode, &value)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
return ERROR_OK;
}
command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
}
else if (argc == 2)
{
u32 value = strtoul(args[1], NULL, 0);
if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
return ERROR_OK;
}
command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
}
else if (argc == 3)
{
u32 value = strtoul(args[1], NULL, 0);
u32 address = strtoul(args[2], NULL, 0);
if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK)
{
command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
return ERROR_OK;
}
command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address);
}
}
return ERROR_OK;
}
int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache);
}
int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
arm_jtag_t *jtag_info;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
}
int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
arm_jtag_t *jtag_info;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
}
int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm9tdmi_common_t *arm9tdmi;
arm920t_common_t *arm920t;
arm_jtag_t *jtag_info;
if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
{
command_print(cmd_ctx, "current target isn't an ARM920t target");
return ERROR_OK;
}
jtag_info = &arm7_9->jtag_info;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
}

45
src/target/arm920t.h Normal file
View File

@@ -0,0 +1,45 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM920T_H
#define ARM920T_H
#include "target.h"
#include "register.h"
#include "embeddedice.h"
#include "arm_jtag.h"
#include "arm9tdmi.h"
#include "armv4_5_mmu.h"
#include "armv4_5_cache.h"
#define ARM920T_COMMON_MAGIC 0xa920a920
typedef struct arm920t_common_s
{
int common_magic;
armv4_5_mmu_common_t armv4_5_mmu;
arm9tdmi_common_t arm9tdmi_common;
u32 cp15_control_reg;
u32 d_fsr;
u32 i_fsr;
u32 d_far;
u32 i_far;
} arm920t_common_t;
#endif /* ARM920T_H */

848
src/target/arm9tdmi.c Normal file
View File

@@ -0,0 +1,848 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "arm9tdmi.h"
#include "arm7_9_common.h"
#include "register.h"
#include "target.h"
#include "armv4_5.h"
#include "embeddedice.h"
#include "log.h"
#include "jtag.h"
#include "arm_jtag.h"
#include <stdlib.h>
#include <string.h>
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
/* cli handling */
int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
/* forward declarations */
int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
int arm9tdmi_quit();
/* target function declarations */
enum target_state arm9tdmi_poll(struct target_s *target);
int arm9tdmi_halt(target_t *target);
int arm9tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
target_type_t arm9tdmi_target =
{
.name = "arm9tdmi",
.poll = arm7_9_poll,
.arch_state = armv4_5_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 = arm7_9_soft_reset_halt,
.get_gdb_reg_list = armv4_5_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.register_commands = arm9tdmi_register_commands,
.target_command = arm9tdmi_target_command,
.init_target = arm9tdmi_init_target,
.quit = arm9tdmi_quit
};
int arm9tdmi_examine_debug_reason(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
/* only check the debug reason if we don't know it already */
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP))
{
scan_field_t fields[3];
u8 databus[4];
u8 instructionbus[4];
u8 debug_reason;
jtag_add_end_state(TAP_PD);
fields[0].device = arm7_9->jtag_info.chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].out_mask = NULL;
fields[0].in_value = databus;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = arm7_9->jtag_info.chain_pos;
fields[1].num_bits = 3;
fields[1].out_value = NULL;
fields[1].out_mask = NULL;
fields[1].in_value = &debug_reason;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = arm7_9->jtag_info.chain_pos;
fields[2].num_bits = 32;
fields[2].out_value = NULL;
fields[2].out_mask = NULL;
fields[2].in_value = instructionbus;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
arm_jtag_scann(&arm7_9->jtag_info, 0x1);
arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
jtag_add_dr_scan(3, fields, TAP_PD);
jtag_execute_queue();
fields[0].in_value = NULL;
fields[0].out_value = databus;
fields[1].in_value = NULL;
fields[1].out_value = &debug_reason;
fields[2].in_value = NULL;
fields[2].out_value = instructionbus;
jtag_add_dr_scan(3, fields, TAP_PD);
if (debug_reason & 0x4)
if (debug_reason & 0x2)
target->debug_reason = DBG_REASON_WPTANDBKPT;
else
target->debug_reason = DBG_REASON_WATCHPOINT;
else
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */
int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed)
{
scan_field_t fields[3];
u8 out_buf[4];
u8 instr_buf[4];
u8 sysspeed_buf = 0x0;
/* prepare buffer */
buf_set_u32(out_buf, 0, 32, out);
instr = flip_u32(instr, 32);
buf_set_u32(instr_buf, 0, 32, instr);
if (sysspeed)
buf_set_u32(&sysspeed_buf, 2, 1, 1);
jtag_add_end_state(TAP_PD);
arm_jtag_scann(jtag_info, 0x1);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = out_buf;
fields[0].out_mask = NULL;
if (in)
{
fields[0].in_value = (u8*)in;
} else
{
fields[0].in_value = NULL;
}
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 3;
fields[1].out_value = &sysspeed_buf;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 32;
fields[2].out_value = instr_buf;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
jtag_add_runtest(0, -1);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
char* in_string;
jtag_execute_queue();
if (in)
{
in_string = buf_to_char((u8*)in, 32);
DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: %s", flip_u32(instr, 32), out, in_string);
free(in_string);
}
else
DEBUG("instr: 0x%8.8x, out: 0x%8.8x", flip_u32(instr, 32), out);
}
#endif
return ERROR_OK;
}
/* just read data (instruction and data-out = don't care) */
int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
{
scan_field_t fields[3];
jtag_add_end_state(TAP_PD);
arm_jtag_scann(jtag_info, 0x1);
arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
fields[0].device = jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].out_mask = NULL;
fields[0].in_value = (u8*)in;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[1].device = jtag_info->chain_pos;
fields[1].num_bits = 3;
fields[1].out_value = NULL;
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[2].device = jtag_info->chain_pos;
fields[2].num_bits = 32;
fields[2].out_value = NULL;
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
jtag_add_runtest(0, -1);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
char* in_string;
jtag_execute_queue();
if (in)
{
in_string = buf_to_char((u8*)in, 32);
DEBUG("in: %s", in_string);
free(in_string);
}
}
#endif
return ERROR_OK;
}
void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* save r0 before using it and put system in ARM state
* to allow common handling of ARM and THUMB debugging */
/* fetch STR r0, [r0] */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* STR r0, [r0] in Memory */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
/* MOV r0, r15 fetched, STR in Decode */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* nothing fetched, STR r0, [r0] in Memory */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
/* fetch MOV */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* fetch BX */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0);
/* NOP fetched, BX in Decode, MOV in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* NOP fetched, BX in Execute (1) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
jtag_execute_queue();
/* fix program counter:
* MOV r0, r15 was the 5th instruction (+8)
* reading PC in Thumb state gives address of instruction + 4
*/
*pc -= 0xc;
}
void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
{
int i;
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++)
{
if (mask & (1 << i))
/* nothing fetched, STM in MEMORY (i'th cycle) */
arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
}
}
void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* MRS r0, cpsr */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* STR r0, [r15] */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
/* fetch NOP, STR in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, STR in MEMORY */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
}
void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
/* MSR1 fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
/* MSR2 fetched, MSR1 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR4 in EXECUTE (1) */
/* last MSR writes flags, which takes only one cycle */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
/* MSR fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
/* NOP fetched, MSR in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR in EXECUTE (1) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* rot == 4 writes flags, which takes only one cycle */
if (rot != 4)
{
/* nothing fetched, MSR in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
}
void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
{
int i;
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++)
{
if (mask & (1 << i))
/* nothing fetched, LDM still in EXECUTE (1+i cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
}
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
void arm9tdmi_load_word_regs(target_t *target, u32 mask)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load-multiple into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_load_hword_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load half-word into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_load_byte_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed load byte into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_word_regs(target_t *target, u32 mask)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store-multiple into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_hword_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store half-word into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_byte_reg(target_t *target, int num)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* put system-speed store byte into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_write_pc(target_t *target, u32 pc)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
void arm9tdmi_branch_resume(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_branch_resume_thumb(target_t *target)
{
DEBUG("");
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* Branch and eXchange */
arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* clean r0 bits to avoid alignment problems */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
/* load r0 value, MOV_IM in Decode*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), 0, NULL, 0);
/* fetch NOP, LDR in Decode, MOV_IM in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* fetch NOP, LDR in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f6), 0, NULL, 1);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
}
void arm9tdmi_enable_single_step(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9 = arm7_9->arch_info;
if (arm9->has_single_step)
{
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
}
else
{
arm7_9_enable_eice_step(target);
}
}
void arm9tdmi_disable_single_step(target_t *target)
{
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm9tdmi_common_t *arm9 = arm7_9->arch_info;
if (arm9->has_single_step)
{
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
}
else
{
arm7_9_disable_eice_step(target);
}
}
void arm9tdmi_build_reg_cache(target_t *target)
{
reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
/* get pointers to arch-specific information */
armv4_5_common_t *armv4_5 = target->arch_info;
arm7_9_common_t *arm7_9 = armv4_5->arch_info;
arm_jtag_t *jtag_info = &arm7_9->jtag_info;
arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
(*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
armv4_5->core_cache = (*cache_p);
(*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
arm7_9->eice_cache = (*cache_p)->next;
if (arm9tdmi->has_monitor_mode)
(*cache_p)->next->reg_list[0].size = 6;
else
(*cache_p)->next->reg_list[0].size = 4;
(*cache_p)->next->reg_list[1].size = 5;
}
int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
arm9tdmi_build_reg_cache(target);
return ERROR_OK;
}
int arm9tdmi_quit()
{
return ERROR_OK;
}
int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant)
{
armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9;
arm7_9 = &arm9tdmi->arm7_9_common;
armv4_5 = &arm7_9->armv4_5_common;
/* prepare JTAG information for the new target */
arm7_9->jtag_info.chain_pos = chain_pos;
arm7_9->jtag_info.scann_size = 5;
/* register arch-specific functions */
arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
arm7_9->change_to_arm = arm9tdmi_change_to_arm;
arm7_9->read_core_regs = arm9tdmi_read_core_regs;
arm7_9->read_xpsr = arm9tdmi_read_xpsr;
arm7_9->write_xpsr = arm9tdmi_write_xpsr;
arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8;
arm7_9->write_core_regs = arm9tdmi_write_core_regs;
arm7_9->load_word_regs = arm9tdmi_load_word_regs;
arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
arm7_9->store_word_regs = arm9tdmi_store_word_regs;
arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
arm7_9->write_pc = arm9tdmi_write_pc;
arm7_9->branch_resume = arm9tdmi_branch_resume;
arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb;
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
arm7_9->pre_debug_entry = NULL;
arm7_9->post_debug_entry = NULL;
arm7_9->pre_restore_context = NULL;
arm7_9->post_restore_context = NULL;
/* initialize arch-specific breakpoint handling */
buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
arm7_9->sw_bkpts_use_wp = 1;
arm7_9->sw_bkpts_enabled = 0;
arm7_9->dbgreq_adjust_pc = 3;
arm7_9->arch_info = arm9tdmi;
arm7_9->use_dbgrq = 1;
arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC;
arm9tdmi->has_monitor_mode = 0;
arm9tdmi->has_single_step = 0;
arm9tdmi->arch_info = NULL;
if (variant)
{
if (strcmp(variant, "arm920t") == 0)
arm9tdmi->has_single_step = 1;
else if (strcmp(variant, "arm922t") == 0)
arm9tdmi->has_single_step = 1;
else if (strcmp(variant, "arm940t") == 0)
arm9tdmi->has_single_step = 1;
}
arm7_9_init_arch_info(target, arm7_9);
return ERROR_OK;
}
/* target arm9tdmi <endianess> <startup_mode> <chain_pos> <variant>*/
int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
{
int chain_pos;
char *variant = NULL;
arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t));
if (argc < 4)
{
ERROR("'target arm9tdmi' requires at least one additional argument");
exit(-1);
}
chain_pos = strtoul(args[3], NULL, 0);
if (argc >= 5)
variant = strdup(args[4]);
arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
return ERROR_OK;
}
int arm9tdmi_register_commands(struct command_context_s *cmd_ctx)
{
int retval;
retval = arm7_9_register_commands(cmd_ctx);
return ERROR_OK;
}

51
src/target/arm9tdmi.h Normal file
View File

@@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM9TDMI_H
#define ARM9TDMI_H
#include "target.h"
#include "register.h"
#include "armv4_5.h"
#include "embeddedice.h"
#include "arm_jtag.h"
#include "arm7_9_common.h"
#define ARM9TDMI_COMMON_MAGIC 0x00a900a9
typedef struct arm9tdmi_common_s
{
int common_magic;
char *variant;
int has_monitor_mode;
int has_single_step;
void *arch_info;
arm7_9_common_t arm7_9_common;
} arm9tdmi_common_t;
extern int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
extern int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant);
extern int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
extern int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed);
extern int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in);
extern void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]);
extern void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]);
#endif /* ARM9TDMI_H */

116
src/target/arm_jtag.c Normal file
View File

@@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "arm_jtag.h"
#include "binarybuffer.h"
#include "log.h"
#include "jtag.h"
#include <stdlib.h>
int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr)
{
jtag_device_t *device = jtag_get_device(jtag_info->chain_pos);
if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
{
scan_field_t field;
field.device = jtag_info->chain_pos;
field.num_bits = device->ir_length;
field.out_value = calloc(CEIL(field.num_bits, 8), 1);
buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
field.out_mask = NULL;
field.in_value = NULL;
field.in_check_value = NULL;
field.in_check_mask = NULL;
field.in_handler = NULL;
field.in_handler_priv = NULL;
jtag_add_ir_scan(1, &field, -1);
free(field.out_value);
}
return ERROR_OK;
}
int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain)
{
if(jtag_info->cur_scan_chain != new_scan_chain)
{
scan_field_t field;
field.device = jtag_info->chain_pos;
field.num_bits = jtag_info->scann_size;
field.out_value = calloc(CEIL(field.num_bits, 8), 1);
buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain);
field.out_mask = NULL;
//field.in_value = &scan_n_capture;
field.in_value = NULL;
field.in_check_value = NULL;
field.in_check_mask = NULL;
field.in_handler = NULL;
field.in_handler_priv = NULL;
arm_jtag_set_instr(jtag_info, jtag_info->scann_instr);
jtag_add_dr_scan(1, &field, -1);
jtag_info->cur_scan_chain = new_scan_chain;
free(field.out_value);
}
return ERROR_OK;
}
int arm_jtag_reset_callback(enum jtag_event event, void *priv)
{
arm_jtag_t *jtag_info = priv;
if (event == JTAG_TRST_ASSERTED)
{
jtag_info->cur_scan_chain = 0;
}
return ERROR_OK;
}
int arm_jtag_setup_connection(arm_jtag_t *jtag_info)
{
jtag_info->scann_instr = 0x2;
jtag_info->cur_scan_chain = 0;
jtag_info->intest_instr = 0xc;
jtag_register_event_callback(arm_jtag_reset_callback, jtag_info);
return ERROR_OK;
}
int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv)
{
u32 *dest = priv;
*dest = flip_u32(buf_get_u32(in_buf, 0, 32), 32);
return ERROR_OK;
}

42
src/target/arm_jtag.h Normal file
View File

@@ -0,0 +1,42 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_JTAG
#define ARM_JTAG
#include "types.h"
typedef struct arm_jtag_s
{
int chain_pos;
int scann_size;
u32 scann_instr;
int cur_scan_chain;
u32 intest_instr;
} arm_jtag_t;
extern int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr);
extern int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain);
extern int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv);
extern int arm_jtag_setup_connection(arm_jtag_t *jtag_info);
#endif /* ARM_JTAG */

583
src/target/armv4_5.c Normal file
View File

@@ -0,0 +1,583 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "armv4_5.h"
#include "target.h"
#include "register.h"
#include "log.h"
#include "binarybuffer.h"
#include "command.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
bitfield_desc_t armv4_5_psr_bitfield_desc[] =
{
{"M[4:0]", 5},
{"T", 1},
{"F", 1},
{"I", 1},
{"reserved", 16},
{"J", 1},
{"reserved", 2},
{"Q", 1},
{"V", 1},
{"C", 1},
{"Z", 1},
{"N", 1},
};
char* armv4_5_core_reg_list[] =
{
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13_usr", "lr_usr", "pc",
"r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "lr_fiq",
"r13_irq", "lr_irq",
"r13_svc", "lr_svc",
"r13_abt", "lr_abt",
"r13_und", "lr_und",
"cpsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_abt", "spsr_und"
};
char* armv4_5_mode_strings[] =
{
"User", "FIQ", "IRQ", "Supervisor", "Abort", "Undefined", "System"
};
char* armv4_5_state_strings[] =
{
"ARM", "Thumb", "Jazelle"
};
int armv4_5_core_reg_arch_type = -1;
armv4_5_core_reg_t armv4_5_core_reg_list_arch_info[] =
{
{0, ARMV4_5_MODE_ANY, NULL, NULL},
{1, ARMV4_5_MODE_ANY, NULL, NULL},
{2, ARMV4_5_MODE_ANY, NULL, NULL},
{3, ARMV4_5_MODE_ANY, NULL, NULL},
{4, ARMV4_5_MODE_ANY, NULL, NULL},
{5, ARMV4_5_MODE_ANY, NULL, NULL},
{6, ARMV4_5_MODE_ANY, NULL, NULL},
{7, ARMV4_5_MODE_ANY, NULL, NULL},
{8, ARMV4_5_MODE_ANY, NULL, NULL},
{9, ARMV4_5_MODE_ANY, NULL, NULL},
{10, ARMV4_5_MODE_ANY, NULL, NULL},
{11, ARMV4_5_MODE_ANY, NULL, NULL},
{12, ARMV4_5_MODE_ANY, NULL, NULL},
{13, ARMV4_5_MODE_USR, NULL, NULL},
{14, ARMV4_5_MODE_USR, NULL, NULL},
{15, ARMV4_5_MODE_ANY, NULL, NULL},
{8, ARMV4_5_MODE_FIQ, NULL, NULL},
{9, ARMV4_5_MODE_FIQ, NULL, NULL},
{10, ARMV4_5_MODE_FIQ, NULL, NULL},
{11, ARMV4_5_MODE_FIQ, NULL, NULL},
{12, ARMV4_5_MODE_FIQ, NULL, NULL},
{13, ARMV4_5_MODE_FIQ, NULL, NULL},
{14, ARMV4_5_MODE_FIQ, NULL, NULL},
{13, ARMV4_5_MODE_IRQ, NULL, NULL},
{14, ARMV4_5_MODE_IRQ, NULL, NULL},
{13, ARMV4_5_MODE_SVC, NULL, NULL},
{14, ARMV4_5_MODE_SVC, NULL, NULL},
{13, ARMV4_5_MODE_ABT, NULL, NULL},
{14, ARMV4_5_MODE_ABT, NULL, NULL},
{13, ARMV4_5_MODE_UND, NULL, NULL},
{14, ARMV4_5_MODE_UND, NULL, NULL},
{16, ARMV4_5_MODE_ANY, NULL, NULL},
{16, ARMV4_5_MODE_FIQ, NULL, NULL},
{16, ARMV4_5_MODE_IRQ, NULL, NULL},
{16, ARMV4_5_MODE_SVC, NULL, NULL},
{16, ARMV4_5_MODE_ABT, NULL, NULL},
{16, ARMV4_5_MODE_UND, NULL, NULL}
};
/* map core mode (USR, FIQ, ...) and register number to indizes into the register cache */
int armv4_5_core_reg_map[7][17] =
{
{ /* USR */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
},
{ /* FIQ */
0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32
},
{ /* IRQ */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33
},
{ /* SVC */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34
},
{ /* ABT */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35
},
{ /* UND */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36
},
{ /* SYS */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
}
};
u8 armv4_5_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
reg_t armv4_5_gdb_dummy_fp_reg =
{
"GDB dummy floating-point register", armv4_5_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
};
u8 armv4_5_gdb_dummy_fps_value[] = {0, 0, 0, 0};
reg_t armv4_5_gdb_dummy_fps_reg =
{
"GDB dummy floating-point status register", armv4_5_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
};
/* map psr mode bits to linear number */
int armv4_5_mode_to_number(enum armv4_5_mode mode)
{
switch (mode)
{
case 16: return 0; break;
case 17: return 1; break;
case 18: return 2; break;
case 19: return 3; break;
case 23: return 4; break;
case 27: return 5; break;
case 31: return 6; break;
case -1: return 0; break; /* map MODE_ANY to user mode */
default:
ERROR("invalid mode value encountered");
return -1;
}
}
/* map linear number to mode bits */
enum armv4_5_mode armv4_5_number_to_mode(int number)
{
switch(number)
{
case 0: return ARMV4_5_MODE_USR; break;
case 1: return ARMV4_5_MODE_FIQ; break;
case 2: return ARMV4_5_MODE_IRQ; break;
case 3: return ARMV4_5_MODE_SVC; break;
case 4: return ARMV4_5_MODE_ABT; break;
case 5: return ARMV4_5_MODE_UND; break;
case 6: return ARMV4_5_MODE_SYS; break;
default:
ERROR("mode index out of bounds");
return -1;
}
};
int armv4_5_get_core_reg(reg_t *reg)
{
int retval;
armv4_5_core_reg_t *armv4_5 = reg->arch_info;
target_t *target = armv4_5->target;
if (target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
//retval = armv4_5->armv4_5_common->full_context(target);
retval = armv4_5->armv4_5_common->read_core_reg(target, armv4_5->num, armv4_5->mode);
return retval;
}
int armv4_5_set_core_reg(reg_t *reg, u32 value)
{
armv4_5_core_reg_t *armv4_5 = reg->arch_info;
target_t *target = armv4_5->target;
if (target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
buf_set_u32(reg->value, 0, 32, value);
reg->dirty = 1;
reg->valid = 1;
return ERROR_OK;
}
int armv4_5_invalidate_core_regs(target_t *target)
{
armv4_5_common_t *armv4_5 = target->arch_info;
int i;
for (i = 0; i < 37; i++)
{
armv4_5->core_cache->reg_list[i].valid = 0;
armv4_5->core_cache->reg_list[i].dirty = 0;
}
return ERROR_OK;
}
reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common)
{
int num_regs = 37;
reg_cache_t *cache = malloc(sizeof(reg_cache_t));
reg_t *reg_list = malloc(sizeof(reg_t) * num_regs);
armv4_5_core_reg_t *arch_info = malloc(sizeof(reg_t) * num_regs);
int i;
cache->name = "arm v4/5 registers";
cache->next = NULL;
cache->reg_list = reg_list;
cache->num_regs = num_regs;
if (armv4_5_core_reg_arch_type == -1)
armv4_5_core_reg_arch_type = register_reg_arch_type(armv4_5_get_core_reg, armv4_5_set_core_reg);
for (i = 0; i < 37; i++)
{
arch_info[i] = armv4_5_core_reg_list_arch_info[i];
arch_info[i].target = target;
arch_info[i].armv4_5_common = armv4_5_common;
reg_list[i].name = armv4_5_core_reg_list[i];
reg_list[i].size = 32;
reg_list[i].value = calloc(1, 4);
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].bitfield_desc = NULL;
reg_list[i].num_bitfields = 0;
reg_list[i].arch_type = armv4_5_core_reg_arch_type;
reg_list[i].arch_info = &arch_info[i];
}
return cache;
}
int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size)
{
armv4_5_common_t *armv4_5 = target->arch_info;
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
ERROR("BUG: called for a non-ARMv4/5 target");
exit(-1);
}
snprintf(buf, buf_size,
"target halted in %s state due to %s, current mode: %s\ncpsr: 0x%8.8x pc: 0x%8.8x",
armv4_5_state_strings[armv4_5->core_state],
target_debug_reason_strings[target->debug_reason],
armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
return ERROR_OK;
}
int handle_armv4_5_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
char output[128];
int output_len;
int mode, num;
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5 = target->arch_info;
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
return ERROR_OK;
}
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "error: target must be halted for register accesses");
return ERROR_OK;
}
for (num = 0; num <= 15; num++)
{
output_len = 0;
for (mode = 0; mode < 6; mode++)
{
if (!ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).valid)
{
armv4_5->full_context(target);
}
output_len += snprintf(output + output_len, 128 - output_len, "%8s: %8.8x ", ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).name,
buf_get_u32(ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).value, 0, 32));
}
command_print(cmd_ctx, output);
}
command_print(cmd_ctx, " cpsr: %8.8x spsr_fiq: %8.8x spsr_irq: %8.8x spsr_svc: %8.8x spsr_abt: %8.8x spsr_und: %8.8x",
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_FIQ].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_IRQ].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_SVC].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_ABT].value, 0, 32),
buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_UND].value, 0, 32));
return ERROR_OK;
}
int handle_armv4_5_core_state_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
target_t *target = get_current_target(cmd_ctx);
armv4_5_common_t *armv4_5 = target->arch_info;
if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
{
command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
return ERROR_OK;
}
if (argc > 0)
{
if (strcmp(args[0], "arm") == 0)
{
armv4_5->core_state = ARMV4_5_STATE_ARM;
}
if (strcmp(args[0], "thumb") == 0)
{
armv4_5->core_state = ARMV4_5_STATE_THUMB;
}
}
command_print(cmd_ctx, "core state: %s", armv4_5_state_strings[armv4_5->core_state]);
return ERROR_OK;
}
int armv4_5_register_commands(struct command_context_s *cmd_ctx)
{
command_t *armv4_5_cmd;
armv4_5_cmd = register_command(cmd_ctx, NULL, "armv4_5", NULL, COMMAND_ANY, NULL);
register_command(cmd_ctx, armv4_5_cmd, "reg", handle_armv4_5_reg_command, COMMAND_EXEC, "display ARM core registers");
register_command(cmd_ctx, armv4_5_cmd, "core_state", handle_armv4_5_core_state_command, COMMAND_EXEC, "display/change ARM core state <arm|thumb>");
return ERROR_OK;
}
int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size)
{
armv4_5_common_t *armv4_5 = target->arch_info;
int i;
if (target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
*reg_list_size = 26;
*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
for (i = 0; i < 16; i++)
{
(*reg_list)[i] = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i);
}
for (i = 16; i < 24; i++)
{
(*reg_list)[i] = &armv4_5_gdb_dummy_fp_reg;
}
(*reg_list)[24] = &armv4_5_gdb_dummy_fps_reg;
(*reg_list)[25] = &armv4_5->core_cache->reg_list[ARMV4_5_CPSR];
return ERROR_OK;
}
int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
{
armv4_5_common_t *armv4_5 = target->arch_info;
armv4_5_algorithm_t *armv4_5_algorithm_info = arch_info;
enum armv4_5_state core_state = armv4_5->core_state;
enum armv4_5_mode core_mode = armv4_5->core_mode;
u32 context[17];
u32 cpsr;
int exit_breakpoint_size = 0;
int i;
int retval = ERROR_OK;
if (armv4_5_algorithm_info->common_magic != ARMV4_5_COMMON_MAGIC)
{
ERROR("current target isn't an ARMV4/5 target");
return ERROR_TARGET_INVALID;
}
if (target->state != TARGET_HALTED)
{
WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
for (i = 0; i <= 16; i++)
{
if (!ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid)
armv4_5->read_core_reg(target, i, armv4_5_algorithm_info->core_mode);
context[i] = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32);
}
cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32);
for (i = 0; i < num_mem_params; i++)
{
target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
}
for (i = 0; i < num_reg_params; i++)
{
reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
if (!reg)
{
ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
exit(-1);
}
if (reg->size != reg_params[i].size)
{
ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
exit(-1);
}
armv4_5_set_core_reg(reg, buf_get_u32(reg_params[i].value, 0, 32));
}
armv4_5->core_state = armv4_5_algorithm_info->core_state;
if (armv4_5->core_state == ARMV4_5_STATE_ARM)
exit_breakpoint_size = 4;
else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
exit_breakpoint_size = 2;
else
{
ERROR("BUG: can't execute algorithms when not in ARM or Thumb state");
exit(-1);
}
if (armv4_5_algorithm_info->core_mode != ARMV4_5_MODE_ANY)
{
DEBUG("setting core_mode: 0x%2.2x", armv4_5_algorithm_info->core_mode);
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 5, armv4_5_algorithm_info->core_mode);
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
}
if ((retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD)) != ERROR_OK)
{
ERROR("can't add breakpoint to finish algorithm execution");
return ERROR_TARGET_FAILURE;
}
target->type->resume(target, 0, entry_point, 1, 1);
target->type->poll(target);
while (target->state != TARGET_HALTED)
{
usleep(10000);
target->type->poll(target);
if ((timeout_ms -= 10) <= 0)
{
ERROR("timeout waiting for algorithm to complete, trying to halt target");
target->type->halt(target);
timeout_ms = 1000;
while (target->state != TARGET_HALTED)
{
usleep(10000);
target->type->poll(target);
if ((timeout_ms -= 10) <= 0)
{
ERROR("target didn't reenter debug state, exiting");
exit(-1);
}
}
retval = ERROR_TARGET_TIMEOUT;
}
}
breakpoint_remove(target, exit_point);
for (i = 0; i < num_mem_params; i++)
{
if (mem_params[i].direction != PARAM_OUT)
target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
}
for (i = 0; i < num_reg_params; i++)
{
if (reg_params[i].direction != PARAM_OUT)
{
reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
if (!reg)
{
ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
exit(-1);
}
if (reg->size != reg_params[i].size)
{
ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
exit(-1);
}
buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
}
}
for (i = 0; i <= 16; i++)
{
DEBUG("restoring register %s with value 0x%8.8x", ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).name, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32));
buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32, context[i]);
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid = 1;
ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).dirty = 1;
}
buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, cpsr);
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
armv4_5->core_state = core_state;
armv4_5->core_mode = core_mode;
return retval;
}
int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5)
{
target->arch_info = armv4_5;
armv4_5->common_magic = ARMV4_5_COMMON_MAGIC;
armv4_5->core_state = ARMV4_5_STATE_ARM;
armv4_5->core_mode = ARMV4_5_MODE_USR;
return ERROR_OK;
}

237
src/target/armv4_5.h Normal file
View File

@@ -0,0 +1,237 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_H
#define ARMV4_5_H
#include "register.h"
#include "target.h"
enum armv4_5_mode
{
ARMV4_5_MODE_USR = 16,
ARMV4_5_MODE_FIQ = 17,
ARMV4_5_MODE_IRQ = 18,
ARMV4_5_MODE_SVC = 19,
ARMV4_5_MODE_ABT = 23,
ARMV4_5_MODE_UND = 27,
ARMV4_5_MODE_SYS = 31,
ARMV4_5_MODE_ANY = -1
};
extern char* armv4_5_mode_strings[];
enum armv4_5_state
{
ARMV4_5_STATE_ARM,
ARMV4_5_STATE_THUMB,
ARMV4_5_STATE_JAZELLE,
};
extern char* armv4_5_state_strings[];
extern int armv4_5_core_reg_map[7][17];
#define ARMV4_5_CORE_REG_MODE(cache, mode, num) \
cache->reg_list[armv4_5_core_reg_map[armv4_5_mode_to_number(mode)][num]]
#define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \
cache->reg_list[armv4_5_core_reg_map[mode][num]]
/* offsets into armv4_5 core register cache */
enum
{
ARMV4_5_CPSR = 31,
ARMV4_5_SPSR_FIQ = 32,
ARMV4_5_SPSR_IRQ = 33,
ARMV4_5_SPSR_SVC = 34,
ARMV4_5_SPSR_ABT = 35,
ARMV4_5_SPSR_UND = 36
};
#define ARMV4_5_COMMON_MAGIC 0x0A450A45
typedef struct armv4_5_common_s
{
int common_magic;
reg_cache_t *core_cache;
enum armv4_5_mode core_mode;
enum armv4_5_state core_state;
int (*full_context)(struct target_s *target);
int (*read_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode);
int (*write_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode, u32 value);
void *arch_info;
} armv4_5_common_t;
typedef struct armv4_5_algorithm_s
{
int common_magic;
enum armv4_5_mode core_mode;
enum armv4_5_state core_state;
} armv4_5_algorithm_t;
typedef struct armv4_5_core_reg_s
{
int num;
enum armv4_5_mode mode;
target_t *target;
armv4_5_common_t *armv4_5_common;
} armv4_5_core_reg_t;
extern reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common);
extern enum armv4_5_mode armv4_5_number_to_mode(int number);
extern int armv4_5_mode_to_number(enum armv4_5_mode mode);
extern int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size);
extern int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size);
extern int armv4_5_invalidate_core_regs(target_t *target);
extern int armv4_5_register_commands(struct command_context_s *cmd_ctx);
extern int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5);
extern int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
extern int armv4_5_invalidate_core_regs(target_t *target);
/* ARM mode instructions
*/
/* Store multiple increment after
* Rn: base register
* List: for each bit in list: store register
* S: in priviledged mode: store user-mode registers
* W=1: update the base register. W=0: leave the base register untouched
*/
#define ARMV4_5_STMIA(Rn, List, S, W) (0xe8800000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
/* Load multiple increment after
* Rn: base register
* List: for each bit in list: store register
* S: in priviledged mode: store user-mode registers
* W=1: update the base register. W=0: leave the base register untouched
*/
#define ARMV4_5_LDMIA(Rn, List, S, W) (0xe8900000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
/* MOV r8, r8 */
#define ARMV4_5_NOP (0xe1a08008)
/* Move PSR to general purpose register
* R=1: SPSR R=0: CPSR
* Rn: target register
*/
#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | (R << 22) | (Rn << 12))
/* Store register
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | (Rd << 12) | (Rn << 16))
/* Load register
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | (Rd << 12) | (Rn << 16))
/* Move general purpose register to PSR
* R=1: SPSR R=0: CPSR
* Field: Field mask
* 1: control field 2: extension field 4: status field 8: flags field
* Rm: source register
*/
#define ARMV4_5_MSR_GP(Rm, Field, R) (0xe120f000 | Rm | (Field << 16) | (R << 22))
#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) (0xe320f000 | (Im) | (Rotate << 8) | (Field << 16) | (R << 22))
/* Load Register Halfword Immediate Post-Index
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | (Rd << 12) | (Rn << 16))
/* Load Register Byte Immediate Post-Index
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | (Rd << 12) | (Rn << 16))
/* Store register Halfword Immediate Post-Index
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | (Rd << 12) | (Rn << 16))
/* Store register Byte Immediate Post-Index
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | (Rd << 12) | (Rn << 16))
/* Branch (and Link)
* Im: Branch target (left-shifted by 2 bits, added to PC)
* L: 1: branch and link 0: branch only
*/
#define ARMV4_5_B(Im, L) (0xea000000 | Im | (L << 24))
/* Branch and exchange (ARM state)
* Rm: register holding branch target address
*/
#define ARMV4_5_BX(Rm) (0xe12fff10 | Rm)
/* Thumb mode instructions
*/
/* Store register (Thumb mode)
* Rd: source register
* Rn: base register
*/
#define ARMV4_5_T_STR(Rd, Rn) ((0x6000 | Rd | (Rn << 3)) | ((0x6000 | Rd | (Rn << 3)) << 16))
/* Load register (Thumb state)
* Rd: destination register
* Rn: base register
*/
#define ARMV4_5_T_LDR(Rd, Rn) ((0x6800 | (Rn << 3) | Rd) | ((0x6800 | (Rn << 3) | Rd) << 16))
/* Move hi register (Thumb mode)
* Rd: destination register
* Rm: source register
*/
#define ARMV4_5_T_MOV(Rd, Rm) ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) | ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) << 16))
/* No operation (Thumb mode)
*/
#define ARMV4_5_T_NOP (0x1c3f | (0x1c3f << 16))
/* Move immediate to register (Thumb state)
* Rd: destination register
* Im: 8-bit immediate value
*/
#define ARMV4_5_T_MOV_IM(Rd, Im) ((0x2000 | (Rd << 8) | Im) | ((0x2000 | (Rd << 8) | Im) << 16))
/* Branch and Exchange
* Rm: register containing branch target
*/
#define ARMV4_5_T_BX(Rm) ((0x4700 | (Rm << 3)) | ((0x4700 | (Rm << 3)) << 16))
/* Branch (Thumb state)
* Imm: Branch target
*/
#define ARMV4_5_T_B(Imm) ((0xe000 | Imm) | ((0xe000 | Imm) << 16))
#endif /* ARMV4_5_H */

112
src/target/armv4_5_cache.c Normal file
View File

@@ -0,0 +1,112 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "armv4_5_cache.h"
#include "log.h"
#include "command.h"
int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache)
{
int size, assoc, M, len, multiplier;
cache->ctype = (cache_type_reg & 0x1e000000U) >> 25;
cache->separate = (cache_type_reg & 0x01000000U) >> 24;
size = (cache_type_reg & 0x1c0000) >> 18;
assoc = (cache_type_reg & 0x38000) >> 15;
M = (cache_type_reg & 0x4000) >> 14;
len = (cache_type_reg & 0x3000) >> 12;
multiplier = 2 + M;
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
{
/* cache is present */
cache->d_u_size.linelen = 1 << (len + 3);
cache->d_u_size.associativity = multiplier << (assoc - 1);
cache->d_u_size.nsets = 1 << (size + 6 - assoc - len);
cache->d_u_size.cachesize = multiplier << (size + 8);
}
else
{
/* cache is absent */
cache->d_u_size.linelen = -1;
cache->d_u_size.associativity = -1;
cache->d_u_size.nsets = -1;
cache->d_u_size.cachesize = -1;
}
if (cache->separate)
{
size = (cache_type_reg & 0x1c0) >> 6;
assoc = (cache_type_reg & 0x38) >> 3;
M = (cache_type_reg & 0x4) >> 2;
len = (cache_type_reg & 0x3);
multiplier = 2 + M;
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
{
/* cache is present */
cache->i_size.linelen = 1 << (len + 3);
cache->i_size.associativity = multiplier << (assoc - 1);
cache->i_size.nsets = 1 << (size + 6 - assoc - len);
cache->i_size.cachesize = multiplier << (size + 8);
}
else
{
/* cache is absent */
cache->i_size.linelen = -1;
cache->i_size.associativity = -1;
cache->i_size.nsets = -1;
cache->i_size.cachesize = -1;
}
}
else
{
cache->i_size = cache->d_u_size;
}
return ERROR_OK;
}
int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache)
{
if (armv4_5_cache->ctype == -1)
{
command_print(cmd_ctx, "cache not yet identified");
return ERROR_OK;
}
command_print(cmd_ctx, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype,
(armv4_5_cache->separate) ? "separate caches" : "unified cache");
command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
armv4_5_cache->d_u_size.linelen,
armv4_5_cache->d_u_size.associativity,
armv4_5_cache->d_u_size.nsets,
armv4_5_cache->d_u_size.cachesize);
command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
armv4_5_cache->i_size.linelen,
armv4_5_cache->i_size.associativity,
armv4_5_cache->i_size.nsets,
armv4_5_cache->i_size.cachesize);
return ERROR_OK;
}

View File

@@ -0,0 +1,49 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_CACHE_H
#define ARMV4_5_CACHE_H
#include "types.h"
#include "command.h"
typedef struct armv4_5_cachesize_s
{
int linelen;
int associativity;
int nsets;
int cachesize;
} armv4_5_cachesize_t;
typedef struct armv4_5_cache_common_s
{
int ctype; /* specify supported cache operations */
int separate; /* separate caches or unified cache */
armv4_5_cachesize_t d_u_size; /* data cache */
armv4_5_cachesize_t i_size; /* instruction cache */
int i_cache_enabled;
int d_u_cache_enabled;
} armv4_5_cache_common_t;
extern int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache);
extern int armv4_5_cache_state(u32 cp15_control_reg, armv4_5_cache_common_t *cache);
extern int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache);
#endif /* ARMV4_5_CACHE_H */

358
src/target/armv4_5_mmu.c Normal file
View File

@@ -0,0 +1,358 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "arm7_9_common.h"
#include "log.h"
#include "command.h"
#include "armv4_5_mmu.h"
#include <stdlib.h>
u32 armv4mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
char* armv4_5_mmu_page_type_names[] =
{
"section", "large page", "small page", "tiny page"
};
u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap)
{
u32 first_lvl_descriptor = 0x0;
u32 second_lvl_descriptor = 0x0;
u32 ttb = armv4_5_mmu->get_ttb(target);
armv4_5_mmu_read_physical(target, armv4_5_mmu,
(ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
4, 1, (u8*)&first_lvl_descriptor);
DEBUG("1st lvl desc: %8.8x", first_lvl_descriptor);
if ((first_lvl_descriptor & 0x3) == 0)
{
*type = -1;
return ERROR_TARGET_TRANSLATION_FAULT;
}
if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3))
{
*type = -1;
return ERROR_TARGET_TRANSLATION_FAULT;
}
/* domain is always specified in bits 8-5 */
*domain = (first_lvl_descriptor & 0x1e0) >> 5;
if ((first_lvl_descriptor & 0x3) == 2)
{
/* section descriptor */
*type = ARMV4_5_SECTION;
*cb = (first_lvl_descriptor & 0xc) >> 2;
*ap = (first_lvl_descriptor & 0xc00) >> 10;
return (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
}
if ((first_lvl_descriptor & 0x3) == 1)
{
/* coarse page table */
armv4_5_mmu_read_physical(target, armv4_5_mmu,
(first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
4, 1, (u8*)&second_lvl_descriptor);
}
if ((first_lvl_descriptor & 0x3) == 3)
{
/* fine page table */
armv4_5_mmu_read_physical(target, armv4_5_mmu,
(first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
4, 1, (u8*)&second_lvl_descriptor);
}
DEBUG("2nd lvl desc: %8.8x", first_lvl_descriptor);
if ((second_lvl_descriptor & 0x3) == 0)
{
*type = -1;
return ERROR_TARGET_TRANSLATION_FAULT;
}
/* cacheable/bufferable is always specified in bits 3-2 */
*cb = (second_lvl_descriptor & 0xc) >> 2;
if ((second_lvl_descriptor & 0x3) == 1)
{
/* large page descriptor */
*type = ARMV4_5_LARGE_PAGE;
*ap = (second_lvl_descriptor & 0xff0) >> 4;
return (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
}
if ((second_lvl_descriptor & 0x3) == 2)
{
/* small page descriptor */
*type = ARMV4_5_SMALL_PAGE;
*ap = (second_lvl_descriptor & 0xff0) >> 4;
return (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
}
if ((second_lvl_descriptor & 0x3) == 3)
{
/* tiny page descriptor */
*type = ARMV4_5_TINY_PAGE;
*ap = (second_lvl_descriptor & 0x30) >> 4;
return (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
}
/* should not happen */
*type = -1;
return ERROR_TARGET_TRANSLATION_FAULT;
}
int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
/* disable MMU and data (or unified) cache */
armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
/* reenable MMU / cache */
armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
return retval;
}
int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
{
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
/* disable MMU and data (or unified) cache */
armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
/* reenable MMU / cache */
armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
return retval;
}
int armv4_5_mmu_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
{
u32 va;
u32 pa;
int type;
u32 cb;
int domain;
u32 ap;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"virt2phys\" command");
return ERROR_OK;
}
if (argc == 0)
{
command_print(cmd_ctx, "usage: virt2phys <virtual address>");
return ERROR_OK;
}
if (argc == 1)
{
va = strtoul(args[0], NULL, 0);
pa = armv4_5_mmu_translate_va(target, armv4_5_mmu, va, &type, &cb, &domain, &ap);
if (type == -1)
{
switch (pa)
{
case ERROR_TARGET_TRANSLATION_FAULT:
command_print(cmd_ctx, "no valid translation for 0x%8.8x", va);
break;
default:
command_print(cmd_ctx, "unknown translation error");
}
return ERROR_OK;
}
command_print(cmd_ctx, "0x%8.8x -> 0x%8.8x, type: %s, cb: %i, domain: %i, ap: %2.2x",
va, pa, armv4_5_mmu_page_type_names[type], cb, domain, ap);
}
return ERROR_OK;
}
int armv4_5_mmu_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
{
int count = 1;
int size = 4;
u32 address = 0;
int i;
char output[128];
int output_len;
int retval;
u8 *buffer;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
if (argc < 1)
return ERROR_OK;
if (argc == 2)
count = strtoul(args[1], NULL, 0);
address = strtoul(args[0], NULL, 0);
switch (cmd[2])
{
case 'w':
size = 4;
break;
case 'h':
size = 2;
break;
case 'b':
size = 1;
break;
default:
return ERROR_OK;
}
buffer = calloc(count, size);
if ((retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, address, size, count, buffer)) != ERROR_OK)
{
switch (retval)
{
case ERROR_TARGET_UNALIGNED_ACCESS:
command_print(cmd_ctx, "error: address not aligned");
break;
case ERROR_TARGET_NOT_HALTED:
command_print(cmd_ctx, "error: target must be halted for memory accesses");
break;
case ERROR_TARGET_DATA_ABORT:
command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
break;
default:
command_print(cmd_ctx, "error: unknown error");
}
}
output_len = 0;
for (i = 0; i < count; i++)
{
if (i%8 == 0)
output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
switch (size)
{
case 4:
output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", ((u32*)buffer)[i]);
break;
case 2:
output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", ((u16*)buffer)[i]);
break;
case 1:
output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", ((u8*)buffer)[i]);
break;
}
if ((i%8 == 7) || (i == count - 1))
{
command_print(cmd_ctx, output);
output_len = 0;
}
}
free(buffer);
return ERROR_OK;
}
int armv4_5_mmu_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
{
u32 address = 0;
u32 value = 0;
int retval;
if (target->state != TARGET_HALTED)
{
command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
return ERROR_OK;
}
if (argc < 2)
return ERROR_OK;
address = strtoul(args[0], NULL, 0);
value = strtoul(args[1], NULL, 0);
switch (cmd[2])
{
case 'w':
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 4, 1, (u8*)&value);
break;
case 'h':
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 2, 1, (u8*)&value);
break;
case 'b':
retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 1, 1, (u8*)&value);
break;
default:
return ERROR_OK;
}
switch (retval)
{
case ERROR_TARGET_UNALIGNED_ACCESS:
command_print(cmd_ctx, "error: address not aligned");
break;
case ERROR_TARGET_DATA_ABORT:
command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
break;
case ERROR_TARGET_NOT_HALTED:
command_print(cmd_ctx, "error: target must be halted for memory accesses");
break;
case ERROR_OK:
break;
default:
command_print(cmd_ctx, "error: unknown error");
}
return ERROR_OK;
}

52
src/target/armv4_5_mmu.h Normal file
View File

@@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_MMU_H
#define ARMV4_5_MMU_H
#include "armv4_5_cache.h"
typedef struct armv4_5_mmu_common_s
{
u32 (*get_ttb)(target_t *target);
int (*read_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
int (*write_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
void (*disable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
void (*enable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
armv4_5_cache_common_t armv4_5_cache;
int has_tiny_pages;
int mmu_enabled;
} armv4_5_mmu_common_t;
enum
{
ARMV4_5_SECTION, ARMV4_5_LARGE_PAGE, ARMV4_5_SMALL_PAGE, ARMV4_5_TINY_PAGE
};
extern char* armv4_5_page_type_names[];
extern u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
extern int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
extern int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
extern int armv4_5_mmu_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
extern int armv4_5_mmu_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
extern int armv4_5_mmu_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
#endif /* ARMV4_5_MMU_H */

219
src/target/breakpoints.c Normal file
View File

@@ -0,0 +1,219 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include <stdlib.h>
#include "binarybuffer.h"
#include "target.h"
#include "log.h"
#include "types.h"
#include "breakpoints.h"
char *breakpoint_type_strings[] =
{
"hardware",
"software"
};
char *watchpoint_rw_strings[] =
{
"read",
"write",
"access"
};
int breakpoint_add(target_t *target, u32 address, u32 length, enum breakpoint_type type)
{
breakpoint_t *breakpoint = target->breakpoints;
breakpoint_t **breakpoint_p = &target->breakpoints;
int retval;
while (breakpoint)
{
if (breakpoint->address == address)
return ERROR_OK;
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
if ((retval = target->type->add_breakpoint(target, address, length, type)) != ERROR_OK)
{
switch (retval)
{
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
INFO("can't add %s breakpoint, resource not available", breakpoint_type_strings[type]);
return retval;
break;
case ERROR_TARGET_NOT_HALTED:
INFO("can't add breakpoint while target is running");
return retval;
break;
default:
ERROR("unknown error");
exit(-1);
break;
}
}
(*breakpoint_p) = malloc(sizeof(breakpoint_t));
(*breakpoint_p)->address = address;
(*breakpoint_p)->length = length;
(*breakpoint_p)->type = type;
(*breakpoint_p)->set = 0;
(*breakpoint_p)->orig_instr = malloc(CEIL(length, 8));
(*breakpoint_p)->next = NULL;
DEBUG("added %s breakpoint at 0x%8.8x of length 0x%8.8x", breakpoint_type_strings[type], address, length);
return ERROR_OK;
}
int breakpoint_remove(target_t *target, u32 address)
{
breakpoint_t *breakpoint = target->breakpoints;
breakpoint_t **breakpoint_p = &target->breakpoints;
int retval;
while (breakpoint)
{
if (breakpoint->address == address)
break;
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
if (breakpoint)
{
if ((retval = target->type->remove_breakpoint(target, breakpoint)) != ERROR_OK)
{
switch (retval)
{
case ERROR_TARGET_NOT_HALTED:
INFO("can't remove breakpoint while target is running");
return retval;
break;
default:
ERROR("unknown error");
exit(-1);
break;
}
}
(*breakpoint_p) = breakpoint->next;
free(breakpoint->orig_instr);
free(breakpoint);
}
else
{
ERROR("no breakpoint at address 0x%8.8x found", address);
}
return ERROR_OK;
}
breakpoint_t* breakpoint_find(target_t *target, u32 address)
{
breakpoint_t *breakpoint = target->breakpoints;
while (breakpoint)
{
if (breakpoint->address == address)
return breakpoint;
breakpoint = breakpoint->next;
}
return NULL;
}
int watchpoint_add(target_t *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask)
{
watchpoint_t *watchpoint = target->watchpoints;
watchpoint_t **watchpoint_p = &target->watchpoints;
int retval;
while (watchpoint)
{
if (watchpoint->address == address)
return ERROR_OK;
watchpoint_p = &watchpoint->next;
watchpoint = watchpoint->next;
}
if ((retval = target->type->add_watchpoint(target, address, length, rw)) != ERROR_OK)
{
switch (retval)
{
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
INFO("can't add %s watchpoint, resource not available", watchpoint_rw_strings[rw]);
return retval;
break;
default:
ERROR("unknown error");
exit(-1);
break;
}
}
(*watchpoint_p) = malloc(sizeof(watchpoint_t));
(*watchpoint_p)->address = address;
(*watchpoint_p)->length = length;
(*watchpoint_p)->value = value;
(*watchpoint_p)->mask = mask;
(*watchpoint_p)->rw = rw;
(*watchpoint_p)->set = 0;
(*watchpoint_p)->next = NULL;
DEBUG("added %s watchpoint at 0x%8.8x of length 0x%8.8x", watchpoint_rw_strings[rw], address, length);
return ERROR_OK;
}
int watchpoint_remove(target_t *target, u32 address)
{
watchpoint_t *watchpoint = target->watchpoints;
watchpoint_t **watchpoint_p = &target->watchpoints;
int retval;
while (watchpoint)
{
if (watchpoint->address == address)
break;
watchpoint_p = &watchpoint->next;
watchpoint = watchpoint->next;
}
if (watchpoint)
{
if ((retval = target->type->remove_watchpoint(target, watchpoint)) != ERROR_OK)
{
ERROR("BUG: can't remove watchpoint");
exit(-1);
}
(*watchpoint_p) = watchpoint->next;
free(watchpoint);
}
else
{
ERROR("no watchpoint at address 0x%8.8x found", address);
}
return ERROR_OK;
}

70
src/target/breakpoints.h Normal file
View File

@@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef BREAKPOINTS_H
#define BREAKPOINTS_H
#include "target.h"
struct target_s;
enum breakpoint_type
{
BKPT_HARD,
BKPT_SOFT,
};
extern char *breakpoint_type_strings[];
enum watchpoint_rw
{
WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2
};
extern char *watchpoint_rw_strings[];
typedef struct breakpoint_s
{
u32 address;
int length;
enum breakpoint_type type;
int set;
u8 *orig_instr;
struct breakpoint_s *next;
} breakpoint_t;
typedef struct watchpoint_s
{
u32 address;
int length;
u32 mask;
u32 value;
enum watchpoint_rw rw;
int set;
struct watchpoint_s *next;
} watchpoint_t;
extern int breakpoint_add(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
extern int breakpoint_remove(struct target_s *target, u32 address);
extern breakpoint_t* breakpoint_find(struct target_s *target, u32 address);
extern int watchpoint_add(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask);
extern int watchpoint_remove(struct target_s *target, u32 address);
#endif /* BREAKPOINTS_H */

301
src/target/embeddedice.c Normal file
View File

@@ -0,0 +1,301 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "embeddedice.h"
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "log.h"
#include "arm_jtag.h"
#include "types.h"
#include "binarybuffer.h"
#include "target.h"
#include "register.h"
#include "jtag.h"
#include <stdlib.h>
bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] =
{
{"R", 1},
{"W", 1},
{"reserved", 26},
{"version", 4}
};
int embeddedice_reg_arch_info[] =
{
0x0, 0x1, 0x4, 0x5,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15
};
char* embeddedice_reg_list[] =
{
"debug_ctrl",
"debug_status",
"comms_ctrl",
"comms_data",
"watch 0 addr value",
"watch 0 addr mask",
"watch 0 data value",
"watch 0 data mask",
"watch 0 control value",
"watch 0 control mask",
"watch 1 addr value",
"watch 1 addr mask",
"watch 1 data value",
"watch 1 data mask",
"watch 1 control value",
"watch 1 control mask"
};
int embeddedice_reg_arch_type = -1;
int embeddedice_get_reg(reg_t *reg);
int embeddedice_set_reg(reg_t *reg, u32 value);
int embeddedice_write_reg(reg_t *reg, u32 value);
int embeddedice_read_reg(reg_t *reg);
reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
{
reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
reg_t *reg_list = NULL;
embeddedice_reg_t *arch_info = NULL;
int num_regs = 16 + extra_reg;
int i;
/* register a register arch-type for EmbeddedICE registers only once */
if (embeddedice_reg_arch_type == -1)
embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec);
/* the actual registers are kept in two arrays */
reg_list = calloc(num_regs, sizeof(reg_t));
arch_info = calloc(num_regs, sizeof(embeddedice_reg_t));
/* fill in values for the reg cache */
reg_cache->name = "EmbeddedICE registers";
reg_cache->next = NULL;
reg_cache->reg_list = reg_list;
reg_cache->num_regs = num_regs;
/* set up registers */
for (i = 0; i < num_regs - extra_reg; i++)
{
reg_list[i].name = embeddedice_reg_list[i];
reg_list[i].size = 32;
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].bitfield_desc = NULL;
reg_list[i].num_bitfields = 0;
reg_list[i].value = calloc(1, 4);
reg_list[i].arch_info = &arch_info[i];
reg_list[i].arch_type = embeddedice_reg_arch_type;
arch_info[i].addr = embeddedice_reg_arch_info[i];
arch_info[i].jtag_info = jtag_info;
}
/* there may be one extra reg (Abort status (ARM7 rev4) or Vector catch (ARM9)) */
if (extra_reg)
{
reg_list[num_regs - 1].arch_info = &arch_info[num_regs - 1];
arch_info[num_regs - 1].jtag_info = jtag_info;
}
return reg_cache;
}
int embeddedice_get_reg(reg_t *reg)
{
if (embeddedice_read_reg(reg) != ERROR_OK)
{
ERROR("BUG: error scheduling EmbeddedICE register read");
exit(-1);
}
if (jtag_execute_queue() != ERROR_OK)
{
ERROR("register read failed");
}
return ERROR_OK;
}
int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
{
embeddedice_reg_t *ice_reg = reg->arch_info;
u8 reg_addr = ice_reg->addr & 0x1f;
scan_field_t fields[3];
DEBUG("%i", ice_reg->addr);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(ice_reg->jtag_info, 0x2);
arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
fields[0].device = ice_reg->jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = reg->value;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = ice_reg->jtag_info->chain_pos;
fields[1].num_bits = 5;
fields[1].out_value = malloc(1);
buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = ice_reg->jtag_info->chain_pos;
fields[2].num_bits = 1;
fields[2].out_value = malloc(1);
buf_set_u32(fields[2].out_value, 0, 1, 0);
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
fields[0].in_value = reg->value;
fields[0].in_check_value = check_value;
fields[0].in_check_mask = check_mask;
/* when reading the DCC data register, leaving the address field set to
* EICE_COMMS_DATA would read the register twice
* reading the control register is safe
*/
buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
jtag_add_dr_scan(3, fields, -1);
free(fields[1].out_value);
free(fields[2].out_value);
return ERROR_OK;
}
int embeddedice_read_reg(reg_t *reg)
{
return embeddedice_read_reg_w_check(reg, NULL, NULL);
}
int embeddedice_set_reg(reg_t *reg, u32 value)
{
if (embeddedice_write_reg(reg, value) != ERROR_OK)
{
ERROR("BUG: error scheduling EmbeddedICE register write");
exit(-1);
}
buf_set_u32(reg->value, 0, reg->size, value);
reg->valid = 1;
reg->dirty = 0;
return ERROR_OK;
}
int embeddedice_set_reg_w_exec(reg_t *reg, u32 value)
{
embeddedice_set_reg(reg, value);
if (jtag_execute_queue() != ERROR_OK)
{
ERROR("register write failed");
exit(-1);
}
return ERROR_OK;
}
int embeddedice_write_reg(reg_t *reg, u32 value)
{
embeddedice_reg_t *ice_reg = reg->arch_info;
u8 reg_addr = ice_reg->addr & 0x1f;
scan_field_t fields[3];
DEBUG("%i: 0x%8.8x", ice_reg->addr, value);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(ice_reg->jtag_info, 0x2);
arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
fields[0].device = ice_reg->jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = malloc(4);
buf_set_u32(fields[0].out_value, 0, 32, value);
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = ice_reg->jtag_info->chain_pos;
fields[1].num_bits = 5;
fields[1].out_value = malloc(1);
buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = ice_reg->jtag_info->chain_pos;
fields[2].num_bits = 1;
fields[2].out_value = malloc(1);
buf_set_u32(fields[2].out_value, 0, 1, 1);
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
free(fields[0].out_value);
free(fields[1].out_value);
free(fields[2].out_value);
return ERROR_OK;
}
int embeddedice_store_reg(reg_t *reg)
{
return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
}

90
src/target/embeddedice.h Normal file
View File

@@ -0,0 +1,90 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EMBEDDED_ICE_H
#define EMBEDDED_ICE_H
#include "target.h"
#include "register.h"
#include "arm_jtag.h"
enum
{
EICE_DBG_CTRL = 0,
EICE_DBG_STAT = 1,
EICE_COMMS_CTRL = 2,
EICE_COMMS_DATA = 3,
EICE_W0_ADDR_VALUE = 4,
EICE_W0_ADDR_MASK = 5,
EICE_W0_DATA_VALUE = 6,
EICE_W0_DATA_MASK = 7,
EICE_W0_CONTROL_VALUE = 8,
EICE_W0_CONTROL_MASK = 9,
EICE_W1_ADDR_VALUE = 10,
EICE_W1_ADDR_MASK = 11,
EICE_W1_DATA_VALUE = 12,
EICE_W1_DATA_MASK = 13,
EICE_W1_CONTROL_VALUE = 14,
EICE_W1_CONTROL_MASK = 15
};
enum
{
EICE_DBG_CONTROL_INTDIS = 2,
EICE_DBG_CONTROL_DBGRQ = 1,
EICE_DBG_CONTROL_DBGACK = 0,
};
enum
{
EICE_DBG_STATUS_ITBIT = 4,
EICE_DBG_STATUS_SYSCOMP = 3,
EICE_DBG_STATUS_IFEN = 2,
EICE_DBG_STATUS_DBGRQ = 1,
EICE_DBG_STATUS_DBGACK = 0
};
enum
{
EICE_W_CTRL_ENABLE = 0x100,
EICE_W_CTRL_RANGE = 0x80,
EICE_W_CTRL_CHAIN = 0x40,
EICE_W_CTRL_EXTERN = 0x20,
EICE_W_CTRL_nTRANS = 0x10,
EICE_W_CTRL_nOPC = 0x8,
EICE_W_CTRL_MAS = 0x6,
EICE_W_CTRL_ITBIT = 0x2,
EICE_W_CTRL_nRW = 0x1
};
typedef struct embeddedice_reg_s
{
int addr;
arm_jtag_t *jtag_info;
} embeddedice_reg_t;
extern reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
extern int embeddedice_read_reg(reg_t *reg);
extern int embeddedice_write_reg(reg_t *reg, u32 value);
extern int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
extern int embeddedice_store_reg(reg_t *reg);
extern int embeddedice_set_reg(reg_t *reg, u32 value);
extern int embeddedice_set_reg_w_exec(reg_t *reg, u32 value);
#endif /* EMBEDDED_ICE_H */

409
src/target/etm.c Normal file
View File

@@ -0,0 +1,409 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "config.h"
#include "etm.h"
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "log.h"
#include "arm_jtag.h"
#include "types.h"
#include "binarybuffer.h"
#include "target.h"
#include "register.h"
#include "jtag.h"
#include <stdlib.h>
bitfield_desc_t etm_comms_ctrl_bitfield_desc[] =
{
{"R", 1},
{"W", 1},
{"reserved", 26},
{"version", 4}
};
int etm_reg_arch_info[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
};
int etm_reg_arch_size_info[] =
{
32, 32, 17, 8, 3, 9, 32, 17,
26, 16, 25, 8, 17, 32, 32, 17,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
16, 16, 16, 16, 18, 18, 18, 18,
17, 17, 17, 17, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 2,
17, 17, 17, 17, 32, 32, 32, 32
};
char* etm_reg_list[] =
{
"ETM_CTRL",
"ETM_CONFIG",
"ETM_TRIG_EVENT",
"ETM_MMD_CTRL",
"ETM_STATUS",
"ETM_SYS_CONFIG",
"ETM_TRACE_RESOURCE_CTRL",
"ETM_TRACE_EN_CTRL2",
"ETM_TRACE_EN_EVENT",
"ETM_TRACE_EN_CTRL1",
"ETM_FIFOFULL_REGION",
"ETM_FIFOFULL_LEVEL",
"ETM_VIEWDATA_EVENT",
"ETM_VIEWDATA_CTRL1",
"ETM_VIEWDATA_CTRL2",
"ETM_VIEWDATA_CTRL3",
"ETM_ADDR_COMPARATOR_VALUE1",
"ETM_ADDR_COMPARATOR_VALUE2",
"ETM_ADDR_COMPARATOR_VALUE3",
"ETM_ADDR_COMPARATOR_VALUE4",
"ETM_ADDR_COMPARATOR_VALUE5",
"ETM_ADDR_COMPARATOR_VALUE6",
"ETM_ADDR_COMPARATOR_VALUE7",
"ETM_ADDR_COMPARATOR_VALUE8",
"ETM_ADDR_COMPARATOR_VALUE9",
"ETM_ADDR_COMPARATOR_VALUE10",
"ETM_ADDR_COMPARATOR_VALUE11",
"ETM_ADDR_COMPARATOR_VALUE12",
"ETM_ADDR_COMPARATOR_VALUE13",
"ETM_ADDR_COMPARATOR_VALUE14",
"ETM_ADDR_COMPARATOR_VALUE15",
"ETM_ADDR_COMPARATOR_VALUE16",
"ETM_ADDR_ACCESS_TYPE1",
"ETM_ADDR_ACCESS_TYPE2",
"ETM_ADDR_ACCESS_TYPE3",
"ETM_ADDR_ACCESS_TYPE4",
"ETM_ADDR_ACCESS_TYPE5",
"ETM_ADDR_ACCESS_TYPE6",
"ETM_ADDR_ACCESS_TYPE7",
"ETM_ADDR_ACCESS_TYPE8",
"ETM_ADDR_ACCESS_TYPE9",
"ETM_ADDR_ACCESS_TYPE10",
"ETM_ADDR_ACCESS_TYPE11",
"ETM_ADDR_ACCESS_TYPE12",
"ETM_ADDR_ACCESS_TYPE13",
"ETM_ADDR_ACCESS_TYPE14",
"ETM_ADDR_ACCESS_TYPE15",
"ETM_ADDR_ACCESS_TYPE16",
"ETM_DATA_COMPARATOR_VALUE1",
"ETM_DATA_COMPARATOR_VALUE2",
"ETM_DATA_COMPARATOR_VALUE3",
"ETM_DATA_COMPARATOR_VALUE4",
"ETM_DATA_COMPARATOR_VALUE5",
"ETM_DATA_COMPARATOR_VALUE6",
"ETM_DATA_COMPARATOR_VALUE7",
"ETM_DATA_COMPARATOR_VALUE8",
"ETM_DATA_COMPARATOR_VALUE9",
"ETM_DATA_COMPARATOR_VALUE10",
"ETM_DATA_COMPARATOR_VALUE11",
"ETM_DATA_COMPARATOR_VALUE12",
"ETM_DATA_COMPARATOR_VALUE13",
"ETM_DATA_COMPARATOR_VALUE14",
"ETM_DATA_COMPARATOR_VALUE15",
"ETM_DATA_COMPARATOR_VALUE16",
"ETM_DATA_COMPARATOR_MASK1",
"ETM_DATA_COMPARATOR_MASK2",
"ETM_DATA_COMPARATOR_MASK3",
"ETM_DATA_COMPARATOR_MASK4",
"ETM_DATA_COMPARATOR_MASK5",
"ETM_DATA_COMPARATOR_MASK6",
"ETM_DATA_COMPARATOR_MASK7",
"ETM_DATA_COMPARATOR_MASK8",
"ETM_DATA_COMPARATOR_MASK9",
"ETM_DATA_COMPARATOR_MASK10",
"ETM_DATA_COMPARATOR_MASK11",
"ETM_DATA_COMPARATOR_MASK12",
"ETM_DATA_COMPARATOR_MASK13",
"ETM_DATA_COMPARATOR_MASK14",
"ETM_DATA_COMPARATOR_MASK15",
"ETM_DATA_COMPARATOR_MASK16",
"ETM_COUNTER_INITAL_VALUE1",
"ETM_COUNTER_INITAL_VALUE2",
"ETM_COUNTER_INITAL_VALUE3",
"ETM_COUNTER_INITAL_VALUE4",
"ETM_COUNTER_ENABLE1",
"ETM_COUNTER_ENABLE2",
"ETM_COUNTER_ENABLE3",
"ETM_COUNTER_ENABLE4",
"ETM_COUNTER_RELOAD_VALUE1",
"ETM_COUNTER_RELOAD_VALUE2",
"ETM_COUNTER_RELOAD_VALUE3",
"ETM_COUNTER_RELOAD_VALUE4",
"ETM_COUNTER_VALUE1",
"ETM_COUNTER_VALUE2",
"ETM_COUNTER_VALUE3",
"ETM_COUNTER_VALUE4",
"ETM_SEQUENCER_CTRL1",
"ETM_SEQUENCER_CTRL2",
"ETM_SEQUENCER_CTRL3",
"ETM_SEQUENCER_CTRL4",
"ETM_SEQUENCER_CTRL5",
"ETM_SEQUENCER_CTRL6",
"ETM_SEQUENCER_STATE",
"ETM_EXTERNAL_OUTPUT1",
"ETM_EXTERNAL_OUTPUT2",
"ETM_EXTERNAL_OUTPUT3",
"ETM_EXTERNAL_OUTPUT4",
"ETM_CONTEXTID_COMPARATOR_VALUE1",
"ETM_CONTEXTID_COMPARATOR_VALUE2",
"ETM_CONTEXTID_COMPARATOR_VALUE3",
"ETM_CONTEXTID_COMPARATOR_MASK"
};
int etm_reg_arch_type = -1;
int etm_get_reg(reg_t *reg);
int etm_set_reg(reg_t *reg, u32 value);
int etm_write_reg(reg_t *reg, u32 value);
int etm_read_reg(reg_t *reg);
reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
{
reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
reg_t *reg_list = NULL;
etm_reg_t *arch_info = NULL;
int num_regs = sizeof(etm_reg_arch_info)/sizeof(int);
int i;
/* register a register arch-type for etm registers only once */
if (etm_reg_arch_type == -1)
etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec);
/* the actual registers are kept in two arrays */
reg_list = calloc(num_regs, sizeof(reg_t));
arch_info = calloc(num_regs, sizeof(etm_reg_t));
/* fill in values for the reg cache */
reg_cache->name = "etm registers";
reg_cache->next = NULL;
reg_cache->reg_list = reg_list;
reg_cache->num_regs = num_regs;
/* set up registers */
for (i = 0; i < num_regs; i++)
{
reg_list[i].name = etm_reg_list[i];
reg_list[i].size = 32;
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].bitfield_desc = NULL;
reg_list[i].num_bitfields = 0;
reg_list[i].value = calloc(1, 4);
reg_list[i].arch_info = &arch_info[i];
reg_list[i].arch_type = etm_reg_arch_type;
reg_list[i].size = etm_reg_arch_size_info[i];
arch_info[i].addr = etm_reg_arch_info[i];
arch_info[i].jtag_info = jtag_info;
}
return reg_cache;
}
int etm_get_reg(reg_t *reg)
{
if (etm_read_reg(reg) != ERROR_OK)
{
ERROR("BUG: error scheduling etm register read");
exit(-1);
}
if (jtag_execute_queue() != ERROR_OK)
{
ERROR("register read failed");
}
return ERROR_OK;
}
int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
{
etm_reg_t *etm_reg = reg->arch_info;
u8 reg_addr = etm_reg->addr & 0x7f;
scan_field_t fields[3];
DEBUG("%i", etm_reg->addr);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(etm_reg->jtag_info, 0x6);
arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
fields[0].device = etm_reg->jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = reg->value;
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = etm_reg->jtag_info->chain_pos;
fields[1].num_bits = 7;
fields[1].out_value = malloc(1);
buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = etm_reg->jtag_info->chain_pos;
fields[2].num_bits = 1;
fields[2].out_value = malloc(1);
buf_set_u32(fields[2].out_value, 0, 1, 0);
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
fields[0].in_value = reg->value;
fields[0].in_check_value = check_value;
fields[0].in_check_mask = check_mask;
jtag_add_dr_scan(3, fields, -1);
free(fields[1].out_value);
free(fields[2].out_value);
return ERROR_OK;
}
int etm_read_reg(reg_t *reg)
{
return etm_read_reg_w_check(reg, NULL, NULL);
}
int etm_set_reg(reg_t *reg, u32 value)
{
if (etm_write_reg(reg, value) != ERROR_OK)
{
ERROR("BUG: error scheduling etm register write");
exit(-1);
}
buf_set_u32(reg->value, 0, reg->size, value);
reg->valid = 1;
reg->dirty = 0;
return ERROR_OK;
}
int etm_set_reg_w_exec(reg_t *reg, u32 value)
{
etm_set_reg(reg, value);
if (jtag_execute_queue() != ERROR_OK)
{
ERROR("register write failed");
exit(-1);
}
return ERROR_OK;
}
int etm_write_reg(reg_t *reg, u32 value)
{
etm_reg_t *etm_reg = reg->arch_info;
u8 reg_addr = etm_reg->addr & 0x7f;
scan_field_t fields[3];
DEBUG("%i: 0x%8.8x", etm_reg->addr, value);
jtag_add_end_state(TAP_RTI);
arm_jtag_scann(etm_reg->jtag_info, 0x6);
arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
fields[0].device = etm_reg->jtag_info->chain_pos;
fields[0].num_bits = 32;
fields[0].out_value = malloc(4);
buf_set_u32(fields[0].out_value, 0, 32, value);
fields[0].out_mask = NULL;
fields[0].in_value = NULL;
fields[0].in_check_value = NULL;
fields[0].in_check_mask = NULL;
fields[0].in_handler = NULL;
fields[0].in_handler_priv = NULL;
fields[1].device = etm_reg->jtag_info->chain_pos;
fields[1].num_bits = 7;
fields[1].out_value = malloc(1);
buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
fields[1].out_mask = NULL;
fields[1].in_value = NULL;
fields[1].in_check_value = NULL;
fields[1].in_check_mask = NULL;
fields[1].in_handler = NULL;
fields[1].in_handler_priv = NULL;
fields[2].device = etm_reg->jtag_info->chain_pos;
fields[2].num_bits = 1;
fields[2].out_value = malloc(1);
buf_set_u32(fields[2].out_value, 0, 1, 1);
fields[2].out_mask = NULL;
fields[2].in_value = NULL;
fields[2].in_check_value = NULL;
fields[2].in_check_mask = NULL;
fields[2].in_handler = NULL;
fields[2].in_handler_priv = NULL;
jtag_add_dr_scan(3, fields, -1);
free(fields[0].out_value);
free(fields[1].out_value);
free(fields[2].out_value);
return ERROR_OK;
}
int etm_store_reg(reg_t *reg)
{
return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
}

76
src/target/etm.h Normal file
View File

@@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ETM_H
#define ETM_H
#include "target.h"
#include "register.h"
#include "arm_jtag.h"
// ETM registers (V1.2 protocol)
enum
{
ETM_CTRL = 0x00,
ETM_CONFIG = 0x01,
ETM_TRIG_EVENT = 0x02,
ETM_MMD_CTRL = 0x03,
ETM_STATUS = 0x04,
ETM_SYS_CONFIG = 0x05,
ETM_TRACE_RESOURCE_CTRL = 0x06,
ETM_TRACE_EN_CTRL2 = 0x07,
ETM_TRACE_EN_EVENT = 0x08,
ETM_TRACE_EN_CTRL1 = 0x09,
ETM_FIFOFULL_REGION = 0x0a,
ETM_FIFOFULL_LEVEL = 0x0b,
ETM_VIEWDATA_EVENT = 0x0c,
ETM_VIEWDATA_CTRL1 = 0x0d,
ETM_VIEWDATA_CTRL2 = 0x0e,
ETM_VIEWDATA_CTRL3 = 0x0f,
ETM_ADDR_COMPARATOR_VALUE = 0x10,
ETM_ADDR_ACCESS_TYPE = 0x20,
ETM_DATA_COMPARATOR_VALUE = 0x30,
ETM_DATA_COMPARATOR_MASK = 0x40,
ETM_COUNTER_INITAL_VALUE = 0x50,
ETM_COUNTER_ENABLE = 0x54,
ETM_COUNTER_RELOAD_VALUE = 0x58,
ETM_COUNTER_VALUE = 0x5c,
ETM_SEQUENCER_CTRL = 0x60,
ETM_SEQUENCER_STATE = 0x67,
ETM_EXTERNAL_OUTPUT = 0x68,
ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c,
ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,
};
typedef struct etm_reg_s
{
int addr;
arm_jtag_t *jtag_info;
} etm_reg_t;
extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
extern int etm_read_reg(reg_t *reg);
extern int etm_write_reg(reg_t *reg, u32 value);
extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
extern int etm_store_reg(reg_t *reg);
extern int etm_set_reg(reg_t *reg, u32 value);
extern int etm_set_reg_w_exec(reg_t *reg, u32 value);
#endif /* ETM_H */

100
src/target/register.c Normal file
View File

@@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "register.h"
#include "log.h"
#include "command.h"
#include <string.h>
#include <stdlib.h>
reg_arch_type_t *reg_arch_types = NULL;
reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all)
{
int i;
reg_cache_t *cache = first;
while (cache)
{
for (i = 0; i < cache->num_regs; i++)
{
if (strcmp(cache->reg_list[i].name, name) == 0)
return &(cache->reg_list[i]);
}
if (search_all)
cache = cache->next;
else
break;
}
return NULL;
}
reg_cache_t** register_get_last_cache_p(reg_cache_t **first)
{
reg_cache_t **cache_p = first;
if (*cache_p)
while (*cache_p)
cache_p = &((*cache_p)->next);
else
return first;
return cache_p;
}
int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value))
{
reg_arch_type_t** arch_type_p = &reg_arch_types;
int id = 0;
if (*arch_type_p)
{
while (*arch_type_p)
{
id = (*arch_type_p)->id;
arch_type_p = &((*arch_type_p)->next);
}
}
(*arch_type_p) = malloc(sizeof(reg_arch_type_t));
(*arch_type_p)->id = id + 1;
(*arch_type_p)->set = set;
(*arch_type_p)->get = get;
(*arch_type_p)->next = NULL;
return id + 1;
}
reg_arch_type_t* register_get_arch_type(int id)
{
reg_arch_type_t *arch_type = reg_arch_types;
while (arch_type)
{
if (arch_type->id == id)
return arch_type;
arch_type = arch_type->next;
}
return NULL;
}

69
src/target/register.h Normal file
View File

@@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef REGISTER_H
#define REGISTER_H
#include "types.h"
#include "target.h"
struct target_s;
typedef struct bitfield_desc_s
{
char *name;
int num_bits;
} bitfield_desc_t;
typedef struct reg_s
{
char *name;
u8 *value;
int dirty;
int valid;
int size;
bitfield_desc_t *bitfield_desc;
int num_bitfields;
void *arch_info;
int arch_type;
} reg_t;
typedef struct reg_cache_s
{
char *name;
struct reg_cache_s *next;
reg_t *reg_list;
int num_regs;
} reg_cache_t;
typedef struct reg_arch_type_s
{
int id;
int (*get)(reg_t *reg);
int (*set)(reg_t *reg, u32 value);
struct reg_arch_type_s *next;
} reg_arch_type_t;
extern reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all);
extern reg_cache_t** register_get_last_cache_p(reg_cache_t **first);
extern int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value));
extern reg_arch_type_t* register_get_arch_type(int id);
#endif /* REGISTER_H */

1701
src/target/target.c Normal file

File diff suppressed because it is too large Load Diff

231
src/target/target.h Normal file
View File

@@ -0,0 +1,231 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef TARGET_H
#define TARGET_H
#include "register.h"
#include "breakpoints.h"
#include "algorithm.h"
#include "command.h"
#include "types.h"
#include <sys/time.h>
#include <time.h>
struct reg_s;
struct command_context_s;
enum target_state
{
TARGET_UNKNOWN = 0,
TARGET_RUNNING = 1,
TARGET_HALTED = 2,
TARGET_RESET = 3,
TARGET_DEBUG_RUNNING = 4,
};
extern char *target_state_strings[];
enum daemon_startup_mode
{
DAEMON_ATTACH, /* simply attach to the target */
DAEMON_RESET, /* reset target (behaviour defined by reset_mode */
};
enum target_reset_mode
{
RESET_RUN = 0, /* reset and let target run */
RESET_HALT = 1, /* reset and halt target out of reset */
RESET_INIT = 2, /* reset and halt target out of reset, then run init script */
RESET_RUN_AND_HALT = 3, /* reset and let target run, halt after n milliseconds */
RESET_RUN_AND_INIT = 4, /* reset and let target run, halt after n milliseconds, then run init script */
};
enum target_debug_reason
{
DBG_REASON_DBGRQ = 0,
DBG_REASON_BREAKPOINT = 1,
DBG_REASON_WATCHPOINT = 2,
DBG_REASON_WPTANDBKPT = 3,
DBG_REASON_SINGLESTEP = 4,
DBG_REASON_NOTHALTED = 5
};
extern char *target_debug_reason_strings[];
enum target_endianess
{
TARGET_BIG_ENDIAN = 0, TARGET_LITTLE_ENDIAN = 1
};
extern char *target_endianess_strings[];
struct target_s;
typedef struct working_area_s
{
u32 address;
u32 size;
int free;
u8 *backup;
struct working_area_s **user;
struct working_area_s *next;
} working_area_t;
typedef struct target_type_s
{
char *name;
/* poll current target status */
enum target_state (*poll)(struct target_s *target);
/* architecture specific status reply */
int (*arch_state)(struct target_s *target, char *buf, int buf_size);
/* target execution control */
int (*halt)(struct target_s *target);
int (*resume)(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
int (*step)(struct target_s *target, int current, u32 address, int handle_breakpoints);
/* target reset control */
int (*assert_reset)(struct target_s *target);
int (*deassert_reset)(struct target_s *target);
int (*soft_reset_halt)(struct target_s *target);
/* target register access for gdb */
int (*get_gdb_reg_list)(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size);
/* target memory access
* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
* count: number of items of <size>
*/
int (*read_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
int (*write_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
int (*bulk_write_memory)(struct target_s *target, u32 address, u32 count, u8 *buffer);
/* target break-/watchpoint control
* rw: 0 = write, 1 = read, 2 = access
*/
int (*add_breakpoint)(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
int (*remove_breakpoint)(struct target_s *target, breakpoint_t *breakpoint);
int (*add_watchpoint)(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
int (*remove_watchpoint)(struct target_s *target, watchpoint_t *watchpoint);
/* target algorithm support */
int (*run_algorithm)(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
int (*register_commands)(struct command_context_s *cmd_ctx);
int (*target_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
int (*init_target)(struct command_context_s *cmd_ctx, struct target_s *target);
int (*quit)(void);
} target_type_t;
typedef struct target_s
{
target_type_t *type; /* target type definition (name, access functions) */
enum target_reset_mode reset_mode; /* what to do after a reset */
int run_and_halt_time; /* how long the target should run after a run_and_halt reset */
char *reset_script; /* script file to initialize the target after a reset */
char *post_halt_script; /* script file to execute after the target halted */
char *pre_resume_script; /* script file to execute before the target resumed */
u32 working_area; /* working area (initialized RAM) */
u32 working_area_size; /* size in bytes */
u32 backup_working_area; /* whether the content of the working area has to be preserved */
struct working_area_s *working_areas;/* list of allocated working areas */
enum target_debug_reason debug_reason; /* reason why the target entered debug state */
enum target_endianess endianness; /* target endianess */
enum target_state state; /* the current backend-state (running, halted, ...) */
struct reg_cache_s *reg_cache; /* the first register cache of the target (core regs) */
struct breakpoint_s *breakpoints; /* list of breakpoints */
struct watchpoint_s *watchpoints; /* list of watchpoints */
void *arch_info; /* architecture specific information */
struct target_s *next; /* next target in list */
} target_t;
enum target_event
{
TARGET_EVENT_HALTED, /* target entered debug state from normal execution or reset */
TARGET_EVENT_RESUMED, /* target resumed to normal execution */
TARGET_EVENT_RESET, /* target entered reset */
TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */
TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */
};
typedef struct target_event_callback_s
{
int (*callback)(struct target_s *target, enum target_event event, void *priv);
void *priv;
struct target_event_callback_s *next;
} target_event_callback_t;
typedef struct target_timer_callback_s
{
int (*callback)(void *priv);
int time_ms;
int periodic;
struct timeval when;
void *priv;
struct target_timer_callback_s *next;
} target_timer_callback_t;
extern int target_register_commands(struct command_context_s *cmd_ctx);
extern int target_register_user_commands(struct command_context_s *cmd_ctx);
extern int target_init(struct command_context_s *cmd_ctx);
extern int handle_target(void *priv);
extern int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
extern int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
extern int target_call_event_callbacks(target_t *target, enum target_event event);
extern int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv);
extern int target_unregister_timer_callback(int (*callback)(void *priv), void *priv);
extern int target_call_timer_callbacks();
extern target_t* get_current_target(struct command_context_s *cmd_ctx);
extern int get_num_by_target(target_t *query_target);
extern target_t* get_target_by_num(int num);
extern int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
extern int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
extern int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area);
extern int target_free_working_area(struct target_s *target, working_area_t *area);
extern int target_free_all_working_areas(struct target_s *target);
extern target_t *targets;
extern target_event_callback_t *target_event_callbacks;
extern target_timer_callback_t *target_timer_callbacks;
#define ERROR_TARGET_INVALID (-300)
#define ERROR_TARGET_INIT_FAILED (-301)
#define ERROR_TARGET_TIMEOUT (-302)
#define ERROR_TARGET_ALREADY_HALTED (-303)
#define ERROR_TARGET_NOT_HALTED (-304)
#define ERROR_TARGET_FAILURE (-305)
#define ERROR_TARGET_UNALIGNED_ACCESS (-306)
#define ERROR_TARGET_DATA_ABORT (-307)
#define ERROR_TARGET_RESOURCE_NOT_AVAILABLE (-308)
#define ERROR_TARGET_TRANSLATION_FAULT (-309)
#endif /* TARGET_H */