From 3d6bcf07921753141a3905ee5619724573460cb3 Mon Sep 17 00:00:00 2001 From: drath Date: Mon, 25 Feb 2008 17:48:04 +0000 Subject: - convert all files to unix line-ending git-svn-id: svn://svn.berlios.de/openocd/trunk@347 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- src/target/arm11.c | 2716 ++++++++-------- src/target/arm11.h | 500 +-- src/target/arm11_dbgtap.c | 1222 +++---- src/target/arm720t.c | 1252 ++++---- src/target/arm7_9_common.c | 18 +- src/target/arm7tdmi.c | 1748 +++++----- src/target/arm920t.c | 2970 ++++++++--------- src/target/arm926ejs.c | 1888 +++++------ src/target/arm966e.c | 728 ++--- src/target/arm9tdmi.c | 2210 ++++++------- src/target/arm_jtag.c | 414 +-- src/target/cortex_swjdp.c | 1416 ++++----- src/target/embeddedice.c | 1130 +++---- src/target/etb.c | 1482 ++++----- src/target/etb.h | 150 +- src/target/etm.c | 3726 +++++++++++----------- src/target/etm.h | 428 +-- src/target/etm_dummy.h | 66 +- src/target/oocd_trace.h | 128 +- src/target/target.c | 4664 +++++++++++++-------------- src/target/xscale.c | 7598 ++++++++++++++++++++++---------------------- 21 files changed, 18227 insertions(+), 18227 deletions(-) (limited to 'src/target') diff --git a/src/target/arm11.c b/src/target/arm11.c index 11e376a6..d02518a2 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1,1358 +1,1358 @@ -/*************************************************************************** - * Copyright (C) 2008 digenius technology GmbH. * - * * - * 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. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm11.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - - -#if 0 -#define FNC_INFO DEBUG("-") -#else -#define FNC_INFO -#endif - -#if 1 -#define FNC_INFO_NOTIMPLEMENTED do { DEBUG("NOT IMPLEMENTED"); /*exit(-1);*/ } while (0) -#else -#define FNC_INFO_NOTIMPLEMENTED -#endif - -static void arm11_on_enter_debug_state(arm11_common_t * arm11); - - -#define ARM11_HANDLER(x) \ - .x = arm11_##x - -target_type_t arm11_target = -{ - .name = "arm11", - - ARM11_HANDLER(poll), - ARM11_HANDLER(arch_state), - - ARM11_HANDLER(target_request_data), - - ARM11_HANDLER(halt), - ARM11_HANDLER(resume), - ARM11_HANDLER(step), - - ARM11_HANDLER(assert_reset), - ARM11_HANDLER(deassert_reset), - ARM11_HANDLER(soft_reset_halt), - ARM11_HANDLER(prepare_reset_halt), - - ARM11_HANDLER(get_gdb_reg_list), - - ARM11_HANDLER(read_memory), - ARM11_HANDLER(write_memory), - - ARM11_HANDLER(bulk_write_memory), - - ARM11_HANDLER(checksum_memory), - - ARM11_HANDLER(add_breakpoint), - ARM11_HANDLER(remove_breakpoint), - ARM11_HANDLER(add_watchpoint), - ARM11_HANDLER(remove_watchpoint), - - ARM11_HANDLER(run_algorithm), - - ARM11_HANDLER(register_commands), - ARM11_HANDLER(target_command), - ARM11_HANDLER(init_target), - ARM11_HANDLER(quit), -}; - -int arm11_regs_arch_type = -1; - - -enum arm11_regtype -{ - ARM11_REGISTER_CORE, - ARM11_REGISTER_CPSR, - - ARM11_REGISTER_FX, - ARM11_REGISTER_FPS, - - ARM11_REGISTER_FIQ, - ARM11_REGISTER_SVC, - ARM11_REGISTER_ABT, - ARM11_REGISTER_IRQ, - ARM11_REGISTER_UND, - ARM11_REGISTER_MON, - - ARM11_REGISTER_SPSR_FIQ, - ARM11_REGISTER_SPSR_SVC, - ARM11_REGISTER_SPSR_ABT, - ARM11_REGISTER_SPSR_IRQ, - ARM11_REGISTER_SPSR_UND, - ARM11_REGISTER_SPSR_MON, - - /* debug regs */ - ARM11_REGISTER_DSCR, - ARM11_REGISTER_WDTR, - ARM11_REGISTER_RDTR, -}; - - -typedef struct arm11_reg_defs_s -{ - char * name; - u32 num; - int gdb_num; - enum arm11_regtype type; -} arm11_reg_defs_t; - -/* update arm11_regcache_ids when changing this */ -static const arm11_reg_defs_t arm11_reg_defs[] = -{ - {"r0", 0, 0, ARM11_REGISTER_CORE}, - {"r1", 1, 1, ARM11_REGISTER_CORE}, - {"r2", 2, 2, ARM11_REGISTER_CORE}, - {"r3", 3, 3, ARM11_REGISTER_CORE}, - {"r4", 4, 4, ARM11_REGISTER_CORE}, - {"r5", 5, 5, ARM11_REGISTER_CORE}, - {"r6", 6, 6, ARM11_REGISTER_CORE}, - {"r7", 7, 7, ARM11_REGISTER_CORE}, - {"r8", 8, 8, ARM11_REGISTER_CORE}, - {"r9", 9, 9, ARM11_REGISTER_CORE}, - {"r10", 10, 10, ARM11_REGISTER_CORE}, - {"r11", 11, 11, ARM11_REGISTER_CORE}, - {"r12", 12, 12, ARM11_REGISTER_CORE}, - {"sp", 13, 13, ARM11_REGISTER_CORE}, - {"lr", 14, 14, ARM11_REGISTER_CORE}, - {"pc", 15, 15, ARM11_REGISTER_CORE}, - -#if ARM11_REGCACHE_FREGS - {"f0", 0, 16, ARM11_REGISTER_FX}, - {"f1", 1, 17, ARM11_REGISTER_FX}, - {"f2", 2, 18, ARM11_REGISTER_FX}, - {"f3", 3, 19, ARM11_REGISTER_FX}, - {"f4", 4, 20, ARM11_REGISTER_FX}, - {"f5", 5, 21, ARM11_REGISTER_FX}, - {"f6", 6, 22, ARM11_REGISTER_FX}, - {"f7", 7, 23, ARM11_REGISTER_FX}, - {"fps", 0, 24, ARM11_REGISTER_FPS}, -#endif - - {"cpsr", 0, 25, ARM11_REGISTER_CPSR}, - -#if ARM11_REGCACHE_MODEREGS - {"r8_fiq", 8, -1, ARM11_REGISTER_FIQ}, - {"r9_fiq", 9, -1, ARM11_REGISTER_FIQ}, - {"r10_fiq", 10, -1, ARM11_REGISTER_FIQ}, - {"r11_fiq", 11, -1, ARM11_REGISTER_FIQ}, - {"r12_fiq", 12, -1, ARM11_REGISTER_FIQ}, - {"r13_fiq", 13, -1, ARM11_REGISTER_FIQ}, - {"r14_fiq", 14, -1, ARM11_REGISTER_FIQ}, - {"spsr_fiq", 0, -1, ARM11_REGISTER_SPSR_FIQ}, - - {"r13_svc", 13, -1, ARM11_REGISTER_SVC}, - {"r14_svc", 14, -1, ARM11_REGISTER_SVC}, - {"spsr_svc", 0, -1, ARM11_REGISTER_SPSR_SVC}, - - {"r13_abt", 13, -1, ARM11_REGISTER_ABT}, - {"r14_abt", 14, -1, ARM11_REGISTER_ABT}, - {"spsr_abt", 0, -1, ARM11_REGISTER_SPSR_ABT}, - - {"r13_irq", 13, -1, ARM11_REGISTER_IRQ}, - {"r14_irq", 14, -1, ARM11_REGISTER_IRQ}, - {"spsr_irq", 0, -1, ARM11_REGISTER_SPSR_IRQ}, - - {"r13_und", 13, -1, ARM11_REGISTER_UND}, - {"r14_und", 14, -1, ARM11_REGISTER_UND}, - {"spsr_und", 0, -1, ARM11_REGISTER_SPSR_UND}, - - /* ARM1176 only */ - {"r13_mon", 13, -1, ARM11_REGISTER_MON}, - {"r14_mon", 14, -1, ARM11_REGISTER_MON}, - {"spsr_mon", 0, -1, ARM11_REGISTER_SPSR_MON}, -#endif - - /* Debug Registers */ - {"dscr", 0, -1, ARM11_REGISTER_DSCR}, - {"wdtr", 0, -1, ARM11_REGISTER_WDTR}, - {"rdtr", 0, -1, ARM11_REGISTER_RDTR}, -}; - -enum arm11_regcache_ids -{ - ARM11_RC_R0, - ARM11_RC_RX = ARM11_RC_R0, - - ARM11_RC_R1, - ARM11_RC_R2, - ARM11_RC_R3, - ARM11_RC_R4, - ARM11_RC_R5, - ARM11_RC_R6, - ARM11_RC_R7, - ARM11_RC_R8, - ARM11_RC_R9, - ARM11_RC_R10, - ARM11_RC_R11, - ARM11_RC_R12, - ARM11_RC_R13, - ARM11_RC_SP = ARM11_RC_R13, - ARM11_RC_R14, - ARM11_RC_LR = ARM11_RC_R14, - ARM11_RC_R15, - ARM11_RC_PC = ARM11_RC_R15, - -#if ARM11_REGCACHE_FREGS - ARM11_RC_F0, - ARM11_RC_FX = ARM11_RC_F0, - ARM11_RC_F1, - ARM11_RC_F2, - ARM11_RC_F3, - ARM11_RC_F4, - ARM11_RC_F5, - ARM11_RC_F6, - ARM11_RC_F7, - ARM11_RC_FPS, -#endif - - ARM11_RC_CPSR, - -#if ARM11_REGCACHE_MODEREGS - ARM11_RC_R8_FIQ, - ARM11_RC_R9_FIQ, - ARM11_RC_R10_FIQ, - ARM11_RC_R11_FIQ, - ARM11_RC_R12_FIQ, - ARM11_RC_R13_FIQ, - ARM11_RC_R14_FIQ, - ARM11_RC_SPSR_FIQ, - - ARM11_RC_R13_SVC, - ARM11_RC_R14_SVC, - ARM11_RC_SPSR_SVC, - - ARM11_RC_R13_ABT, - ARM11_RC_R14_ABT, - ARM11_RC_SPSR_ABT, - - ARM11_RC_R13_IRQ, - ARM11_RC_R14_IRQ, - ARM11_RC_SPSR_IRQ, - - ARM11_RC_R13_UND, - ARM11_RC_R14_UND, - ARM11_RC_SPSR_UND, - - ARM11_RC_R13_MON, - ARM11_RC_R14_MON, - ARM11_RC_SPSR_MON, -#endif - - ARM11_RC_DSCR, - ARM11_RC_WDTR, - ARM11_RC_RDTR, - - - ARM11_RC_MAX, -}; - -#define ARM11_GDB_REGISTER_COUNT 26 - -u8 arm11_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -reg_t arm11_gdb_dummy_fp_reg = -{ - "GDB dummy floating-point register", arm11_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0 -}; - -u8 arm11_gdb_dummy_fps_value[] = {0, 0, 0, 0}; - -reg_t arm11_gdb_dummy_fps_reg = -{ - "GDB dummy floating-point status register", arm11_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0 -}; - - - -/** Check and if necessary take control of the system - * - * \param arm11 Target state variable. - * \param dscr If the current DSCR content is - * available a pointer to a word holding the - * DSCR can be passed. Otherwise use NULL. - */ -void arm11_check_init(arm11_common_t * arm11, u32 * dscr) -{ - FNC_INFO; - - u32 dscr_local_tmp_copy; - - if (!dscr) - { - dscr = &dscr_local_tmp_copy; - *dscr = arm11_read_DSCR(arm11); - } - - if (!(*dscr & ARM11_DSCR_MODE_SELECT)) - { - DEBUG("Bringing target into debug mode"); - - *dscr |= ARM11_DSCR_MODE_SELECT; /* Halt debug-mode */ - arm11_write_DSCR(arm11, *dscr); - - /* add further reset initialization here */ - - if (*dscr & ARM11_DSCR_CORE_HALTED) - { - arm11->target->state = TARGET_HALTED; - arm11->target->debug_reason = arm11_get_DSCR_debug_reason(*dscr); - } - else - { - arm11->target->state = TARGET_RUNNING; - arm11->target->debug_reason = DBG_REASON_NOTHALTED; - } - - arm11_sc7_clear_bw(arm11); - } -} - - - -#define R(x) \ - (arm11->reg_values[ARM11_RC_##x]) - -/** Save processor state. - * - * This is called when the HALT instruction has succeeded - * or on other occasions that stop the processor. - * - */ -static void arm11_on_enter_debug_state(arm11_common_t * arm11) -{ - FNC_INFO; - - {size_t i; - for(i = 0; i < asizeof(arm11->reg_values); i++) - { - arm11->reg_list[i].valid = 1; - arm11->reg_list[i].dirty = 0; - }} - - /* Save DSCR */ - - R(DSCR) = arm11_read_DSCR(arm11); - - /* Save wDTR */ - - if (R(DSCR) & ARM11_DSCR_WDTR_FULL) - { - arm11_add_debug_SCAN_N(arm11, 0x05, -1); - - arm11_add_IR(arm11, ARM11_INTEST, -1); - - scan_field_t chain5_fields[3]; - - arm11_setup_field(arm11, 32, NULL, &R(WDTR), chain5_fields + 0); - arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); - arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); - - jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); - } - else - { - arm11->reg_list[ARM11_RC_WDTR].valid = 0; - } - - - /* DSCR: set ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE */ - /* ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", but not to issue ITRs - ARM1136 seems to require this to issue ITR's as well */ - - u32 new_dscr = R(DSCR) | ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE; - - /* this executes JTAG queue: */ - - arm11_write_DSCR(arm11, new_dscr); - -// jtag_execute_queue(); - - - -// DEBUG("SAVE DSCR %08x", R(DSCR)); - -// if (R(DSCR) & ARM11_DSCR_WDTR_FULL) -// DEBUG("SAVE wDTR %08x", R(WDTR)); - - - /* From the spec: - Before executing any instruction in debug state you have to drain the write buffer. - This ensures that no imprecise Data Aborts can return at a later point:*/ - - /** \todo TODO: Test drain write buffer. */ - -#if 0 - while (1) - { - /* MRC p14,0,R0,c5,c10,0 */ -// arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000); - - /* mcr 15, 0, r0, cr7, cr10, {4} */ - arm11_run_instr_no_data1(arm11, 0xee070f9a); - - u32 dscr = arm11_read_DSCR(arm11); - - DEBUG("DRAIN, DSCR %08x", dscr); - - if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) - { - arm11_run_instr_no_data1(arm11, 0xe320f000); - - dscr = arm11_read_DSCR(arm11); - - DEBUG("DRAIN, DSCR %08x (DONE)", dscr); - - break; - } - } -#endif - - - arm11_run_instr_data_prepare(arm11); - - /* save r0 - r14 */ - - - /** \todo TODO: handle other mode registers */ - - {size_t i; - for (i = 0; i < 15; i++) - { - /* MCR p14,0,R?,c0,c5,0 */ - arm11_run_instr_data_from_core(arm11, 0xEE000E15 | (i << 12), &R(RX + i), 1); - }} - - - /* save rDTR */ - - /* check rDTRfull in DSCR */ - - if (R(DSCR) & ARM11_DSCR_RDTR_FULL) - { - /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ - arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR)); - } - else - { - arm11->reg_list[ARM11_RC_RDTR].valid = 0; - } - - /* save CPSR */ - - /* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */ - arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR)); - - /* save PC */ - - /* MOV R0,PC (move PC -> r0 (-> wDTR -> local var)) */ - arm11_run_instr_data_from_core_via_r0(arm11, 0xE1A0000F, &R(PC)); - - /* adjust PC depending on ARM state */ - - if (R(CPSR) & ARM11_CPSR_J) /* Java state */ - { - arm11->reg_values[ARM11_RC_PC] -= 0; - } - else if (R(CPSR) & ARM11_CPSR_T) /* Thumb state */ - { - arm11->reg_values[ARM11_RC_PC] -= 4; - } - else /* ARM state */ - { - arm11->reg_values[ARM11_RC_PC] -= 8; - } - -// DEBUG("SAVE PC %08x", R(PC)); - - arm11_run_instr_data_finish(arm11); - - - {size_t i; - for(i = 0; i < ARM11_REGCACHE_COUNT; i++) - { - if (!arm11->reg_list[i].valid) - { - if (arm11->reg_history[i].valid) - INFO("%8s INVALID (%08x)", arm11_reg_defs[i].name, arm11->reg_history[i].value); - } - else - { - if (arm11->reg_history[i].valid) - { - if (arm11->reg_history[i].value != arm11->reg_values[i]) - INFO("%8s %08x (%08x)", arm11_reg_defs[i].name, arm11->reg_values[i], arm11->reg_history[i].value); - } - else - { - INFO("%8s %08x (INVALID)", arm11_reg_defs[i].name, arm11->reg_values[i]); - } - } - }} -} - - -/** Restore processor state - * - * This is called in preparation for the RESTART function. - * - */ -void arm11_leave_debug_state(arm11_common_t * arm11) -{ - FNC_INFO; - - arm11_run_instr_data_prepare(arm11); - - /** \todo TODO: handle other mode registers */ - - /* restore R1 - R14 */ - {size_t i; - for (i = 1; i < 15; i++) - { - if (!arm11->reg_list[ARM11_RC_RX + i].dirty) - continue; - - /* MRC p14,0,r?,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee100e15 | (i << 12), R(RX + i)); - -// DEBUG("RESTORE R%d %08x", i, R(RX + i)); - }} - - arm11_run_instr_data_finish(arm11); - - - /* spec says clear wDTR and rDTR; we assume they are clear as - otherwide out programming would be sloppy */ - - { - u32 DSCR = arm11_read_DSCR(arm11); - - if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL)) - { - ERROR("wDTR/rDTR inconsistent (DSCR %08x)", DSCR); - } - } - - arm11_run_instr_data_prepare(arm11); - - /* restore original wDTR */ - - if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty) - { - /* MCR p14,0,R0,c0,c5,0 */ - arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR)); - } - - /* restore CPSR */ - - /* MSR CPSR,R0*/ - arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR)); - - - /* restore PC */ - - /* MOV PC,R0 */ - arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC)); - - - /* restore R0 */ - - /* MRC p14,0,r0,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0)); - - arm11_run_instr_data_finish(arm11); - - - /* restore DSCR */ - - arm11_write_DSCR(arm11, R(DSCR)); - - - /* restore rDTR */ - - if (R(DSCR) & ARM11_DSCR_RDTR_FULL || arm11->reg_list[ARM11_RC_RDTR].dirty) - { - arm11_add_debug_SCAN_N(arm11, 0x05, -1); - - arm11_add_IR(arm11, ARM11_EXTEST, -1); - - scan_field_t chain5_fields[3]; - - u8 Ready = 0; /* ignored */ - u8 Valid = 0; /* ignored */ - - arm11_setup_field(arm11, 32, &R(RDTR), NULL, chain5_fields + 0); - arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); - arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); - - jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); - } - - - {size_t i; - for(i = 0; i < ARM11_REGCACHE_COUNT; i++) - { - arm11->reg_history[i].value = arm11->reg_values[i]; - arm11->reg_history[i].valid = arm11->reg_list[i].valid; - - arm11->reg_list[i].valid = 0; - arm11->reg_list[i].dirty = 0; - }} -} - - -/* poll current target status */ -int arm11_poll(struct target_s *target) -{ - FNC_INFO; - - arm11_common_t * arm11 = target->arch_info; - - if (arm11->trst_active) - return ERROR_OK; - - u32 dscr = arm11_read_DSCR(arm11); - - DEBUG("DSCR %08x", dscr); - - arm11_check_init(arm11, &dscr); - - if (dscr & ARM11_DSCR_CORE_HALTED) - { -// DEBUG("CH %d", target->state); - - if (target->state != TARGET_HALTED) - { - DEBUG("enter TARGET_HALTED"); - target->state = TARGET_HALTED; - target->debug_reason = arm11_get_DSCR_debug_reason(dscr); - arm11_on_enter_debug_state(arm11); - } - } - else - { -// DEBUG("CR %d", target->state); - - if (target->state != TARGET_RUNNING) - { - DEBUG("enter TARGET_RUNNING"); - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - } - } - - return ERROR_OK; -} -/* architecture specific status reply */ -int arm11_arch_state(struct target_s *target) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - -/* target request support */ -int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - - -/* target execution control */ -int arm11_halt(struct target_s *target) -{ - FNC_INFO; - - arm11_common_t * arm11 = target->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - if (target->state == TARGET_HALTED) - { - WARNING("target was already halted"); - return ERROR_TARGET_ALREADY_HALTED; - } - - if (arm11->trst_active) - { - arm11->halt_requested = true; - return ERROR_OK; - } - - arm11_add_IR(arm11, ARM11_HALT, TAP_RTI); - - jtag_execute_queue(); - - u32 dscr; - - while (1) - { - dscr = arm11_read_DSCR(arm11); - - if (dscr & ARM11_DSCR_CORE_HALTED) - break; - } - - arm11_on_enter_debug_state(arm11); - - target->state = TARGET_HALTED; - target->debug_reason = arm11_get_DSCR_debug_reason(dscr); - - return ERROR_OK; -} - - -int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) -{ - FNC_INFO; - - arm11_common_t * arm11 = target->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - if (target->state != TARGET_HALTED) - { - WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!current) - R(PC) = address; - - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - - arm11_leave_debug_state(arm11); - - arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); - - jtag_execute_queue(); - - while (1) - { - u32 dscr = arm11_read_DSCR(arm11); - - DEBUG("DSCR %08x", dscr); - - if (dscr & ARM11_DSCR_CORE_RESTARTED) - break; - } - - DEBUG("RES %d", target->state); - - return ERROR_OK; -} - -int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints) -{ - FNC_INFO; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - if (target->state != TARGET_HALTED) - { - WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - arm11_common_t * arm11 = target->arch_info; - - /** \todo TODO: check if break-/watchpoints make any sense at all in combination - * with this. */ - - /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively - the VCR might be something worth looking into. */ - - /* Set up breakpoint for stepping */ - - arm11_sc7_action_t brp[2]; - - brp[0].write = 1; - brp[0].address = ARM11_SC7_BVR0; - brp[0].value = R(PC); - brp[1].write = 1; - brp[1].address = ARM11_SC7_BCR0; - brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); - - arm11_sc7_run(arm11, brp, asizeof(brp)); - - /* resume */ - - arm11_leave_debug_state(arm11); - - arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); - - jtag_execute_queue(); - - /** \todo TODO: add a timeout */ - - /* wait for halt */ - - while (1) - { - u32 dscr = arm11_read_DSCR(arm11); - - DEBUG("DSCR %08x", dscr); - - if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) == - (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) - break; - } - - - /* clear breakpoint */ - - arm11_sc7_clear_bw(arm11); - - - /* save state */ - - arm11_on_enter_debug_state(arm11); - -// target->state = TARGET_HALTED; - target->debug_reason = DBG_REASON_SINGLESTEP; - - return ERROR_OK; -} - - -/* target reset control */ -int arm11_assert_reset(struct target_s *target) -{ - FNC_INFO; - -#if 0 - /* assert reset lines */ - /* resets only the DBGTAP, not the ARM */ - - jtag_add_reset(1, 0); - jtag_add_sleep(5000); - - arm11_common_t * arm11 = target->arch_info; - arm11->trst_active = true; -#endif - - return ERROR_OK; -} - -int arm11_deassert_reset(struct target_s *target) -{ - FNC_INFO; - -#if 0 - DEBUG("target->state: %s", target_state_strings[target->state]); - - /* deassert reset lines */ - jtag_add_reset(0, 0); - - arm11_common_t * arm11 = target->arch_info; - arm11->trst_active = false; - - if (arm11->halt_requested) - return arm11_halt(target); -#endif - - return ERROR_OK; -} - -int arm11_soft_reset_halt(struct target_s *target) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - -int arm11_prepare_reset_halt(struct target_s *target) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - -/* target register access for gdb */ -int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size) -{ - FNC_INFO; - - arm11_common_t * arm11 = target->arch_info; - - if (target->state != TARGET_HALTED) - { - return ERROR_TARGET_NOT_HALTED; - } - - *reg_list_size = ARM11_GDB_REGISTER_COUNT; - *reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT); - - {size_t i; - for (i = 16; i < 24; i++) - { - (*reg_list)[i] = &arm11_gdb_dummy_fp_reg; - }} - - (*reg_list)[24] = &arm11_gdb_dummy_fps_reg; - - - {size_t i; - for (i = 0; i < ARM11_REGCACHE_COUNT; i++) - { - if (arm11_reg_defs[i].gdb_num == -1) - continue; - - (*reg_list)[arm11_reg_defs[i].gdb_num] = arm11->reg_list + i; - }} - - return ERROR_OK; -} - - -/* target memory access -* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) -* count: number of items of -*/ -int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - /** \todo TODO: check if buffer cast to u32* and u16* might cause alignment problems */ - - FNC_INFO; - - DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); - - arm11_common_t * arm11 = target->arch_info; - - arm11_run_instr_data_prepare(arm11); - - /* MRC p14,0,r0,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); - - switch (size) - { - case 1: - /** \todo TODO: check if dirty is the right choice to force a rewrite on arm11_resume() */ - arm11->reg_list[ARM11_RC_R1].dirty = 1; - - while (count--) - { - /* ldrb r1, [r0], #1 */ - arm11_run_instr_no_data1(arm11, 0xe4d01001); - - u32 res; - /* MCR p14,0,R1,c0,c5,0 */ - arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); - - *buffer++ = res; - } - break; - - case 2: - { - arm11->reg_list[ARM11_RC_R1].dirty = 1; - - u16 * buf16 = (u16*)buffer; - - while (count--) - { - /* ldrh r1, [r0], #2 */ - arm11_run_instr_no_data1(arm11, 0xe0d010b2); - - u32 res; - - /* MCR p14,0,R1,c0,c5,0 */ - arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); - - *buf16++ = res; - } - break; - } - - case 4: - - /* LDC p14,c5,[R0],#4 */ - arm11_run_instr_data_from_core(arm11, 0xecb05e01, (u32 *)buffer, count); - break; - } - - arm11_run_instr_data_finish(arm11); - - return ERROR_OK; -} - -int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - FNC_INFO; - - DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); - - arm11_common_t * arm11 = target->arch_info; - - arm11_run_instr_data_prepare(arm11); - - /* MRC p14,0,r0,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); - - switch (size) - { - case 1: - arm11->reg_list[ARM11_RC_R1].dirty = 1; - - while (count--) - { - /* MRC p14,0,r1,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); - - /* strb r1, [r0], #1 */ - arm11_run_instr_no_data1(arm11, 0xe4c01001); - } - break; - - case 2: - { - arm11->reg_list[ARM11_RC_R1].dirty = 1; - - u16 * buf16 = (u16*)buffer; - - while (count--) - { - /* MRC p14,0,r1,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buf16++); - - /* strh r1, [r0], #2 */ - arm11_run_instr_no_data1(arm11, 0xe0c010b2); - } - break; - } - - case 4: - /** \todo TODO: check if buffer cast to u32* might cause alignment problems */ - - /* STC p14,c5,[R0],#4 */ - arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count); - break; - } - - arm11_run_instr_data_finish(arm11); - - return ERROR_OK; -} - - -/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */ -int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer) -{ - FNC_INFO; - - return arm11_write_memory(target, address, 4, count, buffer); -} - - -int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - -/* target break-/watchpoint control -* rw: 0 = write, 1 = read, 2 = access -*/ -int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - -int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - -int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - -int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - -/* target algorithm support */ -int arm11_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) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - - -int arm11_register_commands(struct command_context_s *cmd_ctx) -{ - FNC_INFO; - - return ERROR_OK; -} - -int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - FNC_INFO; - - if (argc < 4) - { - ERROR("'target arm11' 4th argument "); - exit(-1); - } - - int chain_pos = strtoul(args[3], NULL, 0); - - NEW(arm11_common_t, arm11, 1); - - arm11->target = target; - - /* prepare JTAG information for the new target */ - arm11->jtag_info.chain_pos = chain_pos; - arm11->jtag_info.scann_size = 5; - - arm_jtag_setup_connection(&arm11->jtag_info); - - jtag_device_t *device = jtag_get_device(chain_pos); - - if (device->ir_length != 5) - { - ERROR("'target arm11' expects 'jtag_device 5 0x01 0x1F 0x1E'"); - exit(-1); - } - - target->arch_info = arm11; - - return ERROR_OK; -} - -int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - FNC_INFO; - - arm11_common_t * arm11 = target->arch_info; - - /* check IDCODE */ - - arm11_add_IR(arm11, ARM11_IDCODE, -1); - - scan_field_t idcode_field; - - arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field); - - jtag_add_dr_scan_vc(1, &idcode_field, TAP_PD); - - /* check DIDR */ - - arm11_add_debug_SCAN_N(arm11, 0x00, -1); - - arm11_add_IR(arm11, ARM11_INTEST, -1); - - scan_field_t chain0_fields[2]; - - arm11_setup_field(arm11, 32, NULL, &arm11->didr, chain0_fields + 0); - arm11_setup_field(arm11, 8, NULL, &arm11->implementor, chain0_fields + 1); - - jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI); - - jtag_execute_queue(); - - - switch (arm11->device_id & 0x0FFFF000) - { - case 0x07B36000: INFO("found ARM1136"); break; - case 0x07B56000: INFO("found ARM1156"); break; - case 0x07B76000: INFO("found ARM1176"); break; - default: - { - ERROR("'target arm11' expects IDCODE 0x*7B*7****"); - exit(-1); - } - } - - arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1; - arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1; - - - DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x", - arm11->device_id, - arm11->implementor, - arm11->didr); - - arm11_build_reg_cache(target); - - - /* as a side-effect this reads DSCR and thus - * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag - * as suggested by the spec. - */ - - arm11_check_init(arm11, NULL); - - return ERROR_OK; -} - -int arm11_quit(void) -{ - FNC_INFO_NOTIMPLEMENTED; - - return ERROR_OK; -} - -/** Load a register that is marked !valid in the register cache */ -int arm11_get_reg(reg_t *reg) -{ - FNC_INFO; - - target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; - - if (target->state != TARGET_HALTED) - { - return ERROR_TARGET_NOT_HALTED; - } - - /** \todo TODO: Check this. We assume that all registers are fetched debug entry. */ - -#if 0 - arm11_common_t *arm11 = target->arch_info; - const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; -#endif - - return ERROR_OK; -} - -/** Change a value in the register cache */ -int arm11_set_reg(reg_t *reg, u8 *buf) -{ - FNC_INFO; - - target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; - arm11_common_t *arm11 = target->arch_info; -// const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; - - arm11->reg_values[((arm11_reg_state_t *)reg->arch_info)->def_index] = buf_get_u32(buf, 0, 32); - reg->valid = 1; - reg->dirty = 1; - - return ERROR_OK; -} - - -void arm11_build_reg_cache(target_t *target) -{ - arm11_common_t *arm11 = target->arch_info; - - NEW(reg_cache_t, cache, 1); - NEW(reg_t, reg_list, ARM11_REGCACHE_COUNT); - NEW(arm11_reg_state_t, arm11_reg_states, ARM11_REGCACHE_COUNT); - - if (arm11_regs_arch_type == -1) - arm11_regs_arch_type = register_reg_arch_type(arm11_get_reg, arm11_set_reg); - - arm11->reg_list = reg_list; - - /* Build the process context cache */ - cache->name = "arm11 registers"; - cache->next = NULL; - cache->reg_list = reg_list; - cache->num_regs = ARM11_REGCACHE_COUNT; - - reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); - (*cache_p) = cache; - -// armv7m->core_cache = cache; -// armv7m->process_context = cache; - - size_t i; - - /* Not very elegant assertion */ - if (ARM11_REGCACHE_COUNT != asizeof(arm11->reg_values) || - ARM11_REGCACHE_COUNT != asizeof(arm11_reg_defs) || - ARM11_REGCACHE_COUNT != ARM11_RC_MAX) - { - ERROR("arm11->reg_values inconsistent (%d %d %d %d)", ARM11_REGCACHE_COUNT, asizeof(arm11->reg_values), asizeof(arm11_reg_defs), ARM11_RC_MAX); - exit(-1); - } - - for (i = 0; i < ARM11_REGCACHE_COUNT; i++) - { - reg_t * r = reg_list + i; - const arm11_reg_defs_t * rd = arm11_reg_defs + i; - arm11_reg_state_t * rs = arm11_reg_states + i; - - r->name = rd->name; - r->size = 32; - r->value = (u8 *)(arm11->reg_values + i); - r->dirty = 0; - r->valid = 0; - r->bitfield_desc = NULL; - r->num_bitfields = 0; - r->arch_type = arm11_regs_arch_type; - r->arch_info = rs; - - rs->def_index = i; - rs->target = target; - } -} - -#if 0 - arm11_run_instr_data_prepare(arm11); - - /* MRC p14,0,r0,c0,c5,0 */ - arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C); - /* MRC p14,0,r1,c0,c5,0 */ - arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF); - - arm11_run_instr_data_finish(arm11); -#endif - - +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm11.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + + +#if 0 +#define FNC_INFO DEBUG("-") +#else +#define FNC_INFO +#endif + +#if 1 +#define FNC_INFO_NOTIMPLEMENTED do { DEBUG("NOT IMPLEMENTED"); /*exit(-1);*/ } while (0) +#else +#define FNC_INFO_NOTIMPLEMENTED +#endif + +static void arm11_on_enter_debug_state(arm11_common_t * arm11); + + +#define ARM11_HANDLER(x) \ + .x = arm11_##x + +target_type_t arm11_target = +{ + .name = "arm11", + + ARM11_HANDLER(poll), + ARM11_HANDLER(arch_state), + + ARM11_HANDLER(target_request_data), + + ARM11_HANDLER(halt), + ARM11_HANDLER(resume), + ARM11_HANDLER(step), + + ARM11_HANDLER(assert_reset), + ARM11_HANDLER(deassert_reset), + ARM11_HANDLER(soft_reset_halt), + ARM11_HANDLER(prepare_reset_halt), + + ARM11_HANDLER(get_gdb_reg_list), + + ARM11_HANDLER(read_memory), + ARM11_HANDLER(write_memory), + + ARM11_HANDLER(bulk_write_memory), + + ARM11_HANDLER(checksum_memory), + + ARM11_HANDLER(add_breakpoint), + ARM11_HANDLER(remove_breakpoint), + ARM11_HANDLER(add_watchpoint), + ARM11_HANDLER(remove_watchpoint), + + ARM11_HANDLER(run_algorithm), + + ARM11_HANDLER(register_commands), + ARM11_HANDLER(target_command), + ARM11_HANDLER(init_target), + ARM11_HANDLER(quit), +}; + +int arm11_regs_arch_type = -1; + + +enum arm11_regtype +{ + ARM11_REGISTER_CORE, + ARM11_REGISTER_CPSR, + + ARM11_REGISTER_FX, + ARM11_REGISTER_FPS, + + ARM11_REGISTER_FIQ, + ARM11_REGISTER_SVC, + ARM11_REGISTER_ABT, + ARM11_REGISTER_IRQ, + ARM11_REGISTER_UND, + ARM11_REGISTER_MON, + + ARM11_REGISTER_SPSR_FIQ, + ARM11_REGISTER_SPSR_SVC, + ARM11_REGISTER_SPSR_ABT, + ARM11_REGISTER_SPSR_IRQ, + ARM11_REGISTER_SPSR_UND, + ARM11_REGISTER_SPSR_MON, + + /* debug regs */ + ARM11_REGISTER_DSCR, + ARM11_REGISTER_WDTR, + ARM11_REGISTER_RDTR, +}; + + +typedef struct arm11_reg_defs_s +{ + char * name; + u32 num; + int gdb_num; + enum arm11_regtype type; +} arm11_reg_defs_t; + +/* update arm11_regcache_ids when changing this */ +static const arm11_reg_defs_t arm11_reg_defs[] = +{ + {"r0", 0, 0, ARM11_REGISTER_CORE}, + {"r1", 1, 1, ARM11_REGISTER_CORE}, + {"r2", 2, 2, ARM11_REGISTER_CORE}, + {"r3", 3, 3, ARM11_REGISTER_CORE}, + {"r4", 4, 4, ARM11_REGISTER_CORE}, + {"r5", 5, 5, ARM11_REGISTER_CORE}, + {"r6", 6, 6, ARM11_REGISTER_CORE}, + {"r7", 7, 7, ARM11_REGISTER_CORE}, + {"r8", 8, 8, ARM11_REGISTER_CORE}, + {"r9", 9, 9, ARM11_REGISTER_CORE}, + {"r10", 10, 10, ARM11_REGISTER_CORE}, + {"r11", 11, 11, ARM11_REGISTER_CORE}, + {"r12", 12, 12, ARM11_REGISTER_CORE}, + {"sp", 13, 13, ARM11_REGISTER_CORE}, + {"lr", 14, 14, ARM11_REGISTER_CORE}, + {"pc", 15, 15, ARM11_REGISTER_CORE}, + +#if ARM11_REGCACHE_FREGS + {"f0", 0, 16, ARM11_REGISTER_FX}, + {"f1", 1, 17, ARM11_REGISTER_FX}, + {"f2", 2, 18, ARM11_REGISTER_FX}, + {"f3", 3, 19, ARM11_REGISTER_FX}, + {"f4", 4, 20, ARM11_REGISTER_FX}, + {"f5", 5, 21, ARM11_REGISTER_FX}, + {"f6", 6, 22, ARM11_REGISTER_FX}, + {"f7", 7, 23, ARM11_REGISTER_FX}, + {"fps", 0, 24, ARM11_REGISTER_FPS}, +#endif + + {"cpsr", 0, 25, ARM11_REGISTER_CPSR}, + +#if ARM11_REGCACHE_MODEREGS + {"r8_fiq", 8, -1, ARM11_REGISTER_FIQ}, + {"r9_fiq", 9, -1, ARM11_REGISTER_FIQ}, + {"r10_fiq", 10, -1, ARM11_REGISTER_FIQ}, + {"r11_fiq", 11, -1, ARM11_REGISTER_FIQ}, + {"r12_fiq", 12, -1, ARM11_REGISTER_FIQ}, + {"r13_fiq", 13, -1, ARM11_REGISTER_FIQ}, + {"r14_fiq", 14, -1, ARM11_REGISTER_FIQ}, + {"spsr_fiq", 0, -1, ARM11_REGISTER_SPSR_FIQ}, + + {"r13_svc", 13, -1, ARM11_REGISTER_SVC}, + {"r14_svc", 14, -1, ARM11_REGISTER_SVC}, + {"spsr_svc", 0, -1, ARM11_REGISTER_SPSR_SVC}, + + {"r13_abt", 13, -1, ARM11_REGISTER_ABT}, + {"r14_abt", 14, -1, ARM11_REGISTER_ABT}, + {"spsr_abt", 0, -1, ARM11_REGISTER_SPSR_ABT}, + + {"r13_irq", 13, -1, ARM11_REGISTER_IRQ}, + {"r14_irq", 14, -1, ARM11_REGISTER_IRQ}, + {"spsr_irq", 0, -1, ARM11_REGISTER_SPSR_IRQ}, + + {"r13_und", 13, -1, ARM11_REGISTER_UND}, + {"r14_und", 14, -1, ARM11_REGISTER_UND}, + {"spsr_und", 0, -1, ARM11_REGISTER_SPSR_UND}, + + /* ARM1176 only */ + {"r13_mon", 13, -1, ARM11_REGISTER_MON}, + {"r14_mon", 14, -1, ARM11_REGISTER_MON}, + {"spsr_mon", 0, -1, ARM11_REGISTER_SPSR_MON}, +#endif + + /* Debug Registers */ + {"dscr", 0, -1, ARM11_REGISTER_DSCR}, + {"wdtr", 0, -1, ARM11_REGISTER_WDTR}, + {"rdtr", 0, -1, ARM11_REGISTER_RDTR}, +}; + +enum arm11_regcache_ids +{ + ARM11_RC_R0, + ARM11_RC_RX = ARM11_RC_R0, + + ARM11_RC_R1, + ARM11_RC_R2, + ARM11_RC_R3, + ARM11_RC_R4, + ARM11_RC_R5, + ARM11_RC_R6, + ARM11_RC_R7, + ARM11_RC_R8, + ARM11_RC_R9, + ARM11_RC_R10, + ARM11_RC_R11, + ARM11_RC_R12, + ARM11_RC_R13, + ARM11_RC_SP = ARM11_RC_R13, + ARM11_RC_R14, + ARM11_RC_LR = ARM11_RC_R14, + ARM11_RC_R15, + ARM11_RC_PC = ARM11_RC_R15, + +#if ARM11_REGCACHE_FREGS + ARM11_RC_F0, + ARM11_RC_FX = ARM11_RC_F0, + ARM11_RC_F1, + ARM11_RC_F2, + ARM11_RC_F3, + ARM11_RC_F4, + ARM11_RC_F5, + ARM11_RC_F6, + ARM11_RC_F7, + ARM11_RC_FPS, +#endif + + ARM11_RC_CPSR, + +#if ARM11_REGCACHE_MODEREGS + ARM11_RC_R8_FIQ, + ARM11_RC_R9_FIQ, + ARM11_RC_R10_FIQ, + ARM11_RC_R11_FIQ, + ARM11_RC_R12_FIQ, + ARM11_RC_R13_FIQ, + ARM11_RC_R14_FIQ, + ARM11_RC_SPSR_FIQ, + + ARM11_RC_R13_SVC, + ARM11_RC_R14_SVC, + ARM11_RC_SPSR_SVC, + + ARM11_RC_R13_ABT, + ARM11_RC_R14_ABT, + ARM11_RC_SPSR_ABT, + + ARM11_RC_R13_IRQ, + ARM11_RC_R14_IRQ, + ARM11_RC_SPSR_IRQ, + + ARM11_RC_R13_UND, + ARM11_RC_R14_UND, + ARM11_RC_SPSR_UND, + + ARM11_RC_R13_MON, + ARM11_RC_R14_MON, + ARM11_RC_SPSR_MON, +#endif + + ARM11_RC_DSCR, + ARM11_RC_WDTR, + ARM11_RC_RDTR, + + + ARM11_RC_MAX, +}; + +#define ARM11_GDB_REGISTER_COUNT 26 + +u8 arm11_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fp_reg = +{ + "GDB dummy floating-point register", arm11_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0 +}; + +u8 arm11_gdb_dummy_fps_value[] = {0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fps_reg = +{ + "GDB dummy floating-point status register", arm11_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0 +}; + + + +/** Check and if necessary take control of the system + * + * \param arm11 Target state variable. + * \param dscr If the current DSCR content is + * available a pointer to a word holding the + * DSCR can be passed. Otherwise use NULL. + */ +void arm11_check_init(arm11_common_t * arm11, u32 * dscr) +{ + FNC_INFO; + + u32 dscr_local_tmp_copy; + + if (!dscr) + { + dscr = &dscr_local_tmp_copy; + *dscr = arm11_read_DSCR(arm11); + } + + if (!(*dscr & ARM11_DSCR_MODE_SELECT)) + { + DEBUG("Bringing target into debug mode"); + + *dscr |= ARM11_DSCR_MODE_SELECT; /* Halt debug-mode */ + arm11_write_DSCR(arm11, *dscr); + + /* add further reset initialization here */ + + if (*dscr & ARM11_DSCR_CORE_HALTED) + { + arm11->target->state = TARGET_HALTED; + arm11->target->debug_reason = arm11_get_DSCR_debug_reason(*dscr); + } + else + { + arm11->target->state = TARGET_RUNNING; + arm11->target->debug_reason = DBG_REASON_NOTHALTED; + } + + arm11_sc7_clear_bw(arm11); + } +} + + + +#define R(x) \ + (arm11->reg_values[ARM11_RC_##x]) + +/** Save processor state. + * + * This is called when the HALT instruction has succeeded + * or on other occasions that stop the processor. + * + */ +static void arm11_on_enter_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + {size_t i; + for(i = 0; i < asizeof(arm11->reg_values); i++) + { + arm11->reg_list[i].valid = 1; + arm11->reg_list[i].dirty = 0; + }} + + /* Save DSCR */ + + R(DSCR) = arm11_read_DSCR(arm11); + + /* Save wDTR */ + + if (R(DSCR) & ARM11_DSCR_WDTR_FULL) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + arm11_setup_field(arm11, 32, NULL, &R(WDTR), chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + else + { + arm11->reg_list[ARM11_RC_WDTR].valid = 0; + } + + + /* DSCR: set ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE */ + /* ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", but not to issue ITRs + ARM1136 seems to require this to issue ITR's as well */ + + u32 new_dscr = R(DSCR) | ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE; + + /* this executes JTAG queue: */ + + arm11_write_DSCR(arm11, new_dscr); + +// jtag_execute_queue(); + + + +// DEBUG("SAVE DSCR %08x", R(DSCR)); + +// if (R(DSCR) & ARM11_DSCR_WDTR_FULL) +// DEBUG("SAVE wDTR %08x", R(WDTR)); + + + /* From the spec: + Before executing any instruction in debug state you have to drain the write buffer. + This ensures that no imprecise Data Aborts can return at a later point:*/ + + /** \todo TODO: Test drain write buffer. */ + +#if 0 + while (1) + { + /* MRC p14,0,R0,c5,c10,0 */ +// arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000); + + /* mcr 15, 0, r0, cr7, cr10, {4} */ + arm11_run_instr_no_data1(arm11, 0xee070f9a); + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) + { + arm11_run_instr_no_data1(arm11, 0xe320f000); + + dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x (DONE)", dscr); + + break; + } + } +#endif + + + arm11_run_instr_data_prepare(arm11); + + /* save r0 - r14 */ + + + /** \todo TODO: handle other mode registers */ + + {size_t i; + for (i = 0; i < 15; i++) + { + /* MCR p14,0,R?,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15 | (i << 12), &R(RX + i), 1); + }} + + + /* save rDTR */ + + /* check rDTRfull in DSCR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL) + { + /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR)); + } + else + { + arm11->reg_list[ARM11_RC_RDTR].valid = 0; + } + + /* save CPSR */ + + /* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR)); + + /* save PC */ + + /* MOV R0,PC (move PC -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE1A0000F, &R(PC)); + + /* adjust PC depending on ARM state */ + + if (R(CPSR) & ARM11_CPSR_J) /* Java state */ + { + arm11->reg_values[ARM11_RC_PC] -= 0; + } + else if (R(CPSR) & ARM11_CPSR_T) /* Thumb state */ + { + arm11->reg_values[ARM11_RC_PC] -= 4; + } + else /* ARM state */ + { + arm11->reg_values[ARM11_RC_PC] -= 8; + } + +// DEBUG("SAVE PC %08x", R(PC)); + + arm11_run_instr_data_finish(arm11); + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + if (!arm11->reg_list[i].valid) + { + if (arm11->reg_history[i].valid) + INFO("%8s INVALID (%08x)", arm11_reg_defs[i].name, arm11->reg_history[i].value); + } + else + { + if (arm11->reg_history[i].valid) + { + if (arm11->reg_history[i].value != arm11->reg_values[i]) + INFO("%8s %08x (%08x)", arm11_reg_defs[i].name, arm11->reg_values[i], arm11->reg_history[i].value); + } + else + { + INFO("%8s %08x (INVALID)", arm11_reg_defs[i].name, arm11->reg_values[i]); + } + } + }} +} + + +/** Restore processor state + * + * This is called in preparation for the RESTART function. + * + */ +void arm11_leave_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + arm11_run_instr_data_prepare(arm11); + + /** \todo TODO: handle other mode registers */ + + /* restore R1 - R14 */ + {size_t i; + for (i = 1; i < 15; i++) + { + if (!arm11->reg_list[ARM11_RC_RX + i].dirty) + continue; + + /* MRC p14,0,r?,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15 | (i << 12), R(RX + i)); + +// DEBUG("RESTORE R%d %08x", i, R(RX + i)); + }} + + arm11_run_instr_data_finish(arm11); + + + /* spec says clear wDTR and rDTR; we assume they are clear as + otherwide out programming would be sloppy */ + + { + u32 DSCR = arm11_read_DSCR(arm11); + + if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL)) + { + ERROR("wDTR/rDTR inconsistent (DSCR %08x)", DSCR); + } + } + + arm11_run_instr_data_prepare(arm11); + + /* restore original wDTR */ + + if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty) + { + /* MCR p14,0,R0,c0,c5,0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR)); + } + + /* restore CPSR */ + + /* MSR CPSR,R0*/ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR)); + + + /* restore PC */ + + /* MOV PC,R0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC)); + + + /* restore R0 */ + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0)); + + arm11_run_instr_data_finish(arm11); + + + /* restore DSCR */ + + arm11_write_DSCR(arm11, R(DSCR)); + + + /* restore rDTR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL || arm11->reg_list[ARM11_RC_RDTR].dirty) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u8 Ready = 0; /* ignored */ + u8 Valid = 0; /* ignored */ + + arm11_setup_field(arm11, 32, &R(RDTR), NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + arm11->reg_history[i].value = arm11->reg_values[i]; + arm11->reg_history[i].valid = arm11->reg_list[i].valid; + + arm11->reg_list[i].valid = 0; + arm11->reg_list[i].dirty = 0; + }} +} + + +/* poll current target status */ +int arm11_poll(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + if (arm11->trst_active) + return ERROR_OK; + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + arm11_check_init(arm11, &dscr); + + if (dscr & ARM11_DSCR_CORE_HALTED) + { +// DEBUG("CH %d", target->state); + + if (target->state != TARGET_HALTED) + { + DEBUG("enter TARGET_HALTED"); + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + arm11_on_enter_debug_state(arm11); + } + } + else + { +// DEBUG("CR %d", target->state); + + if (target->state != TARGET_RUNNING) + { + DEBUG("enter TARGET_RUNNING"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + } + + return ERROR_OK; +} +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + + +/* target execution control */ +int arm11_halt(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + + if (arm11->trst_active) + { + arm11->halt_requested = true; + return ERROR_OK; + } + + arm11_add_IR(arm11, ARM11_HALT, TAP_RTI); + + jtag_execute_queue(); + + u32 dscr; + + while (1) + { + dscr = arm11_read_DSCR(arm11); + + if (dscr & ARM11_DSCR_CORE_HALTED) + break; + } + + arm11_on_enter_debug_state(arm11); + + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + + return ERROR_OK; +} + + +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!current) + R(PC) = address; + + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_CORE_RESTARTED) + break; + } + + DEBUG("RES %d", target->state); + + return ERROR_OK; +} + +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + FNC_INFO; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + arm11_common_t * arm11 = target->arch_info; + + /** \todo TODO: check if break-/watchpoints make any sense at all in combination + * with this. */ + + /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively + the VCR might be something worth looking into. */ + + /* Set up breakpoint for stepping */ + + arm11_sc7_action_t brp[2]; + + brp[0].write = 1; + brp[0].address = ARM11_SC7_BVR0; + brp[0].value = R(PC); + brp[1].write = 1; + brp[1].address = ARM11_SC7_BCR0; + brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); + + arm11_sc7_run(arm11, brp, asizeof(brp)); + + /* resume */ + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + /** \todo TODO: add a timeout */ + + /* wait for halt */ + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) == + (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) + break; + } + + + /* clear breakpoint */ + + arm11_sc7_clear_bw(arm11); + + + /* save state */ + + arm11_on_enter_debug_state(arm11); + +// target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + + return ERROR_OK; +} + + +/* target reset control */ +int arm11_assert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + /* assert reset lines */ + /* resets only the DBGTAP, not the ARM */ + + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + + arm11_common_t * arm11 = target->arch_info; + arm11->trst_active = true; +#endif + + return ERROR_OK; +} + +int arm11_deassert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + DEBUG("target->state: %s", target_state_strings[target->state]); + + /* deassert reset lines */ + jtag_add_reset(0, 0); + + arm11_common_t * arm11 = target->arch_info; + arm11->trst_active = false; + + if (arm11->halt_requested) + return arm11_halt(target); +#endif + + return ERROR_OK; +} + +int arm11_soft_reset_halt(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_prepare_reset_halt(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target register access for gdb */ +int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + *reg_list_size = ARM11_GDB_REGISTER_COUNT; + *reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT); + + {size_t i; + for (i = 16; i < 24; i++) + { + (*reg_list)[i] = &arm11_gdb_dummy_fp_reg; + }} + + (*reg_list)[24] = &arm11_gdb_dummy_fps_reg; + + + {size_t i; + for (i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + if (arm11_reg_defs[i].gdb_num == -1) + continue; + + (*reg_list)[arm11_reg_defs[i].gdb_num] = arm11->reg_list + i; + }} + + return ERROR_OK; +} + + +/* target memory access +* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) +* count: number of items of +*/ +int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + /** \todo TODO: check if buffer cast to u32* and u16* might cause alignment problems */ + + FNC_INFO; + + DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); + + arm11_common_t * arm11 = target->arch_info; + + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); + + switch (size) + { + case 1: + /** \todo TODO: check if dirty is the right choice to force a rewrite on arm11_resume() */ + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + while (count--) + { + /* ldrb r1, [r0], #1 */ + arm11_run_instr_no_data1(arm11, 0xe4d01001); + + u32 res; + /* MCR p14,0,R1,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); + + *buffer++ = res; + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* ldrh r1, [r0], #2 */ + arm11_run_instr_no_data1(arm11, 0xe0d010b2); + + u32 res; + + /* MCR p14,0,R1,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); + + *buf16++ = res; + } + break; + } + + case 4: + + /* LDC p14,c5,[R0],#4 */ + arm11_run_instr_data_from_core(arm11, 0xecb05e01, (u32 *)buffer, count); + break; + } + + arm11_run_instr_data_finish(arm11); + + return ERROR_OK; +} + +int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + FNC_INFO; + + DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); + + arm11_common_t * arm11 = target->arch_info; + + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); + + switch (size) + { + case 1: + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + while (count--) + { + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); + + /* strb r1, [r0], #1 */ + arm11_run_instr_no_data1(arm11, 0xe4c01001); + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buf16++); + + /* strh r1, [r0], #2 */ + arm11_run_instr_no_data1(arm11, 0xe0c010b2); + } + break; + } + + case 4: + /** \todo TODO: check if buffer cast to u32* might cause alignment problems */ + + /* STC p14,c5,[R0],#4 */ + arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count); + break; + } + + arm11_run_instr_data_finish(arm11); + + return ERROR_OK; +} + + +/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */ +int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer) +{ + FNC_INFO; + + return arm11_write_memory(target, address, 4, count, buffer); +} + + +int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target break-/watchpoint control +* rw: 0 = write, 1 = read, 2 = access +*/ +int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target algorithm support */ +int arm11_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) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +int arm11_register_commands(struct command_context_s *cmd_ctx) +{ + FNC_INFO; + + return ERROR_OK; +} + +int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + FNC_INFO; + + if (argc < 4) + { + ERROR("'target arm11' 4th argument "); + exit(-1); + } + + int chain_pos = strtoul(args[3], NULL, 0); + + NEW(arm11_common_t, arm11, 1); + + arm11->target = target; + + /* prepare JTAG information for the new target */ + arm11->jtag_info.chain_pos = chain_pos; + arm11->jtag_info.scann_size = 5; + + arm_jtag_setup_connection(&arm11->jtag_info); + + jtag_device_t *device = jtag_get_device(chain_pos); + + if (device->ir_length != 5) + { + ERROR("'target arm11' expects 'jtag_device 5 0x01 0x1F 0x1E'"); + exit(-1); + } + + target->arch_info = arm11; + + return ERROR_OK; +} + +int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + /* check IDCODE */ + + arm11_add_IR(arm11, ARM11_IDCODE, -1); + + scan_field_t idcode_field; + + arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field); + + jtag_add_dr_scan_vc(1, &idcode_field, TAP_PD); + + /* check DIDR */ + + arm11_add_debug_SCAN_N(arm11, 0x00, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain0_fields[2]; + + arm11_setup_field(arm11, 32, NULL, &arm11->didr, chain0_fields + 0); + arm11_setup_field(arm11, 8, NULL, &arm11->implementor, chain0_fields + 1); + + jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI); + + jtag_execute_queue(); + + + switch (arm11->device_id & 0x0FFFF000) + { + case 0x07B36000: INFO("found ARM1136"); break; + case 0x07B56000: INFO("found ARM1156"); break; + case 0x07B76000: INFO("found ARM1176"); break; + default: + { + ERROR("'target arm11' expects IDCODE 0x*7B*7****"); + exit(-1); + } + } + + arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1; + arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1; + + + DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x", + arm11->device_id, + arm11->implementor, + arm11->didr); + + arm11_build_reg_cache(target); + + + /* as a side-effect this reads DSCR and thus + * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag + * as suggested by the spec. + */ + + arm11_check_init(arm11, NULL); + + return ERROR_OK; +} + +int arm11_quit(void) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +/** Load a register that is marked !valid in the register cache */ +int arm11_get_reg(reg_t *reg) +{ + FNC_INFO; + + target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + /** \todo TODO: Check this. We assume that all registers are fetched debug entry. */ + +#if 0 + arm11_common_t *arm11 = target->arch_info; + const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; +#endif + + return ERROR_OK; +} + +/** Change a value in the register cache */ +int arm11_set_reg(reg_t *reg, u8 *buf) +{ + FNC_INFO; + + target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; + arm11_common_t *arm11 = target->arch_info; +// const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; + + arm11->reg_values[((arm11_reg_state_t *)reg->arch_info)->def_index] = buf_get_u32(buf, 0, 32); + reg->valid = 1; + reg->dirty = 1; + + return ERROR_OK; +} + + +void arm11_build_reg_cache(target_t *target) +{ + arm11_common_t *arm11 = target->arch_info; + + NEW(reg_cache_t, cache, 1); + NEW(reg_t, reg_list, ARM11_REGCACHE_COUNT); + NEW(arm11_reg_state_t, arm11_reg_states, ARM11_REGCACHE_COUNT); + + if (arm11_regs_arch_type == -1) + arm11_regs_arch_type = register_reg_arch_type(arm11_get_reg, arm11_set_reg); + + arm11->reg_list = reg_list; + + /* Build the process context cache */ + cache->name = "arm11 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = ARM11_REGCACHE_COUNT; + + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + (*cache_p) = cache; + +// armv7m->core_cache = cache; +// armv7m->process_context = cache; + + size_t i; + + /* Not very elegant assertion */ + if (ARM11_REGCACHE_COUNT != asizeof(arm11->reg_values) || + ARM11_REGCACHE_COUNT != asizeof(arm11_reg_defs) || + ARM11_REGCACHE_COUNT != ARM11_RC_MAX) + { + ERROR("arm11->reg_values inconsistent (%d %d %d %d)", ARM11_REGCACHE_COUNT, asizeof(arm11->reg_values), asizeof(arm11_reg_defs), ARM11_RC_MAX); + exit(-1); + } + + for (i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + reg_t * r = reg_list + i; + const arm11_reg_defs_t * rd = arm11_reg_defs + i; + arm11_reg_state_t * rs = arm11_reg_states + i; + + r->name = rd->name; + r->size = 32; + r->value = (u8 *)(arm11->reg_values + i); + r->dirty = 0; + r->valid = 0; + r->bitfield_desc = NULL; + r->num_bitfields = 0; + r->arch_type = arm11_regs_arch_type; + r->arch_info = rs; + + rs->def_index = i; + rs->target = target; + } +} + +#if 0 + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C); + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF); + + arm11_run_instr_data_finish(arm11); +#endif + + diff --git a/src/target/arm11.h b/src/target/arm11.h index 4e061ae4..f2263b52 100644 --- a/src/target/arm11.h +++ b/src/target/arm11.h @@ -1,250 +1,250 @@ -/*************************************************************************** - * Copyright (C) 2008 digenius technology GmbH. * - * * - * 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 ARM11_H -#define ARM11_H - -#include "target.h" -#include "register.h" -#include "embeddedice.h" -#include "arm_jtag.h" - - -#define bool int -#define true 1 -#define false 0 - -#define asizeof(x) (sizeof(x) / sizeof((x)[0])) - -#define NEW(type, variable, items) \ - type * variable = malloc(sizeof(type) * items) - - -#define ARM11_REGCACHE_MODEREGS 0 -#define ARM11_REGCACHE_FREGS 0 - -#define ARM11_REGCACHE_COUNT (20 + \ - 23 * ARM11_REGCACHE_MODEREGS + \ - 9 * ARM11_REGCACHE_FREGS) - - -typedef struct arm11_register_history_s -{ - u32 value; - u8 valid; -}arm11_register_history_t; - - - -typedef struct arm11_common_s -{ - target_t * target; - - arm_jtag_t jtag_info; - - /** \name Processor type detection */ - /*@{*/ - - u32 device_id; /**< IDCODE readout */ - u32 didr; /**< DIDR readout (debug capabilities) */ - u8 implementor; /**< DIDR Implementor readout */ - - size_t brp; /**< Number of Breakpoint Register Pairs */ - size_t wrp; /**< Number of Watchpoint Register Pairs */ - - /*@}*/ - - - u32 last_dscr; /**< Last retrieved DSCR value; - * Can be used to detect changes */ - - u8 trst_active; - u8 halt_requested; - - /** \name Shadow registers to save processor state */ - /*@{*/ - - reg_t * reg_list; /**< target register list */ - u32 reg_values[ARM11_REGCACHE_COUNT]; /**< data for registers */ - - /*@}*/ - - arm11_register_history_t - reg_history[ARM11_REGCACHE_COUNT]; /**< register state before last resume */ - - -} arm11_common_t; - - -/** - * ARM11 DBGTAP instructions - * - * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html - */ -enum arm11_instructions -{ - ARM11_EXTEST = 0x00, - ARM11_SCAN_N = 0x02, - ARM11_RESTART = 0x04, - ARM11_HALT = 0x08, - ARM11_INTEST = 0x0C, - ARM11_ITRSEL = 0x1D, - ARM11_IDCODE = 0x1E, - ARM11_BYPASS = 0x1F, -}; - -enum arm11_dscr -{ - ARM11_DSCR_CORE_HALTED = 1 << 0, - ARM11_DSCR_CORE_RESTARTED = 1 << 1, - - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2, - ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2, - - ARM11_DSCR_STICKY_PRECISE_DATA_ABORT = 1 << 6, - ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT = 1 << 7, - ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE = 1 << 13, - ARM11_DSCR_MODE_SELECT = 1 << 14, - ARM11_DSCR_WDTR_FULL = 1 << 29, - ARM11_DSCR_RDTR_FULL = 1 << 30, -}; - -enum arm11_cpsr -{ - ARM11_CPSR_T = 1 << 5, - ARM11_CPSR_J = 1 << 24, -}; - -enum arm11_sc7 -{ - ARM11_SC7_NULL = 0, - ARM11_SC7_VCR = 7, - ARM11_SC7_PC = 8, - ARM11_SC7_BVR0 = 64, - ARM11_SC7_BCR0 = 80, - ARM11_SC7_WVR0 = 96, - ARM11_SC7_WCR0 = 112, -}; - - - -typedef struct arm11_reg_state_s -{ - u32 def_index; - target_t * target; -} arm11_reg_state_t; - - - - -/* poll current target status */ -int arm11_poll(struct target_s *target); -/* architecture specific status reply */ -int arm11_arch_state(struct target_s *target); - -/* target request support */ -int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer); - -/* target execution control */ -int arm11_halt(struct target_s *target); -int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); -int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints); - -/* target reset control */ -int arm11_assert_reset(struct target_s *target); -int arm11_deassert_reset(struct target_s *target); -int arm11_soft_reset_halt(struct target_s *target); -int arm11_prepare_reset_halt(struct target_s *target); - -/* target register access for gdb */ -int arm11_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 -*/ -int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm11_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 arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer); - -int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); - -/* target break-/watchpoint control -* rw: 0 = write, 1 = read, 2 = access -*/ -int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); -int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); - -/* target algorithm support */ -int arm11_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 arm11_register_commands(struct command_context_s *cmd_ctx); -int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm11_quit(void); - - -/* helpers */ -void arm11_build_reg_cache(target_t *target); - - -/* internals */ - -void arm11_setup_field (arm11_common_t * arm11, int num_bits, void * in_data, void * out_data, scan_field_t * field); -void arm11_add_IR (arm11_common_t * arm11, u8 instr, enum tap_state state); -void arm11_add_debug_SCAN_N (arm11_common_t * arm11, u8 chain, enum tap_state state); -void arm11_add_debug_INST (arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state); -u32 arm11_read_DSCR (arm11_common_t * arm11); -void arm11_write_DSCR (arm11_common_t * arm11, u32 dscr); - -enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr); - -void arm11_run_instr_data_prepare (arm11_common_t * arm11); -void arm11_run_instr_data_finish (arm11_common_t * arm11); -void arm11_run_instr_no_data (arm11_common_t * arm11, u32 * opcode, size_t count); -void arm11_run_instr_no_data1 (arm11_common_t * arm11, u32 opcode); -void arm11_run_instr_data_to_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); -void arm11_run_instr_data_to_core1 (arm11_common_t * arm11, u32 opcode, u32 data); -void arm11_run_instr_data_from_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); -void arm11_run_instr_data_from_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 * data); -void arm11_run_instr_data_to_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 data); - - -typedef struct arm11_sc7_action_s -{ - bool write; - u8 address; - u32 value; -} arm11_sc7_action_t; - -void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count); -void arm11_sc7_clear_bw(arm11_common_t * arm11); - - - -#endif /* ARM11_H */ +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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 ARM11_H +#define ARM11_H + +#include "target.h" +#include "register.h" +#include "embeddedice.h" +#include "arm_jtag.h" + + +#define bool int +#define true 1 +#define false 0 + +#define asizeof(x) (sizeof(x) / sizeof((x)[0])) + +#define NEW(type, variable, items) \ + type * variable = malloc(sizeof(type) * items) + + +#define ARM11_REGCACHE_MODEREGS 0 +#define ARM11_REGCACHE_FREGS 0 + +#define ARM11_REGCACHE_COUNT (20 + \ + 23 * ARM11_REGCACHE_MODEREGS + \ + 9 * ARM11_REGCACHE_FREGS) + + +typedef struct arm11_register_history_s +{ + u32 value; + u8 valid; +}arm11_register_history_t; + + + +typedef struct arm11_common_s +{ + target_t * target; + + arm_jtag_t jtag_info; + + /** \name Processor type detection */ + /*@{*/ + + u32 device_id; /**< IDCODE readout */ + u32 didr; /**< DIDR readout (debug capabilities) */ + u8 implementor; /**< DIDR Implementor readout */ + + size_t brp; /**< Number of Breakpoint Register Pairs */ + size_t wrp; /**< Number of Watchpoint Register Pairs */ + + /*@}*/ + + + u32 last_dscr; /**< Last retrieved DSCR value; + * Can be used to detect changes */ + + u8 trst_active; + u8 halt_requested; + + /** \name Shadow registers to save processor state */ + /*@{*/ + + reg_t * reg_list; /**< target register list */ + u32 reg_values[ARM11_REGCACHE_COUNT]; /**< data for registers */ + + /*@}*/ + + arm11_register_history_t + reg_history[ARM11_REGCACHE_COUNT]; /**< register state before last resume */ + + +} arm11_common_t; + + +/** + * ARM11 DBGTAP instructions + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html + */ +enum arm11_instructions +{ + ARM11_EXTEST = 0x00, + ARM11_SCAN_N = 0x02, + ARM11_RESTART = 0x04, + ARM11_HALT = 0x08, + ARM11_INTEST = 0x0C, + ARM11_ITRSEL = 0x1D, + ARM11_IDCODE = 0x1E, + ARM11_BYPASS = 0x1F, +}; + +enum arm11_dscr +{ + ARM11_DSCR_CORE_HALTED = 1 << 0, + ARM11_DSCR_CORE_RESTARTED = 1 << 1, + + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2, + + ARM11_DSCR_STICKY_PRECISE_DATA_ABORT = 1 << 6, + ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT = 1 << 7, + ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE = 1 << 13, + ARM11_DSCR_MODE_SELECT = 1 << 14, + ARM11_DSCR_WDTR_FULL = 1 << 29, + ARM11_DSCR_RDTR_FULL = 1 << 30, +}; + +enum arm11_cpsr +{ + ARM11_CPSR_T = 1 << 5, + ARM11_CPSR_J = 1 << 24, +}; + +enum arm11_sc7 +{ + ARM11_SC7_NULL = 0, + ARM11_SC7_VCR = 7, + ARM11_SC7_PC = 8, + ARM11_SC7_BVR0 = 64, + ARM11_SC7_BCR0 = 80, + ARM11_SC7_WVR0 = 96, + ARM11_SC7_WCR0 = 112, +}; + + + +typedef struct arm11_reg_state_s +{ + u32 def_index; + target_t * target; +} arm11_reg_state_t; + + + + +/* poll current target status */ +int arm11_poll(struct target_s *target); +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target); + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer); + +/* target execution control */ +int arm11_halt(struct target_s *target); +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints); + +/* target reset control */ +int arm11_assert_reset(struct target_s *target); +int arm11_deassert_reset(struct target_s *target); +int arm11_soft_reset_halt(struct target_s *target); +int arm11_prepare_reset_halt(struct target_s *target); + +/* target register access for gdb */ +int arm11_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 +*/ +int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm11_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 arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer); + +int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +/* target break-/watchpoint control +* rw: 0 = write, 1 = read, 2 = access +*/ +int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); + +/* target algorithm support */ +int arm11_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 arm11_register_commands(struct command_context_s *cmd_ctx); +int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm11_quit(void); + + +/* helpers */ +void arm11_build_reg_cache(target_t *target); + + +/* internals */ + +void arm11_setup_field (arm11_common_t * arm11, int num_bits, void * in_data, void * out_data, scan_field_t * field); +void arm11_add_IR (arm11_common_t * arm11, u8 instr, enum tap_state state); +void arm11_add_debug_SCAN_N (arm11_common_t * arm11, u8 chain, enum tap_state state); +void arm11_add_debug_INST (arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state); +u32 arm11_read_DSCR (arm11_common_t * arm11); +void arm11_write_DSCR (arm11_common_t * arm11, u32 dscr); + +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr); + +void arm11_run_instr_data_prepare (arm11_common_t * arm11); +void arm11_run_instr_data_finish (arm11_common_t * arm11); +void arm11_run_instr_no_data (arm11_common_t * arm11, u32 * opcode, size_t count); +void arm11_run_instr_no_data1 (arm11_common_t * arm11, u32 opcode); +void arm11_run_instr_data_to_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_to_core1 (arm11_common_t * arm11, u32 opcode, u32 data); +void arm11_run_instr_data_from_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_from_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 * data); +void arm11_run_instr_data_to_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 data); + + +typedef struct arm11_sc7_action_s +{ + bool write; + u8 address; + u32 value; +} arm11_sc7_action_t; + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count); +void arm11_sc7_clear_bw(arm11_common_t * arm11); + + + +#endif /* ARM11_H */ diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 13b412c5..d77c9535 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -1,611 +1,611 @@ -/*************************************************************************** - * Copyright (C) 2008 digenius technology GmbH. * - * * - * 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. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm11.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 0 -#define JTAG_DEBUG(expr ...) \ - do { \ - log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \ - } while(0) -#else -#define JTAG_DEBUG(expr ...) \ - do {} while(0) -#endif - -/** Code de-clutter: Construct scan_field_t to write out a value - * - * \param arm11 Target state variable. - * \param num_bits Length of the data field - * \param out_data pointer to the data that will be sent out - * (data is read when it is added to the JTAG queue) - * \param in_data pointer to the memory that will receive data that was clocked in - * (data is written when the JTAG queue is executed) - * \param field target data structure that will be initialized - */ -void arm11_setup_field(arm11_common_t * arm11, int num_bits, void * out_data, void * in_data, scan_field_t * field) -{ - field->device = arm11->jtag_info.chain_pos; - field->num_bits = num_bits; - field->out_mask = NULL; - field->in_check_mask = NULL; - field->in_check_value = NULL; - field->in_handler = NULL; - field->in_handler_priv = NULL; - - field->out_value = out_data; - field->in_value = in_data; -} - - -/** Write JTAG instruction register - * - * \param arm11 Target state variable. - * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. - * \param state Pass the final TAP state or -1 for the default value (Pause-IR). - * - * \remarks This adds to the JTAG command queue but does \em not execute it. - */ -void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state) -{ - jtag_device_t *device = jtag_get_device(arm11->jtag_info.chain_pos); - - if (buf_get_u32(device->cur_instr, 0, 5) == instr) - { - JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); - return; - } - - JTAG_DEBUG("IR <= 0x%02x", instr); - - scan_field_t field; - - arm11_setup_field(arm11, 5, &instr, NULL, &field); - - jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state); -} - -/** Verify shifted out data from Scan Chain Register (SCREG) - * Used as parameter to scan_field_t::in_handler in - * arm11_add_debug_SCAN_N(). - * - */ -static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field) -{ - /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */ - u8 v = *in_value & 0x1F; - - if (v != 0x10) - { - ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v); - exit(-1); - } - - JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); - return ERROR_OK; -} - -/** Select and write to Scan Chain Register (SCREG) - * - * This function sets the instruction register to SCAN_N and writes - * the data register with the selected chain number. - * - * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html - * - * \param arm11 Target state variable. - * \param chain Scan chain that will be selected. - * \param state Pass the final TAP state or -1 for the default - * value (Pause-DR). - * - * The chain takes effect when Update-DR is passed (usually when subsequently - * the INTEXT/EXTEST instructions are written). - * - * \warning (Obsolete) Using this twice in a row will \em fail. The first call will end - * in Pause-DR. The second call, due to the IR caching, will not - * go through Capture-DR when shifting in the new scan chain number. - * As a result the verification in arm11_in_handler_SCAN_N() must - * fail. - * - * \remarks This adds to the JTAG command queue but does \em not execute it. - */ - -void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state state) -{ - JTAG_DEBUG("SCREG <= 0x%02x", chain); - - arm11_add_IR(arm11, ARM11_SCAN_N, -1); - - scan_field_t field; - - arm11_setup_field(arm11, 5, &chain, NULL, &field); - - field.in_handler = arm11_in_handler_SCAN_N; - - jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state); -} - -/** Write an instruction into the ITR register - * - * \param arm11 Target state variable. - * \param inst An ARM11 processor instruction/opcode. - * \param flag Optional parameter to retrieve the InstCompl flag - * (this will be written when the JTAG chain is executed). - * \param state Pass the final TAP state or -1 for the default - * value (Run-Test/Idle). - * - * \remarks By default this ends with Run-Test/Idle state - * and causes the instruction to be executed. If - * a subsequent write to DTR is needed before - * executing the instruction then TAP_PD should be - * passed to \p state. - * - * \remarks This adds to the JTAG command queue but does \em not execute it. - */ -void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state) -{ - JTAG_DEBUG("INST <= 0x%08x", inst); - - scan_field_t itr[2]; - - arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); - arm11_setup_field(arm11, 1, NULL, flag, itr + 1); - - jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state); -} - -/** Read the Debug Status and Control Register (DSCR) - * - * same as CP14 c1 - * - * \param arm11 Target state variable. - * \return DSCR content - * - * \remarks This is a stand-alone function that executes the JTAG command queue. - */ -u32 arm11_read_DSCR(arm11_common_t * arm11) -{ - arm11_add_debug_SCAN_N(arm11, 0x01, -1); - - arm11_add_IR(arm11, ARM11_INTEST, -1); - - u32 dscr; - scan_field_t chain1_field; - - arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); - - jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); - - jtag_execute_queue(); - - if (arm11->last_dscr != dscr) - JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr); - - arm11->last_dscr = dscr; - - return dscr; -} - -/** Write the Debug Status and Control Register (DSCR) - * - * same as CP14 c1 - * - * \param arm11 Target state variable. - * \param dscr DSCR content - * - * \remarks This is a stand-alone function that executes the JTAG command queue. - */ -void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr) -{ - arm11_add_debug_SCAN_N(arm11, 0x01, -1); - - arm11_add_IR(arm11, ARM11_EXTEST, -1); - - scan_field_t chain1_field; - - arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); - - jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); - - jtag_execute_queue(); - - JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr); - - arm11->last_dscr = dscr; -} - - - -/** Get the debug reason from Debug Status and Control Register (DSCR) - * - * \param dscr DSCR value to analyze - * \return Debug reason - * - */ -enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr) -{ - switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK) - { - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: return DBG_REASON_DBGRQ; - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: return DBG_REASON_BREAKPOINT; - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: return DBG_REASON_WATCHPOINT; - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: return DBG_REASON_BREAKPOINT; - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: return DBG_REASON_DBGRQ; - case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: return DBG_REASON_BREAKPOINT; - - default: - return DBG_REASON_DBGRQ; - } -}; - - - -/** Prepare the stage for ITR/DTR operations - * from the arm11_run_instr... group of functions. - * - * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() - * around a block of arm11_run_instr_... calls. - * - * Select scan chain 5 to allow quick access to DTR. When scan - * chain 4 is needed to put in a register the ITRSel instruction - * shortcut is used instead of actually changing the Scan_N - * register. - * - * \param arm11 Target state variable. - * - */ -void arm11_run_instr_data_prepare(arm11_common_t * arm11) -{ - arm11_add_debug_SCAN_N(arm11, 0x05, -1); -} - -/** Cleanup after ITR/DTR operations - * from the arm11_run_instr... group of functions - * - * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() - * around a block of arm11_run_instr_... calls. - * - * Any RTI can lead to an instruction execution when - * scan chains 4 or 5 are selected and the IR holds - * INTEST or EXTEST. So we must disable that before - * any following activities lead to an RTI. - * - * \param arm11 Target state variable. - * - */ -void arm11_run_instr_data_finish(arm11_common_t * arm11) -{ - arm11_add_debug_SCAN_N(arm11, 0x00, -1); -} - - -/** Execute one or multiple instructions via ITR - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode Pointer to sequence of ARM opcodes - * \param count Number of opcodes to execute - * - */ -void arm11_run_instr_no_data(arm11_common_t * arm11, u32 * opcode, size_t count) -{ - arm11_add_IR(arm11, ARM11_ITRSEL, -1); - - while (count--) - { - arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_RTI); - - while (1) - { - u8 flag; - - arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_RTI : TAP_PD); - - jtag_execute_queue(); - - if (flag) - break; - } - } -} - -/** Execute one instruction via ITR - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode - * - */ -void arm11_run_instr_no_data1(arm11_common_t * arm11, u32 opcode) -{ - arm11_run_instr_no_data(arm11, &opcode, 1); -} - - -/** Execute one instruction via ITR repeatedly while - * passing data to the core via DTR on each execution. - * - * The executed instruction \em must read data from DTR. - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode - * \param data Pointer to the data words to be passed to the core - * \param count Number of data words and instruction repetitions - * - */ -void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) -{ - arm11_add_IR(arm11, ARM11_ITRSEL, -1); - - arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD); - - arm11_add_IR(arm11, ARM11_EXTEST, -1); - - scan_field_t chain5_fields[3]; - - u32 Data; - u8 Ready; - u8 nRetry; - - arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); - arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); - arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); - - while (count--) - { - do - { - Data = *data; - - jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI); - jtag_execute_queue(); - - JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); - } - while (!Ready); - - data++; - } - - arm11_add_IR(arm11, ARM11_INTEST, -1); - - do - { - Data = 0; - - jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); - jtag_execute_queue(); - - JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); - } - while (!Ready); - - -} - -/** Execute an instruction via ITR while handing data into the core via DTR. - * - * The executed instruction \em must read data from DTR. - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode - * \param data Data word to be passed to the core via DTR - * - */ -void arm11_run_instr_data_to_core1(arm11_common_t * arm11, u32 opcode, u32 data) -{ - arm11_run_instr_data_to_core(arm11, opcode, &data, 1); -} - - -/** Execute one instruction via ITR repeatedly while - * reading data from the core via DTR on each execution. - * - * The executed instruction \em must write data to DTR. - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode - * \param data Pointer to an array that receives the data words from the core - * \param count Number of data words and instruction repetitions - * - */ -void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) -{ - arm11_add_IR(arm11, ARM11_ITRSEL, -1); - - arm11_add_debug_INST(arm11, opcode, NULL, TAP_RTI); - - arm11_add_IR(arm11, ARM11_INTEST, -1); - - scan_field_t chain5_fields[3]; - - u32 Data; - u8 Ready; - u8 nRetry; - - arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); - arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); - arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); - - while (count--) - { - do - { - jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD); - jtag_execute_queue(); - - JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); - } - while (!Ready); - - *data++ = Data; - } -} - -/** Execute one instruction via ITR - * then load r0 into DTR and read DTR from core. - * - * The first executed instruction (\p opcode) should write data to r0. - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode to write r0 with the value of interest - * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. - * - */ -void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data) -{ - arm11_run_instr_no_data1(arm11, opcode); - - /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ - arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); -} - -/** Load data into core via DTR then move it to r0 then - * execute one instruction via ITR - * - * The final executed instruction (\p opcode) should read data from r0. - * - * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block - * - * \param arm11 Target state variable. - * \param opcode ARM opcode to read r0 act upon it - * \param data Data word that will be written to r0 before \p opcode is executed - * - */ -void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data) -{ - /* MRC p14,0,r0,c0,c5,0 */ - arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); - - arm11_run_instr_no_data1(arm11, opcode); -} - - -void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count) -{ - arm11_add_debug_SCAN_N(arm11, 0x07, -1); - - arm11_add_IR(arm11, ARM11_EXTEST, -1); - - scan_field_t chain7_fields[3]; - - u8 nRW; - u32 DataOut; - u8 AddressOut; - u8 Ready; - u32 DataIn; - u8 AddressIn; - - arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); - arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); - arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); - - {size_t i; - for (i = 0; i < count + 1; i++) - { - if (i < count) - { - nRW = actions[i].write ? 1 : 0; - DataOut = actions[i].value; - AddressOut = actions[i].address; - } - else - { - nRW = 0; - DataOut = 0; - AddressOut = 0; - } - - do - { - JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW); - - jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD); - jtag_execute_queue(); - - JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready); - } - while (!Ready); /* 'nRW' is 'Ready' on read out */ - - if (i > 0) - { - if (actions[i - 1].address != AddressIn) - { - WARNING("Scan chain 7 shifted out unexpected address"); - } - - if (!actions[i - 1].write) - { - actions[i - 1].value = DataIn; - } - else - { - if (actions[i - 1].value != DataIn) - { - WARNING("Scan chain 7 shifted out unexpected data"); - } - } - } - }} - - {size_t i; - for (i = 0; i < count; i++) - { - JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value); - }} -} - -void arm11_sc7_clear_bw(arm11_common_t * arm11) -{ - size_t actions = arm11->brp + arm11->wrp; - - arm11_sc7_action_t clear_bw[actions]; - - {size_t i; - for (i = 0; i < actions; i++) - { - clear_bw[i].write = true; - clear_bw[i].value = 0; - clear_bw[i].address = - i < arm11->brp ? - ARM11_SC7_BCR0 + i : - ARM11_SC7_WCR0 + i - arm11->brp; - }} - - arm11_sc7_run(arm11, clear_bw, actions); -} - +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm11.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define JTAG_DEBUG(expr ...) \ + do { \ + log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) +#else +#define JTAG_DEBUG(expr ...) \ + do {} while(0) +#endif + +/** Code de-clutter: Construct scan_field_t to write out a value + * + * \param arm11 Target state variable. + * \param num_bits Length of the data field + * \param out_data pointer to the data that will be sent out + * (data is read when it is added to the JTAG queue) + * \param in_data pointer to the memory that will receive data that was clocked in + * (data is written when the JTAG queue is executed) + * \param field target data structure that will be initialized + */ +void arm11_setup_field(arm11_common_t * arm11, int num_bits, void * out_data, void * in_data, scan_field_t * field) +{ + field->device = arm11->jtag_info.chain_pos; + field->num_bits = num_bits; + field->out_mask = NULL; + field->in_check_mask = NULL; + field->in_check_value = NULL; + field->in_handler = NULL; + field->in_handler_priv = NULL; + + field->out_value = out_data; + field->in_value = in_data; +} + + +/** Write JTAG instruction register + * + * \param arm11 Target state variable. + * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. + * \param state Pass the final TAP state or -1 for the default value (Pause-IR). + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state) +{ + jtag_device_t *device = jtag_get_device(arm11->jtag_info.chain_pos); + + if (buf_get_u32(device->cur_instr, 0, 5) == instr) + { + JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); + return; + } + + JTAG_DEBUG("IR <= 0x%02x", instr); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &instr, NULL, &field); + + jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state); +} + +/** Verify shifted out data from Scan Chain Register (SCREG) + * Used as parameter to scan_field_t::in_handler in + * arm11_add_debug_SCAN_N(). + * + */ +static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field) +{ + /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */ + u8 v = *in_value & 0x1F; + + if (v != 0x10) + { + ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v); + exit(-1); + } + + JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); + return ERROR_OK; +} + +/** Select and write to Scan Chain Register (SCREG) + * + * This function sets the instruction register to SCAN_N and writes + * the data register with the selected chain number. + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html + * + * \param arm11 Target state variable. + * \param chain Scan chain that will be selected. + * \param state Pass the final TAP state or -1 for the default + * value (Pause-DR). + * + * The chain takes effect when Update-DR is passed (usually when subsequently + * the INTEXT/EXTEST instructions are written). + * + * \warning (Obsolete) Using this twice in a row will \em fail. The first call will end + * in Pause-DR. The second call, due to the IR caching, will not + * go through Capture-DR when shifting in the new scan chain number. + * As a result the verification in arm11_in_handler_SCAN_N() must + * fail. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ + +void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state state) +{ + JTAG_DEBUG("SCREG <= 0x%02x", chain); + + arm11_add_IR(arm11, ARM11_SCAN_N, -1); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &chain, NULL, &field); + + field.in_handler = arm11_in_handler_SCAN_N; + + jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state); +} + +/** Write an instruction into the ITR register + * + * \param arm11 Target state variable. + * \param inst An ARM11 processor instruction/opcode. + * \param flag Optional parameter to retrieve the InstCompl flag + * (this will be written when the JTAG chain is executed). + * \param state Pass the final TAP state or -1 for the default + * value (Run-Test/Idle). + * + * \remarks By default this ends with Run-Test/Idle state + * and causes the instruction to be executed. If + * a subsequent write to DTR is needed before + * executing the instruction then TAP_PD should be + * passed to \p state. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state) +{ + JTAG_DEBUG("INST <= 0x%08x", inst); + + scan_field_t itr[2]; + + arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); + arm11_setup_field(arm11, 1, NULL, flag, itr + 1); + + jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state); +} + +/** Read the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \return DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +u32 arm11_read_DSCR(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + u32 dscr; + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + if (arm11->last_dscr != dscr) + JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; + + return dscr; +} + +/** Write the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \param dscr DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; +} + + + +/** Get the debug reason from Debug Status and Control Register (DSCR) + * + * \param dscr DSCR value to analyze + * \return Debug reason + * + */ +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr) +{ + switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK) + { + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: return DBG_REASON_WATCHPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: return DBG_REASON_BREAKPOINT; + + default: + return DBG_REASON_DBGRQ; + } +}; + + + +/** Prepare the stage for ITR/DTR operations + * from the arm11_run_instr... group of functions. + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Select scan chain 5 to allow quick access to DTR. When scan + * chain 4 is needed to put in a register the ITRSel instruction + * shortcut is used instead of actually changing the Scan_N + * register. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_prepare(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x05, -1); +} + +/** Cleanup after ITR/DTR operations + * from the arm11_run_instr... group of functions + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Any RTI can lead to an instruction execution when + * scan chains 4 or 5 are selected and the IR holds + * INTEST or EXTEST. So we must disable that before + * any following activities lead to an RTI. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_finish(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x00, -1); +} + + +/** Execute one or multiple instructions via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode Pointer to sequence of ARM opcodes + * \param count Number of opcodes to execute + * + */ +void arm11_run_instr_no_data(arm11_common_t * arm11, u32 * opcode, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + while (count--) + { + arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_RTI); + + while (1) + { + u8 flag; + + arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_RTI : TAP_PD); + + jtag_execute_queue(); + + if (flag) + break; + } + } +} + +/** Execute one instruction via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * + */ +void arm11_run_instr_no_data1(arm11_common_t * arm11, u32 opcode) +{ + arm11_run_instr_no_data(arm11, &opcode, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * passing data to the core via DTR on each execution. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to the data words to be passed to the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + Data = *data; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); + } + while (!Ready); + + data++; + } + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + do + { + Data = 0; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + +} + +/** Execute an instruction via ITR while handing data into the core via DTR. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Data word to be passed to the core via DTR + * + */ +void arm11_run_instr_data_to_core1(arm11_common_t * arm11, u32 opcode, u32 data) +{ + arm11_run_instr_data_to_core(arm11, opcode, &data, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * reading data from the core via DTR on each execution. + * + * The executed instruction \em must write data to DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to an array that receives the data words from the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_RTI); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + *data++ = Data; + } +} + +/** Execute one instruction via ITR + * then load r0 into DTR and read DTR from core. + * + * The first executed instruction (\p opcode) should write data to r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to write r0 with the value of interest + * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. + * + */ +void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data) +{ + arm11_run_instr_no_data1(arm11, opcode); + + /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); +} + +/** Load data into core via DTR then move it to r0 then + * execute one instruction via ITR + * + * The final executed instruction (\p opcode) should read data from r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to read r0 act upon it + * \param data Data word that will be written to r0 before \p opcode is executed + * + */ +void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data) +{ + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); + + arm11_run_instr_no_data1(arm11, opcode); +} + + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count) +{ + arm11_add_debug_SCAN_N(arm11, 0x07, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain7_fields[3]; + + u8 nRW; + u32 DataOut; + u8 AddressOut; + u8 Ready; + u32 DataIn; + u8 AddressIn; + + arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); + arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); + arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); + + {size_t i; + for (i = 0; i < count + 1; i++) + { + if (i < count) + { + nRW = actions[i].write ? 1 : 0; + DataOut = actions[i].value; + AddressOut = actions[i].address; + } + else + { + nRW = 0; + DataOut = 0; + AddressOut = 0; + } + + do + { + JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW); + + jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready); + } + while (!Ready); /* 'nRW' is 'Ready' on read out */ + + if (i > 0) + { + if (actions[i - 1].address != AddressIn) + { + WARNING("Scan chain 7 shifted out unexpected address"); + } + + if (!actions[i - 1].write) + { + actions[i - 1].value = DataIn; + } + else + { + if (actions[i - 1].value != DataIn) + { + WARNING("Scan chain 7 shifted out unexpected data"); + } + } + } + }} + + {size_t i; + for (i = 0; i < count; i++) + { + JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value); + }} +} + +void arm11_sc7_clear_bw(arm11_common_t * arm11) +{ + size_t actions = arm11->brp + arm11->wrp; + + arm11_sc7_action_t clear_bw[actions]; + + {size_t i; + for (i = 0; i < actions; i++) + { + clear_bw[i].write = true; + clear_bw[i].value = 0; + clear_bw[i].address = + i < arm11->brp ? + ARM11_SC7_BCR0 + i : + ARM11_SC7_WCR0 + i - arm11->brp; + }} + + arm11_sc7_run(arm11, clear_bw, actions); +} + diff --git a/src/target/arm720t.c b/src/target/arm720t.c index 87a1afb4..2c7e2aea 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -1,626 +1,626 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm720t.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 0 -#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); -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, - .prepare_reset_halt = arm7_9_prepare_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, - .checksum_memory = arm7_9_checksum_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; - - buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - 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; - fields[1].in_value = NULL; - if (in) - { - fields[1].in_handler = arm_jtag_buf_to_u32_flip; - fields[1].in_handler_priv = in; - } else - { - 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", 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_reg); - arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); - 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_reg); - arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); -} - -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) -{ - 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); - } - - USER("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_STATUS_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 = 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, "arm720t specific commands"); - - register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); - - register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - 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); -} - +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm720t.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#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); +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, + .prepare_reset_halt = arm7_9_prepare_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, + .checksum_memory = arm7_9_checksum_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; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + 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; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } else + { + 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", 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_reg); + arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); + 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_reg); + arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); +} + +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) +{ + 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); + } + + USER("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_STATUS_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 = 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, "arm720t specific commands"); + + register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); + + register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + 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); +} + diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 2a149425..af0205d6 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -676,7 +676,7 @@ int arm7_9_handle_target_request(void *priv) return ERROR_OK; } -int arm7_9_poll(target_t *target) +int arm7_9_poll(target_t *target) { int retval; armv4_5_common_t *armv4_5 = target->arch_info; @@ -692,15 +692,15 @@ int arm7_9_poll(target_t *target) embeddedice_read_reg(dbg_stat); if ((retval = jtag_execute_queue()) != ERROR_OK) { - return retval; + return retval; } if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) { DEBUG("DBGACK set, dbg_state->value: 0x%x", buf_get_u32(dbg_stat->value, 0, 32)); - if (target->state == TARGET_UNKNOWN) + if (target->state == TARGET_UNKNOWN) { - WARNING("DBGACK set while target was in unknown state. Reset or initialize target."); + WARNING("DBGACK set while target was in unknown state. Reset or initialize target."); } if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { @@ -718,18 +718,18 @@ int arm7_9_poll(target_t *target) target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } - if (target->state != TARGET_HALTED) - { - WARNING("DBGACK set, but the target did not end up in the halted stated %d", target->state); + if (target->state != TARGET_HALTED) + { + WARNING("DBGACK set, but the target did not end up in the halted stated %d", target->state); } - } + } else { if (target->state != TARGET_DEBUG_RUNNING) target->state = TARGET_RUNNING; } - return ERROR_OK; + return ERROR_OK; } int arm7_9_assert_reset(target_t *target) diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 5679bbc6..d8d5e57e 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -1,874 +1,874 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#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 -#include - -#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 */ -int arm7tdmi_poll(struct target_s *target); -int arm7tdmi_halt(target_t *target); - -target_type_t arm7tdmi_target = -{ - .name = "arm7tdmi", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .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, - .prepare_reset_halt = arm7_9_prepare_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, - .checksum_memory = arm7_9_checksum_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, NULL); - - 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; - - buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); - 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, NULL); - - 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; - fields[1].in_value = NULL; - if (in) - { - fields[1].in_handler = arm_jtag_buf_to_u32_flip; - fields[1].in_handler_priv = in; - } - else - { - 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_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in); - } - else - DEBUG("out: 0x%8.8x", out); -} -#endif - - return ERROR_OK; -} - -/* clock the target, reading the databus */ -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, NULL); - - 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 = NULL; - 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_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } -} -#endif - - return ERROR_OK; -} - -/* clock the target, and read the databus - * the *in pointer points to a buffer where elements of 'size' bytes - * are stored in big (be==1) or little (be==0) endianness - */ -int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) -{ - 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, NULL); - - 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 = NULL; - switch (size) - { - case 4: - fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip; - break; - case 2: - fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip; - break; - case 1: - fields[1].in_handler = arm_jtag_buf_to_8_flip; - break; - } - 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_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } -} -#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); - - /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(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, data for LDR r0, [PC, #0] */ - arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); - /* nothing fetched, data from previous cycle is written to register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 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_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) -{ - 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; - int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; - u32 *buf_u32 = buffer; - u16 *buf_u16 = buffer; - u8 *buf_u8 = buffer; - - /* 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++) - { - /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */ - if (mask & (1 << i)) - { - switch (size) - { - case 4: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; - } - } - } - -} - -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); - - /* load r0 value */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); - /* fetch NOP, LDR in Decode */ - 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(0x7f8), 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; - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); - arm7_9->eice_cache = (*cache_p)->next; - - if (arm7_9->etm_ctx) - { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); - arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; - } -} - -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; - - 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_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; - 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 */ - arm7_9->arm_bkpt = 0xdeeedeee; - arm7_9->thumb_bkpt = 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->arch_info = NULL; - arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC; - - if (variant) - { - arm7tdmi->variant = strdup(variant); - } - else - { - arm7tdmi->variant = strdup(""); - } - - arm7_9_init_arch_info(target, arm7_9); - - return ERROR_OK; -} - -/* target arm7tdmi */ -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[3], 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; - -} - +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 +#include + +#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 */ +int arm7tdmi_poll(struct target_s *target); +int arm7tdmi_halt(target_t *target); + +target_type_t arm7tdmi_target = +{ + .name = "arm7tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .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, + .prepare_reset_halt = arm7_9_prepare_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, + .checksum_memory = arm7_9_checksum_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, NULL); + + 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; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + 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, NULL); + + 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; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } + else + { + 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_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in); + } + else + DEBUG("out: 0x%8.8x", out); +} +#endif + + return ERROR_OK; +} + +/* clock the target, reading the databus */ +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, NULL); + + 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 = NULL; + 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_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + 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, NULL); + + 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 = NULL; + switch (size) + { + case 4: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip; + break; + case 2: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip; + break; + case 1: + fields[1].in_handler = arm_jtag_buf_to_8_flip; + break; + } + 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_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#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); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(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, data for LDR r0, [PC, #0] */ + arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); + /* nothing fetched, data from previous cycle is written to register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 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_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + 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; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* 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++) + { + /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */ + if (mask & (1 << i)) + { + switch (size) + { + case 4: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + } + +} + +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); + + /* load r0 value */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + /* fetch NOP, LDR in Decode */ + 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(0x7f8), 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; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +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; + + 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_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; + 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 */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 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->arch_info = NULL; + arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC; + + if (variant) + { + arm7tdmi->variant = strdup(variant); + } + else + { + arm7tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + return ERROR_OK; +} + +/* target arm7tdmi */ +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[3], 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; + +} + diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 17c53973..e9a109a5 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -1,1485 +1,1485 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm920t.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#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); - -int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_read_mmu_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); -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); - -#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) - -target_type_t arm920t_target = -{ - .name = "arm920t", - - .poll = arm7_9_poll, - .arch_state = arm920t_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .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, - .prepare_reset_halt = arm7_9_prepare_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, - .checksum_memory = arm7_9_checksum_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, NULL); - - 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 = ®_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_handler_priv = value; - fields[1].in_handler = arm_jtag_buf_to_u32; - - jtag_add_dr_scan(4, fields, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - jtag_execute_queue(); - DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); -#endif - - 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; - u8 value_buf[4]; - - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - 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 = value_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 = 6; - fields[2].out_value = ®_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); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); -#endif - - return ERROR_OK; -} - -int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode) -{ - 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 = 0; /* interpreted access */ - u8 reg_addr_buf = 0x0; - u8 nr_w_buf = 0; - u8 cp15_opcode_buf[4]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); - - 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 = cp15_opcode_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 = 6; - fields[2].out_value = ®_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, arm_opcode, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - arm7_9_execute_sys_speed(target); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("failed executing JTAG queue, exiting"); - exit(-1); - } - - return ERROR_OK; -} - -int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - u32* regs_p[1]; - u32 regs[2]; - u32 cp15c15 = 0x0; - - /* load address into R1 */ - regs[1] = address; - arm9tdmi_write_core_regs(target, 0x2, 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); - - /* execute CP15 instruction and ARM load (reading from coprocessor) */ - arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); - - /* disable interpreted access mode */ - cp15c15 &= ~1U; /* clear interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* retrieve value from R0 */ - regs_p[0] = value; - arm9tdmi_read_core_regs(target, 0x1, regs_p); - jtag_execute_queue(); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); -#endif - - 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, 1).dirty = 1; - - return ERROR_OK; -} - -int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address) -{ - u32 cp15c15 = 0x0; - armv4_5_common_t *armv4_5 = target->arch_info; - u32 regs[2]; - - /* load value, address into R0, R1 */ - 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); - - /* execute CP15 instruction and ARM store (writing to coprocessor) */ - arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); - - /* disable interpreted access mode */ - cp15c15 &= ~1U; /* set interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); -#endif - - 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, 1).dirty = 1; - - return ERROR_OK; -} - -u32 arm920t_get_ttb(target_t *target) -{ - int retval; - u32 ttb = 0x0; - - if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &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, 0x0, &arm920t->d_fsr); - arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); - arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); - arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); - - DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x", - arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); - - if (arm920t->preserve_cache) - { - /* 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 */ - if (arm920t->preserve_cache) - { - 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) -{ - 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); - } - - USER( "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_STATUS_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; - - /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) - */ - 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; - - /* disabling linefills leads to lockups, so keep them enabled for now - * this doesn't affect correctness, but might affect timing issues, if - * important data is evicted from the cache during the debug session - * */ - arm920t->preserve_cache = 0; - - /* override hw single-step capability from ARM9TDMI */ - arm7_9->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 = 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 [value]"); - register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) [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 "); - - register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content"); - register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content"); - - return ERROR_OK; -} - -int arm920t_handle_read_cache_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; - arm_jtag_t *jtag_info; - u32 cp15c15; - u32 cp15_ctrl, cp15_ctrl_saved; - u32 regs[16]; - u32 *regs_p[16]; - u32 C15_C_D_Ind, C15_C_I_Ind; - int i; - FILE *output; - arm920t_cache_line_t d_cache[8][64], i_cache[8][64]; - int segment, index; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: arm920t read_cache "); - return ERROR_OK; - } - - if ((output = fopen(args[0], "w")) == NULL) - { - DEBUG("error opening cache content file"); - return ERROR_OK; - } - - for (i = 0; i < 16; i++) - regs_p[i] = ®s[i]; - - 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; - - /* disable MMU and Caches */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); - jtag_execute_queue(); - cp15_ctrl_saved = cp15_ctrl; - cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); - - /* read CP15 test state register */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); - jtag_execute_queue(); - - /* read DCache content */ - fprintf(output, "DCache:\n"); - - /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ - for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) - { - fprintf(output, "\nsegment: %i\n----------", segment); - - /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* D CAM Read, loads current victim into C15.C.D.Ind */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0)); - - /* read current victim */ - arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - for (index = 0; index < 64; index++) - { - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (index << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write DCache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); - - /* Read D RAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); - - /* Read D CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D RAM and CAM content */ - arm9tdmi_read_core_regs(target, 0x3fe, regs_p); - jtag_execute_queue(); - - d_cache[segment][index].cam = regs[9]; - - /* mask LFSR[6] */ - regs[9] &= 0xfffffffe; - fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); - - for (i = 1; i < 9; i++) - { - d_cache[segment][index].data[i] = regs[i]; - fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); - } - - } - - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write DCache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } - - /* read ICache content */ - fprintf(output, "ICache:\n"); - - /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ - for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) - { - fprintf(output, "segment: %i\n----------", segment); - - /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* I CAM Read, loads current victim into C15.C.I.Ind */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0)); - - /* read current victim */ - arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - for (index = 0; index < 64; index++) - { - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (index << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write ICache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); - - /* Read I RAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); - - /* Read I CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I RAM and CAM content */ - arm9tdmi_read_core_regs(target, 0x3fe, regs_p); - jtag_execute_queue(); - - i_cache[segment][index].cam = regs[9]; - - /* mask LFSR[6] */ - regs[9] &= 0xfffffffe; - fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); - - for (i = 1; i < 9; i++) - { - i_cache[segment][index].data[i] = regs[i]; - fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); - } - - } - - - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write ICache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } - - /* restore CP15 MMU and Cache settings */ - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); - - command_print(cmd_ctx, "cache content successfully output to %s", args[0]); - - fclose(output); - - /* mark registers dirty. */ - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; - - return ERROR_OK; -} - -int arm920t_handle_read_mmu_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; - arm_jtag_t *jtag_info; - u32 cp15c15; - u32 cp15_ctrl, cp15_ctrl_saved; - u32 regs[16]; - u32 *regs_p[16]; - int i; - FILE *output; - u32 Dlockdown, Ilockdown; - arm920t_tlb_entry_t d_tlb[64], i_tlb[64]; - int victim; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: arm920t read_mmu "); - return ERROR_OK; - } - - if ((output = fopen(args[0], "w")) == NULL) - { - DEBUG("error opening mmu content file"); - return ERROR_OK; - } - - for (i = 0; i < 16; i++) - regs_p[i] = ®s[i]; - - 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; - - /* disable MMU and Caches */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); - jtag_execute_queue(); - cp15_ctrl_saved = cp15_ctrl; - cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); - - /* read CP15 test state register */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); - jtag_execute_queue(); - - /* prepare reading D TLB content - * */ - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Read D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB lockdown stored to r1 */ - arm9tdmi_read_core_regs(target, 0x2, regs_p); - jtag_execute_queue(); - Dlockdown = regs[1]; - - for (victim = 0; victim < 64; victim += 8) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* Read D TLB CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB CAM content stored to r2-r9 */ - arm9tdmi_read_core_regs(target, 0x3fc, regs_p); - jtag_execute_queue(); - - for (i = 0; i < 8; i++) - d_tlb[victim + i].cam = regs[i + 2]; - } - - for (victim = 0; victim < 64; victim++) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* Read D TLB RAM1 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0)); - - /* Read D TLB RAM2 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB RAM content stored to r2 and r3 */ - arm9tdmi_read_core_regs(target, 0xc, regs_p); - jtag_execute_queue(); - - d_tlb[victim].ram1 = regs[2]; - d_tlb[victim].ram2 = regs[3]; - } - - /* restore D TLB lockdown */ - regs[1] = Dlockdown; - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* prepare reading I TLB content - * */ - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Read I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB lockdown stored to r1 */ - arm9tdmi_read_core_regs(target, 0x2, regs_p); - jtag_execute_queue(); - Ilockdown = regs[1]; - - for (victim = 0; victim < 64; victim += 8) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* Read I TLB CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB CAM content stored to r2-r9 */ - arm9tdmi_read_core_regs(target, 0x3fc, regs_p); - jtag_execute_queue(); - - for (i = 0; i < 8; i++) - i_tlb[i + victim].cam = regs[i + 2]; - } - - for (victim = 0; victim < 64; victim++) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* Read I TLB RAM1 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0)); - - /* Read I TLB RAM2 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB RAM content stored to r2 and r3 */ - arm9tdmi_read_core_regs(target, 0xc, regs_p); - jtag_execute_queue(); - - i_tlb[victim].ram1 = regs[2]; - i_tlb[victim].ram2 = regs[3]; - } - - /* restore I TLB lockdown */ - regs[1] = Ilockdown; - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* restore CP15 MMU and Cache settings */ - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); - - /* output data to file */ - fprintf(output, "D TLB content:\n"); - for (i = 0; i < 64; i++) - { - fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); - } - - fprintf(output, "\n\nI TLB content:\n"); - for (i = 0; i < 64; i++) - { - fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); - } - - command_print(cmd_ctx, "mmu content successfully output to %s", args[0]); - - fclose(output); - - /* mark registers dirty */ - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; - - 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, 0x0, &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); - } - } - else - { - command_print(cmd_ctx, "usage: arm920t cp15i [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); -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm920t.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#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); + +int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_read_mmu_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); +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); + +#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) + +target_type_t arm920t_target = +{ + .name = "arm920t", + + .poll = arm7_9_poll, + .arch_state = arm920t_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .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, + .prepare_reset_halt = arm7_9_prepare_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, + .checksum_memory = arm7_9_checksum_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, NULL); + + 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 = ®_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_handler_priv = value; + fields[1].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(4, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + 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; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + 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 = value_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 = 6; + fields[2].out_value = ®_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); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode) +{ + 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 = 0; /* interpreted access */ + u8 reg_addr_buf = 0x0; + u8 nr_w_buf = 0; + u8 cp15_opcode_buf[4]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); + + 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 = cp15_opcode_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 = 6; + fields[2].out_value = ®_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, arm_opcode, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + arm7_9_execute_sys_speed(target); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("failed executing JTAG queue, exiting"); + exit(-1); + } + + return ERROR_OK; +} + +int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + u32* regs_p[1]; + u32 regs[2]; + u32 cp15c15 = 0x0; + + /* load address into R1 */ + regs[1] = address; + arm9tdmi_write_core_regs(target, 0x2, 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); + + /* execute CP15 instruction and ARM load (reading from coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* clear interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* retrieve value from R0 */ + regs_p[0] = value; + arm9tdmi_read_core_regs(target, 0x1, regs_p); + jtag_execute_queue(); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); +#endif + + 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, 1).dirty = 1; + + return ERROR_OK; +} + +int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address) +{ + u32 cp15c15 = 0x0; + armv4_5_common_t *armv4_5 = target->arch_info; + u32 regs[2]; + + /* load value, address into R0, R1 */ + 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); + + /* execute CP15 instruction and ARM store (writing to coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); +#endif + + 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, 1).dirty = 1; + + return ERROR_OK; +} + +u32 arm920t_get_ttb(target_t *target) +{ + int retval; + u32 ttb = 0x0; + + if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &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, 0x0, &arm920t->d_fsr); + arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); + arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); + arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x", + arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); + + if (arm920t->preserve_cache) + { + /* 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 */ + if (arm920t->preserve_cache) + { + 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) +{ + 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); + } + + USER( "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_STATUS_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; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + 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; + + /* disabling linefills leads to lockups, so keep them enabled for now + * this doesn't affect correctness, but might affect timing issues, if + * important data is evicted from the cache during the debug session + * */ + arm920t->preserve_cache = 0; + + /* override hw single-step capability from ARM9TDMI */ + arm7_9->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 = 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 [value]"); + register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) [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 "); + + register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content"); + register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content"); + + return ERROR_OK; +} + +int arm920t_handle_read_cache_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; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + u32 C15_C_D_Ind, C15_C_I_Ind; + int i; + FILE *output; + arm920t_cache_line_t d_cache[8][64], i_cache[8][64]; + int segment, index; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_cache "); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening cache content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + 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; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* read DCache content */ + fprintf(output, "DCache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "\nsegment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* D CAM Read, loads current victim into C15.C.D.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* Read D RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read D CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + d_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + d_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* read ICache content */ + fprintf(output, "ICache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "segment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* I CAM Read, loads current victim into C15.C.I.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* Read I RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read I CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + i_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + i_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + command_print(cmd_ctx, "cache content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty. */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + return ERROR_OK; +} + +int arm920t_handle_read_mmu_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; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + int i; + FILE *output; + u32 Dlockdown, Ilockdown; + arm920t_tlb_entry_t d_tlb[64], i_tlb[64]; + int victim; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_mmu "); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening mmu content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + 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; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* prepare reading D TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Dlockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + d_tlb[victim + i].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0)); + + /* Read D TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + d_tlb[victim].ram1 = regs[2]; + d_tlb[victim].ram2 = regs[3]; + } + + /* restore D TLB lockdown */ + regs[1] = Dlockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* prepare reading I TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Ilockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + i_tlb[i + victim].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0)); + + /* Read I TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + i_tlb[victim].ram1 = regs[2]; + i_tlb[victim].ram2 = regs[3]; + } + + /* restore I TLB lockdown */ + regs[1] = Ilockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + /* output data to file */ + fprintf(output, "D TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + fprintf(output, "\n\nI TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + command_print(cmd_ctx, "mmu content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + 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, 0x0, &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); + } + } + else + { + command_print(cmd_ctx, "usage: arm920t cp15i [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); +} diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index a02c27ae..afe9226c 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -1,944 +1,944 @@ -/*************************************************************************** - * Copyright (C) 2007 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm926ejs.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 1 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm926ejs_register_commands(struct command_context_s *cmd_ctx); - -int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* forward declarations */ -int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm926ejs_quit(); -int arm926ejs_arch_state(struct target_s *target); -int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm926ejs_soft_reset_halt(struct target_s *target); -static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical); -static int arm926ejs_mmu(struct target_s *target, int *enabled); - -target_type_t arm926ejs_target = -{ - .name = "arm926ejs", - - .poll = arm7_9_poll, - .arch_state = arm926ejs_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .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 = arm926ejs_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm7_9_read_memory, - .write_memory = arm926ejs_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_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 = arm926ejs_register_commands, - .target_command = arm926ejs_target_command, - .init_target = arm926ejs_init_target, - .quit = arm926ejs_quit, - .virt2phys = arm926ejs_virt2phys, - .mmu = arm926ejs_mmu -}; - - -int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field) -{ - /* The ARM926EJ-S' instruction register is 4 bits wide */ - u8 t = *captured & 0xf; - u8 t2 = *field->in_check_value & 0xf; - if (t == t2) - { - return ERROR_OK; - } - else if ((t == 0x0f) || (t == 0x00)) - { - DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access"); - return ERROR_OK; - } - return ERROR_JTAG_QUEUE_FAILED;; -} - -#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) - -int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, 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; - u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); - scan_field_t fields[4]; - u8 address_buf[2]; - u8 nr_w_buf = 0; - u8 access = 1; - - buf_set_u32(address_buf, 0, 14, address); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - 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 = 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 = 1; - fields[1].out_value = &access; - fields[1].out_mask = NULL; - fields[1].in_value = &access; - 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 = 14; - fields[2].out_value = address_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[0].in_handler_priv = value; - fields[0].in_handler = arm_jtag_buf_to_u32; - - do - { - /* rescan with NOP, to wait for the access to complete */ - access = 0; - nr_w_buf = 0; - jtag_add_dr_scan(4, fields, -1); - jtag_execute_queue(); - } while (buf_get_u32(&access, 0, 1) != 1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", address, *value); -#endif - - arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan); - - return ERROR_OK; -} - -int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, 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; - u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); - scan_field_t fields[4]; - u8 value_buf[4]; - u8 address_buf[2]; - u8 nr_w_buf = 1; - u8 access = 1; - - buf_set_u32(address_buf, 0, 14, address); - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = value_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 = 1; - fields[1].out_value = &access; - fields[1].out_mask = NULL; - fields[1].in_value = &access; - 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 = 14; - fields[2].out_value = address_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); - - do - { - /* rescan with NOP, to wait for the access to complete */ - access = 0; - nr_w_buf = 0; - jtag_add_dr_scan(4, fields, -1); - jtag_execute_queue(); - } while (buf_get_u32(&access, 0, 1) != 1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", address, value); -#endif - - arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan); - - return ERROR_OK; -} - -int arm926ejs_examine_debug_reason(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - int debug_reason; - int retval; - - embeddedice_read_reg(dbg_stat); - if ((retval = jtag_execute_queue()) != ERROR_OK) - return retval; - - debug_reason = buf_get_u32(dbg_stat->value, 6, 4); - - switch (debug_reason) - { - case 1: - DEBUG("breakpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 2: - DEBUG("breakpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 3: - DEBUG("soft breakpoint (BKPT instruction)"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 4: - DEBUG("vector catch breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 5: - DEBUG("external breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 6: - DEBUG("watchpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 7: - DEBUG("watchpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 8: - DEBUG("external watchpoint"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 9: - DEBUG("internal debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 10: - DEBUG("external debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 11: - ERROR("BUG: debug re-entry from system speed access shouldn't be handled here"); - break; - default: - ERROR("BUG: unknown debug reason: 0x%x", debug_reason); - target->debug_reason = DBG_REASON_DBGRQ; - } - - return ERROR_OK; -} - -u32 arm926ejs_get_ttb(target_t *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; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - int retval; - u32 ttb = 0x0; - - if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK) - return retval; - - return ttb; -} - -void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - 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; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); - jtag_execute_queue(); - - if (mmu) - { - /* invalidate TLB */ - arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); - - cp15_control &= ~0x1U; - } - - if (d_u_cache) - { - u32 debug_override; - /* read-modify-write CP15 debug override register - * to enable "test and clean all" */ - arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); - debug_override |= 0x80000; - arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); - - /* clean and invalidate DCache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); - - /* write CP15 debug override register - * to disable "test and clean all" */ - debug_override &= ~0x80000; - arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); - - cp15_control &= ~0x4U; - } - - if (i_cache) - { - /* invalidate ICache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); - - cp15_control &= ~0x1000U; - } - - arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); -} - -void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - 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; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache) - cp15_control |= 0x4U; - - if (i_cache) - cp15_control |= 0x1000U; - - arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); -} - -void arm926ejs_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; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - /* examine cp15 control reg */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); - jtag_execute_queue(); - DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg); - - if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) - { - u32 cache_type_reg; - /* identify caches */ - arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); - jtag_execute_queue(); - armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); - } - - arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; - - /* save i/d fault status and address register */ - arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); - arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); - arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); - - DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x", - arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); - - - u32 cache_dbg_ctrl; - - /* read-modify-write CP15 cache debug control register - * to disable I/D-cache linefills and force WT */ - arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); - cache_dbg_ctrl |= 0x7; - arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); -} - -void arm926ejs_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; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - /* restore i/d fault status and address register */ - arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); - arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); - arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); - - u32 cache_dbg_ctrl; - - /* read-modify-write CP15 cache debug control register - * to reenable I/D-cache linefills and disable WT */ - arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); - cache_dbg_ctrl &= ~0x7; - arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); -} - -int arm926ejs_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, arm926ejs_common_t **arm926ejs_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - - 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; - } - - arm926ejs = arm9tdmi->arch_info; - if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - *arm926ejs_p = arm926ejs; - - return ERROR_OK; -} - -int arm926ejs_arch_state(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; - arm926ejs_common_t *arm926ejs = 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); - } - - USER( - "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[arm926ejs->armv4_5_mmu.mmu_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); - - return ERROR_OK; -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs = 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_STATUS_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; - - arm926ejs_disable_mmu_caches(target, 1, 1, 1); - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) - return retval; - - /* If ICache is enabled, we have to invalidate affected ICache lines - * the DCache is forced to write-through, so we don't have to clean it here - */ - if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) - { - if (count <= 1) - { - /* invalidate ICache single entry with MVA */ - arm926ejs->write_cp15(target, 0, 1, 7, 5, address); - } - else - { - /* invalidate ICache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, address); - } - } - - return retval; -} - -int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm9tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; - -} - -int arm926ejs_quit() -{ - - return ERROR_OK; -} - -int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant) -{ - arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common; - arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; - - /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) - */ - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - arm9tdmi->arch_info = arm926ejs; - arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; - - arm7_9->post_debug_entry = arm926ejs_post_debug_entry; - arm7_9->pre_restore_context = arm926ejs_pre_restore_context; - - arm926ejs->read_cp15 = arm926ejs_cp15_read; - arm926ejs->write_cp15 = arm926ejs_cp15_write; - arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; - arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; - arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; - arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; - arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; - arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; - arm926ejs->armv4_5_mmu.has_tiny_pages = 1; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - - arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; - - /* The ARM926EJ-S implements the ARMv5TE architecture which - * has the BKPT instruction, so we don't have to use a watchpoint comparator - */ - arm7_9->arm_bkpt = ARMV5_BKPT(0x0); - arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - arm7_9->sw_bkpts_use_wp = 0; - arm7_9->sw_bkpts_enabled = 1; - - return ERROR_OK; -} - -int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t)); - - if (argc < 4) - { - ERROR("'target arm926ejs' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant); - - return ERROR_OK; -} - -int arm926ejs_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm926ejs_cmd; - - - retval = arm9tdmi_register_commands(cmd_ctx); - - arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands"); - - register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - - register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); - register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); - - register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - return ERROR_OK; -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs; - int opcode_1; - int opcode_2; - int CRn; - int CRm; - - if ((argc < 4) || (argc > 5)) - { - command_print(cmd_ctx, "usage: arm926ejs cp15 [value]"); - return ERROR_OK; - } - - opcode_1 = strtoul(args[0], NULL, 0); - opcode_2 = strtoul(args[1], NULL, 0); - CRn = strtoul(args[2], NULL, 0); - CRm = strtoul(args[3], NULL, 0); - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc == 4) - { - u32 value; - if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access register"); - return ERROR_OK; - } - jtag_execute_queue(); - - command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); - } - else - { - u32 value = strtoul(args[4], NULL, 0); - if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access register"); - return ERROR_OK; - } - command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); - } - - return ERROR_OK; -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache); -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); -} - -int arm926ejs_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; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); -} -static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - int retval; - int type; - u32 cb; - int domain; - u32 ap; - - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs); - if (retval != ERROR_OK) - { - return retval; - } - u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); - if (type == -1) - { - return ret; - } - *physical = ret; - return ERROR_OK; -} - -static int arm926ejs_mmu(struct target_s *target, int *enabled) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm926ejs_common_t *arm926ejs = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_INVALID; - } - *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2007 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm926ejs.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 1 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm926ejs_register_commands(struct command_context_s *cmd_ctx); + +int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm926ejs_quit(); +int arm926ejs_arch_state(struct target_s *target); +int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_soft_reset_halt(struct target_s *target); +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int arm926ejs_mmu(struct target_s *target, int *enabled); + +target_type_t arm926ejs_target = +{ + .name = "arm926ejs", + + .poll = arm7_9_poll, + .arch_state = arm926ejs_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .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 = arm926ejs_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm926ejs_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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 = arm926ejs_register_commands, + .target_command = arm926ejs_target_command, + .init_target = arm926ejs_init_target, + .quit = arm926ejs_quit, + .virt2phys = arm926ejs_virt2phys, + .mmu = arm926ejs_mmu +}; + + +int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field) +{ + /* The ARM926EJ-S' instruction register is 4 bits wide */ + u8 t = *captured & 0xf; + u8 t2 = *field->in_check_value & 0xf; + if (t == t2) + { + return ERROR_OK; + } + else if ((t == 0x0f) || (t == 0x00)) + { + DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access"); + return ERROR_OK; + } + return ERROR_JTAG_QUEUE_FAILED;; +} + +#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) + +int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, 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; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 address_buf[2]; + u8 nr_w_buf = 0; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + 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 = 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 = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + 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 = 14; + fields[2].out_value = address_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[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, *value); +#endif + + arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, 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; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 value_buf[4]; + u8 address_buf[2]; + u8 nr_w_buf = 1; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_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 = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + 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 = 14; + fields[2].out_value = address_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); + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, value); +#endif + + arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_examine_debug_reason(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + int debug_reason; + int retval; + + embeddedice_read_reg(dbg_stat); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + debug_reason = buf_get_u32(dbg_stat->value, 6, 4); + + switch (debug_reason) + { + case 1: + DEBUG("breakpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 2: + DEBUG("breakpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 3: + DEBUG("soft breakpoint (BKPT instruction)"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 4: + DEBUG("vector catch breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 5: + DEBUG("external breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 6: + DEBUG("watchpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 7: + DEBUG("watchpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 8: + DEBUG("external watchpoint"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 9: + DEBUG("internal debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 10: + DEBUG("external debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 11: + ERROR("BUG: debug re-entry from system speed access shouldn't be handled here"); + break; + default: + ERROR("BUG: unknown debug reason: 0x%x", debug_reason); + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +u32 arm926ejs_get_ttb(target_t *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; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + int retval; + u32 ttb = 0x0; + + if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK) + return retval; + + return ttb; +} + +void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + 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; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + { + /* invalidate TLB */ + arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); + + cp15_control &= ~0x1U; + } + + if (d_u_cache) + { + u32 debug_override; + /* read-modify-write CP15 debug override register + * to enable "test and clean all" */ + arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); + debug_override |= 0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + /* clean and invalidate DCache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + /* write CP15 debug override register + * to disable "test and clean all" */ + debug_override &= ~0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + cp15_control &= ~0x1000U; + } + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + 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; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_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; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* examine cp15 control reg */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg); + + if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + /* identify caches */ + arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); + jtag_execute_queue(); + armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); + } + + arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* save i/d fault status and address register */ + arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); + arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); + arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x", + arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); + + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to disable I/D-cache linefills and force WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl |= 0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +void arm926ejs_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; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); + arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); + arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to reenable I/D-cache linefills and disable WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl &= ~0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +int arm926ejs_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, arm926ejs_common_t **arm926ejs_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + + 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; + } + + arm926ejs = arm9tdmi->arch_info; + if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm926ejs_p = arm926ejs; + + return ERROR_OK; +} + +int arm926ejs_arch_state(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; + arm926ejs_common_t *arm926ejs = 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); + } + + USER( + "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[arm926ejs->armv4_5_mmu.mmu_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + + return ERROR_OK; +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs = 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_STATUS_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; + + arm926ejs_disable_mmu_caches(target, 1, 1, 1); + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + /* If ICache is enabled, we have to invalidate affected ICache lines + * the DCache is forced to write-through, so we don't have to clean it here + */ + if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + if (count <= 1) + { + /* invalidate ICache single entry with MVA */ + arm926ejs->write_cp15(target, 0, 1, 7, 5, address); + } + else + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, address); + } + } + + return retval; +} + +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm926ejs_quit() +{ + + return ERROR_OK; +} + +int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm926ejs; + arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm926ejs_post_debug_entry; + arm7_9->pre_restore_context = arm926ejs_pre_restore_context; + + arm926ejs->read_cp15 = arm926ejs_cp15_read; + arm926ejs->write_cp15 = arm926ejs_cp15_write; + arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; + arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; + arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; + arm926ejs->armv4_5_mmu.has_tiny_pages = 1; + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + + arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; + + /* The ARM926EJ-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t)); + + if (argc < 4) + { + ERROR("'target arm926ejs' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant); + + return ERROR_OK; +} + +int arm926ejs_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm926ejs_cmd; + + + retval = arm9tdmi_register_commands(cmd_ctx); + + arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands"); + + register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + + register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); + register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); + + register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + return ERROR_OK; +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs; + int opcode_1; + int opcode_2; + int CRn; + int CRm; + + if ((argc < 4) || (argc > 5)) + { + command_print(cmd_ctx, "usage: arm926ejs cp15 [value]"); + return ERROR_OK; + } + + opcode_1 = strtoul(args[0], NULL, 0); + opcode_2 = strtoul(args[1], NULL, 0); + CRn = strtoul(args[2], NULL, 0); + CRm = strtoul(args[3], NULL, 0); + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc == 4) + { + u32 value; + if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + else + { + u32 value = strtoul(args[4], NULL, 0); + if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + + return ERROR_OK; +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache); +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_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; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S 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, &arm926ejs->armv4_5_mmu); +} +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs); + if (retval != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + *physical = ret; + return ERROR_OK; +} + +static int arm926ejs_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm926ejs_common_t *arm926ejs = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 1ea2ce77..4ba5d852 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -1,364 +1,364 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm966e.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 -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm966e_register_commands(struct command_context_s *cmd_ctx); - -/* forward declarations */ -int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm966e_quit(void); - -target_type_t arm966e_target = -{ - .name = "arm966e", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .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, - .prepare_reset_halt = arm7_9_prepare_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, - .checksum_memory = arm7_9_checksum_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 = arm966e_register_commands, - .target_command = arm966e_target_command, - .init_target = arm966e_init_target, - .quit = arm966e_quit, -}; - -int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm9tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; -} - -int arm966e_quit(void) -{ - - return ERROR_OK; -} - -int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant) -{ - arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common; - arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; - - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - arm9tdmi->arch_info = arm966e; - arm966e->common_magic = ARM966E_COMMON_MAGIC; - - /* The ARM966E-S implements the ARMv5TE architecture which - * has the BKPT instruction, so we don't have to use a watchpoint comparator - */ - arm7_9->arm_bkpt = ARMV5_BKPT(0x0); - arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - arm7_9->sw_bkpts_use_wp = 0; - arm7_9->sw_bkpts_enabled = 1; - - return ERROR_OK; -} - -int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t)); - - if (argc < 4) - { - ERROR("'target arm966e' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm966e_init_arch_info(target, arm966e, chain_pos, variant); - - return ERROR_OK; -} - -int arm966e_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, arm966e_common_t **arm966e_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm966e_common_t *arm966e; - - 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; - } - - arm966e = arm9tdmi->arch_info; - if (arm966e->common_magic != ARM966E_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - *arm966e_p = arm966e; - - return ERROR_OK; -} - -int arm966e_read_cp15(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[3]; - 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, NULL); - - 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 = 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 = 6; - fields[1].out_value = ®_addr_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 = 1; - fields[2].out_value = &nr_w_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); - - fields[0].in_handler_priv = value; - fields[0].in_handler = arm_jtag_buf_to_u32; - - jtag_add_dr_scan(3, fields, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - jtag_execute_queue(); - DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); -#endif - - return ERROR_OK; -} - -int arm966e_write_cp15(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[3]; - u8 reg_addr_buf = reg_addr & 0x3f; - u8 nr_w_buf = 1; - u8 value_buf[4]; - - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = value_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 = 6; - fields[1].out_value = ®_addr_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 = 1; - fields[2].out_value = &nr_w_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); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); -#endif - - return ERROR_OK; -} - -int arm966e_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; - arm966e_common_t *arm966e; - arm_jtag_t *jtag_info; - - if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM966e 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 = arm966e_read_cp15(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 = arm966e_write_cp15(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 arm966e_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm966e_cmd; - - retval = arm9tdmi_register_commands(cmd_ctx); - arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands"); - register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - - return ERROR_OK; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm966e.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 +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm966e_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm966e_quit(void); + +target_type_t arm966e_target = +{ + .name = "arm966e", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .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, + .prepare_reset_halt = arm7_9_prepare_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, + .checksum_memory = arm7_9_checksum_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 = arm966e_register_commands, + .target_command = arm966e_target_command, + .init_target = arm966e_init_target, + .quit = arm966e_quit, +}; + +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; +} + +int arm966e_quit(void) +{ + + return ERROR_OK; +} + +int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm966e; + arm966e->common_magic = ARM966E_COMMON_MAGIC; + + /* The ARM966E-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t)); + + if (argc < 4) + { + ERROR("'target arm966e' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm966e_init_arch_info(target, arm966e, chain_pos, variant); + + return ERROR_OK; +} + +int arm966e_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, arm966e_common_t **arm966e_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm966e_common_t *arm966e; + + 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; + } + + arm966e = arm9tdmi->arch_info; + if (arm966e->common_magic != ARM966E_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm966e_p = arm966e; + + return ERROR_OK; +} + +int arm966e_read_cp15(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[3]; + 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, NULL); + + 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 = 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 = 6; + fields[1].out_value = ®_addr_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 = 1; + fields[2].out_value = &nr_w_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); + + fields[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(3, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + return ERROR_OK; +} + +int arm966e_write_cp15(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[3]; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 1; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_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 = 6; + fields[1].out_value = ®_addr_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 = 1; + fields[2].out_value = &nr_w_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); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm966e_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; + arm966e_common_t *arm966e; + arm_jtag_t *jtag_info; + + if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM966e 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 = arm966e_read_cp15(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 = arm966e_write_cp15(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 arm966e_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm966e_cmd; + + retval = arm9tdmi_register_commands(cmd_ctx); + arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands"); + register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + + return ERROR_OK; +} diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 7170693d..595790bc 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -1,1105 +1,1105 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm9tdmi.h" - -#include "arm7_9_common.h" -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "embeddedice.h" -#include "etm.h" -#include "etb.h" -#include "log.h" -#include "jtag.h" -#include "arm_jtag.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm9tdmi_register_commands(struct command_context_s *cmd_ctx); -int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* 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_type_t arm9tdmi_target = -{ - .name = "arm9tdmi", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .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, - .prepare_reset_halt = arm7_9_prepare_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, - .checksum_memory = arm7_9_checksum_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 = arm9tdmi_register_commands, - .target_command = arm9tdmi_target_command, - .init_target = arm9tdmi_init_target, - .quit = arm9tdmi_quit -}; - -arm9tdmi_vector_t arm9tdmi_vectors[] = -{ - {"reset", ARM9TDMI_RESET_VECTOR}, - {"undef", ARM9TDMI_UNDEF_VECTOR}, - {"swi", ARM9TDMI_SWI_VECTOR}, - {"pabt", ARM9TDMI_PABT_VECTOR}, - {"dabt", ARM9TDMI_DABT_VECTOR}, - {"reserved", ARM9TDMI_RESERVED_VECTOR}, - {"irq", ARM9TDMI_IRQ_VECTOR}, - {"fiq", ARM9TDMI_FIQ_VECTOR}, - {0, 0}, -}; - -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, NULL); - - 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); - - buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); - - 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, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = out_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - if (in) - { - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = in; - } - else - { - 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 = &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_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); - } - else - DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, 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, NULL); - - 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 = NULL; - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = in; - 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_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } - } -#endif - - return ERROR_OK; -} - -/* clock the target, and read the databus - * the *in pointer points to a buffer where elements of 'size' bytes - * are stored in big (be==1) or little (be==0) endianness - */ -int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) -{ - 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, NULL); - - 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 = NULL; - switch (size) - { - case 4: - fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32; - break; - case 2: - fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16; - break; - case 1: - fields[0].in_handler = arm_jtag_buf_to_8; - break; - } - fields[0].in_handler_priv = in; - 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_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } - } -#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); - - /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); - /* LDR in Decode */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* LDR in Execute */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* LDR in Memory (to account for interlock) */ - 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_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) -{ - 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; - int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; - u32 *buf_u32 = buffer; - u16 *buf_u16 = buffer; - u8 *buf_u8 = buffer; - - /* 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) */ - switch (size) - { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; - } - } - -} - -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); - - /* load r0 value, MOV_IM in Decode*/ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(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(0x7f7), 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; - - if (arm7_9->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; - - if (arm7_9->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; - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - /* one extra register (vector catch) */ - (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); - arm7_9->eice_cache = (*cache_p)->next; - - if (arm7_9->etm_ctx) - { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); - arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; - } -} - -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_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; - 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 */ - arm7_9->arm_bkpt = 0xdeeedeee; - arm7_9->thumb_bkpt = 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; - - arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC; - arm9tdmi->arch_info = NULL; - - if (variant) - { - arm9tdmi->variant = strdup(variant); - } - else - { - arm9tdmi->variant = strdup(""); - } - - arm7_9_init_arch_info(target, arm7_9); - - /* override use of DBGRQ, this is safe on ARM9TDMI */ - arm7_9->use_dbgrq = 1; - - /* all ARM9s have the vector catch register */ - arm7_9->has_vector_catch = 1; - - return ERROR_OK; -} - -int arm9tdmi_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) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - - 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; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - - return ERROR_OK; -} - - -/* target arm9tdmi */ -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 = 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; - - command_t *arm9tdmi_cmd; - - - retval = arm7_9_register_commands(cmd_ctx); - - arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands"); - - register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'']"); - - - return ERROR_OK; - -} - -int handle_arm9tdmi_catch_vectors_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; - reg_t *vector_catch; - u32 vector_catch_value; - int i, j; - - if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM9TDMI based target"); - return ERROR_OK; - } - - vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; - - /* read the vector catch register if necessary */ - if (!vector_catch->valid) - embeddedice_read_reg(vector_catch); - - /* get the current setting */ - vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); - - if (argc > 0) - { - vector_catch_value = 0x0; - if (strcmp(args[0], "all") == 0) - { - vector_catch_value = 0xdf; - } - else if (strcmp(args[0], "none") == 0) - { - /* do nothing */ - } - else - { - for (i = 0; i < argc; i++) - { - /* go through list of vectors */ - for(j = 0; arm9tdmi_vectors[j].name; j++) - { - if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0) - { - vector_catch_value |= arm9tdmi_vectors[j].value; - break; - } - } - - /* complain if vector wasn't found */ - if (!arm9tdmi_vectors[j].name) - { - command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]); - - /* reread current setting */ - vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); - - break; - } - } - } - - /* store new settings */ - buf_set_u32(vector_catch->value, 0, 32, vector_catch_value); - embeddedice_store_reg(vector_catch); - } - - /* output current settings (skip RESERVED vector) */ - for (i = 0; i < 8; i++) - { - if (i != 5) - { - command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name, - (vector_catch_value & (1 << i)) ? "catch" : "don't catch"); - } - } - - return ERROR_OK; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm9tdmi.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "etm.h" +#include "etb.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm9tdmi_register_commands(struct command_context_s *cmd_ctx); +int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* 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_type_t arm9tdmi_target = +{ + .name = "arm9tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .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, + .prepare_reset_halt = arm7_9_prepare_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, + .checksum_memory = arm7_9_checksum_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 = arm9tdmi_register_commands, + .target_command = arm9tdmi_target_command, + .init_target = arm9tdmi_init_target, + .quit = arm9tdmi_quit +}; + +arm9tdmi_vector_t arm9tdmi_vectors[] = +{ + {"reset", ARM9TDMI_RESET_VECTOR}, + {"undef", ARM9TDMI_UNDEF_VECTOR}, + {"swi", ARM9TDMI_SWI_VECTOR}, + {"pabt", ARM9TDMI_PABT_VECTOR}, + {"dabt", ARM9TDMI_DABT_VECTOR}, + {"reserved", ARM9TDMI_RESERVED_VECTOR}, + {"irq", ARM9TDMI_IRQ_VECTOR}, + {"fiq", ARM9TDMI_FIQ_VECTOR}, + {0, 0}, +}; + +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, NULL); + + 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); + + buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); + + 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, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = out_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + if (in) + { + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + } + else + { + 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 = &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_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); + } + else + DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, 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, NULL); + + 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 = NULL; + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + 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_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + 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, NULL); + + 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 = NULL; + switch (size) + { + case 4: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32; + break; + case 2: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16; + break; + case 1: + fields[0].in_handler = arm_jtag_buf_to_8; + break; + } + fields[0].in_handler_priv = in; + 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_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#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); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); + /* LDR in Decode */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Memory (to account for interlock) */ + 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_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + 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; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* 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) */ + switch (size) + { + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + +} + +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); + + /* load r0 value, MOV_IM in Decode*/ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(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(0x7f7), 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; + + if (arm7_9->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; + + if (arm7_9->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; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* one extra register (vector catch) */ + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +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_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; + 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 */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 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; + + arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC; + arm9tdmi->arch_info = NULL; + + if (variant) + { + arm9tdmi->variant = strdup(variant); + } + else + { + arm9tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + /* override use of DBGRQ, this is safe on ARM9TDMI */ + arm7_9->use_dbgrq = 1; + + /* all ARM9s have the vector catch register */ + arm7_9->has_vector_catch = 1; + + return ERROR_OK; +} + +int arm9tdmi_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) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + + 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; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + + return ERROR_OK; +} + + +/* target arm9tdmi */ +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 = 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; + + command_t *arm9tdmi_cmd; + + + retval = arm7_9_register_commands(cmd_ctx); + + arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands"); + + register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'']"); + + + return ERROR_OK; + +} + +int handle_arm9tdmi_catch_vectors_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; + reg_t *vector_catch; + u32 vector_catch_value; + int i, j; + + if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM9TDMI based target"); + return ERROR_OK; + } + + vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; + + /* read the vector catch register if necessary */ + if (!vector_catch->valid) + embeddedice_read_reg(vector_catch); + + /* get the current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + if (argc > 0) + { + vector_catch_value = 0x0; + if (strcmp(args[0], "all") == 0) + { + vector_catch_value = 0xdf; + } + else if (strcmp(args[0], "none") == 0) + { + /* do nothing */ + } + else + { + for (i = 0; i < argc; i++) + { + /* go through list of vectors */ + for(j = 0; arm9tdmi_vectors[j].name; j++) + { + if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0) + { + vector_catch_value |= arm9tdmi_vectors[j].value; + break; + } + } + + /* complain if vector wasn't found */ + if (!arm9tdmi_vectors[j].name) + { + command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]); + + /* reread current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + break; + } + } + } + + /* store new settings */ + buf_set_u32(vector_catch->value, 0, 32, vector_catch_value); + embeddedice_store_reg(vector_catch); + } + + /* output current settings (skip RESERVED vector) */ + for (i = 0; i < 8; i++) + { + if (i != 5) + { + command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name, + (vector_catch_value & (1 << i)) ? "catch" : "don't catch"); + } + } + + return ERROR_OK; +} diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 08cf3462..7a9e8786 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -1,207 +1,207 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm_jtag.h" - -#include "binarybuffer.h" -#include "log.h" -#include "jtag.h" - -#include - -#if 0 -#define _ARM_JTAG_SCAN_N_CHECK_ -#endif - -int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler) -{ - 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 = handler; - 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) - { -#ifdef _ARM_JTAG_SCAN_N_CHECK_ - u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1); -#endif - 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 = NULL; -#ifdef _ARM_JTAG_SCAN_N_CHECK_ - jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL); -#else - field.in_handler = NULL; - field.in_handler_priv = NULL; -#endif - - - arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL); - 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; -} - -/* read JTAG buffer into host-endian u32, flipping bit-order */ -int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u32 *dest = priv; - *dest = flip_u32(le_to_h_u32(in_buf), 32); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u32, flipping bit-order */ -int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u16, flipping bit-order */ -int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u32, flipping bit-order */ -int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u16, flipping bit-order */ -int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into u8, flipping bit-order */ -int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u8 *dest = priv; - *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff; - return ERROR_OK; -} - -/* not-flipping variants */ -/* read JTAG buffer into host-endian u32 */ -int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u32 *dest = priv; - *dest = le_to_h_u32(in_buf); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u32 */ -int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf)); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u16 */ -int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u32 */ -int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf)); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u16 */ -int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into u8 */ -int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u8 *dest = priv; - *dest = le_to_h_u32(in_buf) & 0xff; - return ERROR_OK; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm_jtag.h" + +#include "binarybuffer.h" +#include "log.h" +#include "jtag.h" + +#include + +#if 0 +#define _ARM_JTAG_SCAN_N_CHECK_ +#endif + +int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler) +{ + 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 = handler; + 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) + { +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1); +#endif + 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 = NULL; +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL); +#else + field.in_handler = NULL; + field.in_handler_priv = NULL; +#endif + + + arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL); + 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; +} + +/* read JTAG buffer into host-endian u32, flipping bit-order */ +int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32, flipping bit-order */ +int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16, flipping bit-order */ +int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32, flipping bit-order */ +int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16, flipping bit-order */ +int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8, flipping bit-order */ +int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff; + return ERROR_OK; +} + +/* not-flipping variants */ +/* read JTAG buffer into host-endian u32 */ +int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = le_to_h_u32(in_buf); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32 */ +int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16 */ +int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32 */ +int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16 */ +int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8 */ +int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = le_to_h_u32(in_buf) & 0xff; + return ERROR_OK; +} diff --git a/src/target/cortex_swjdp.c b/src/target/cortex_swjdp.c index 88b641e3..160f4c53 100644 --- a/src/target/cortex_swjdp.c +++ b/src/target/cortex_swjdp.c @@ -1,708 +1,708 @@ -/*************************************************************************** - * Copyright (C) 2006 by Magnus Lundin * - * lundin@mlu.mine.nu * - * * - * 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. * - ***************************************************************************/ -/*************************************************************************** - * * - * CoreSight (Light?) SerialWireJtagDebugPort * - * * - * CoreSightâ„¢ DAP-Lite TRM, ARM DDI 0316A * - * Cortex-M3â„¢ TRM, ARM DDI 0337C * - * * -***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "cortex_m3.h" -#include "cortex_swjdp.h" -#include "jtag.h" -#include "log.h" -#include - -/* - -Transaction Mode: -swjdp->trans_mode = TRANS_MODE_COMPOSITE; -Uses Overrun checking mode and does not do actual JTAG send/receive or transaction -result checking until swjdp_end_transaction() -This must be done before using or deallocating any return variables. - -swjdp->trans_mode == TRANS_MODE_ATOMIC -All reads and writes to the AHB bus are checked for valid completion, and return values -are immediatley available. - -*/ - -/*************************************************************************** - * * - * DPACC and APACC scanchain access through JTAG-DR * - * * -***************************************************************************/ - -/* Scan out and in from target ordered u8 buffers */ -int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack) -{ - scan_field_t fields[2]; - u8 out_addr_buf; - - jtag_add_end_state(TAP_RTI); - arm_jtag_set_instr(jtag_info, instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 3; - buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); - fields[0].out_value = &out_addr_buf; - fields[0].out_mask = NULL; - fields[0].in_value = ack; - 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 = outvalue; - fields[1].out_mask = NULL; - fields[1].in_value = invalue; - 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); - - return ERROR_OK; -} - -/* Scan out and in from host ordered u32 variables */ -int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack) -{ - scan_field_t fields[2]; - u8 out_value_buf[4]; - u8 out_addr_buf; - - jtag_add_end_state(TAP_RTI); - arm_jtag_set_instr(jtag_info, instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 3; - buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); - fields[0].out_value = &out_addr_buf; - fields[0].out_mask = NULL; - fields[0].in_value = ack; - 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; - buf_set_u32(out_value_buf, 0, 32, outvalue); - fields[1].out_value = out_value_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - if (invalue) - { - fields[1].in_handler = arm_jtag_buf_to_u32; - fields[1].in_handler_priv = invalue; - } - else - { - 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); - - return ERROR_OK; -} - -/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ -int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue) -{ - swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); - if ((RnW == DPAP_READ) && (invalue != NULL)) - { - swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); - } - - /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */ - if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - { - return swjdp_transaction_endcheck(swjdp); - } - - return ERROR_OK; -} - -int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue) -{ - - swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); - if ((RnW==DPAP_READ) && (invalue != NULL)) - { - swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); - } - - /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */ - if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - { - return swjdp_transaction_endcheck(swjdp); - } - - return ERROR_OK; -} - -int swjdp_transaction_endcheck(swjdp_common_t *swjdp) -{ - int waitcount = 0; - u32 ctrlstat; - - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - - swjdp->ack = swjdp->ack & 0x7; - - while (swjdp->ack != 2) - { - if (swjdp->ack == 1) - { - waitcount++; - if (waitcount > 100) - { - WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction"); - - return ERROR_JTAG_DEVICE_ERROR; - } - } - else - { - WARNING("Invalid ACK in SWJDP transaction"); - return ERROR_JTAG_DEVICE_ERROR; - } - - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - swjdp->ack = swjdp->ack & 0x7; - } - - /* Check for STICKYERR and STICKYORUN */ - if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) - { - DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat); - /* Check power to debug regions */ - if ((ctrlstat & 0xf0000000) != 0xf0000000) - { - ahbap_debugport_init(swjdp); - } - else - { - u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr; - - if (ctrlstat & SSTICKYORUN) - ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed"); - - if (ctrlstat & SSTICKYERR) - ERROR("SWJ-DP STICKY ERROR"); - - /* Clear Sticky Error Bits */ - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - - DEBUG("swjdp: status 0x%x", ctrlstat); - - /* Can we find out the reason for the error ?? */ - ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar); - ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar); - } - jtag_execute_queue(); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -/*************************************************************************** - * * - * DP and AHB-AP register access through APACC and DPACC * - * * -***************************************************************************/ - -int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr) -{ - u8 out_value_buf[4]; - - buf_set_u32(out_value_buf, 0, 32, value); - return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); -} - -int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr) -{ - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value); - - return ERROR_OK; -} - -int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr) -{ - u32 select; - select = (reg_addr & 0xFF0000F0); - - if (select != swjdp->dp_select_value) - { - swjdp_write_dpacc(swjdp, select, DP_SELECT); - swjdp->dp_select_value = select; - } - - return ERROR_OK; -} - -int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); - - return ERROR_OK; -} - -int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf); - - return ERROR_OK; -} -int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value) -{ - u8 out_value_buf[4]; - - buf_set_u32(out_value_buf, 0, 32, value); - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); - - return ERROR_OK; -} - -int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value); - - return ERROR_OK; -} - -/*************************************************************************** - * * - * AHB-AP access to memory and system registers on AHB bus * - * * -***************************************************************************/ - -int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar) -{ - csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; - if (csw != swjdp->ap_csw_value) - { - //DEBUG("swjdp : Set CSW %x",csw); - ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw ); - swjdp->ap_csw_value = csw; - } - if (tar != swjdp->ap_tar_value) - { - //DEBUG("swjdp : Set TAR %x",tar); - ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar ); - swjdp->ap_tar_value = tar; - } - if (csw & CSW_ADDRINC_MASK) - { - /* Do not cache TAR value when autoincrementing */ - swjdp->ap_tar_value = -1; - } - return ERROR_OK; -} - -/***************************************************************************** -* * -* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) * -* * -* Read a u32 value from memory or system register * -* Functionally equivalent to target_read_u32(target, address, u32 *value), * -* but with less overhead * -*****************************************************************************/ -int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) -{ - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); - - return ERROR_OK; -} - -int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value) -{ - ahbap_read_system_u32(swjdp, address, value); - - return swjdp_transaction_endcheck(swjdp); -} - -/***************************************************************************** -* * -* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) * -* * -* Write a u32 value to memory or system register * -* * -*****************************************************************************/ -int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) -{ - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); - - return ERROR_OK; -} - -int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value) -{ - ahbap_write_system_u32(swjdp, address, value); - - return swjdp_transaction_endcheck(swjdp); -} - -/***************************************************************************** -* * -* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * -* * -* Write a buffer in target order (little endian) * -* * -*****************************************************************************/ -int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 outvalue; - int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while ((address & 0x3) && (count > 0)) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - outvalue = (*buffer++) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - swjdp_transaction_endcheck(swjdp); - count--; - address++; - } - wcount = count >> 2; - count = count - 4 * wcount; - while (wcount > 0) - { - /* Adjust to write blocks within 4K aligned boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (wcount < blocksize) - blocksize = wcount; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - for (writecount=0; writecount 1) - { - WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - outvalue = (*buffer++) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - retval = swjdp_transaction_endcheck(swjdp); - count--; - address++; - } - - return retval; -} - -int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 outvalue; - int retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); - outvalue = *((u16*)buffer) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - retval = swjdp_transaction_endcheck(swjdp); - count -= 2; - address += 2; - buffer += 2; - } - - return retval; -} - -/***************************************************************************** -* * -* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * -* * -* Read block fast in target order (little endian) into a buffer * -* * -*****************************************************************************/ -int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 invalue; - int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while ((address & 0x3) && (count > 0)) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue); - swjdp_transaction_endcheck(swjdp); - *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; - count--; - address++; - } - wcount = count >> 2; - count = count - 4 * wcount; - while (wcount > 0) - { - /* Adjust to read within 4K block boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (wcount < blocksize) - blocksize = wcount; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - /* Scan out first read */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL); - for (readcount = 0; readcount < blocksize - 1; readcount++) - { - /* Scan out read instruction and scan in previous value */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); - } - /* Scan in last value */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); - if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) - { - wcount = wcount - blocksize; - address += 4 * blocksize; - buffer += 4 * blocksize; - } - else - { - errorcount++; - } - if (errorcount > 1) - { - WARNING("Block read error address 0x%x, count 0x%x", address, count); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); - retval = swjdp_transaction_endcheck(swjdp); - *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; - count--; - address++; - } - - return retval; -} - -int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 invalue; - int retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); - retval = swjdp_transaction_endcheck(swjdp); - *((u16*)buffer) = (invalue >> 8 * (address & 0x3)); - count -= 2; - address += 2; - buffer += 2; - } - - return retval; -} - -int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address) -{ - int readcount, errorcount = 0; - u32 blocksize; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - /* Adjust to read within 4K block boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (count < blocksize) - blocksize = count; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - for (readcount = 0; readcount < blocksize; readcount++) - { - ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount ); - } - if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) - { - count = count - blocksize; - address = address + 4 * blocksize; - buffer = buffer + blocksize; - } - else - { - errorcount++; - } - if (errorcount > 1) - { - WARNING("Block read error address 0x%x, count 0x%x", address, count); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - return ERROR_OK; -} - -int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum) -{ - int retval; - u32 dcrdr; - - ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum ); - - /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); - - retval = swjdp_transaction_endcheck(swjdp); - ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); - return retval; -} - -int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum) -{ - int retval; - u32 dcrdr; - - ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); - - /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR ); - - retval = swjdp_transaction_endcheck(swjdp); - ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); - return retval; -} - -int ahbap_debugport_init(swjdp_common_t *swjdp) -{ - u32 idreg, romaddr, dummy; - u32 ctrlstat; - int cnt = 0; - - DEBUG(" "); - - swjdp->ap_csw_value = -1; - swjdp->ap_tar_value = -1; - swjdp->trans_mode = TRANS_MODE_ATOMIC; - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - - swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; - - swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - - /* Check that we have debug power domains activated */ - while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) - { - DEBUG("swjdp: wait CDBGPWRUPACK"); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - usleep(10000); - } - - while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) - { - DEBUG("swjdp: wait CSYSPWRUPACK"); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - usleep(10000); - } - - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - /* With debug power on we can activate OVERRUN checking */ - swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; - swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - - ahbap_read_reg_u32(swjdp, 0xFC, &idreg); - ahbap_read_reg_u32(swjdp, 0xF8, &romaddr); - - DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * 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. * + ***************************************************************************/ +/*************************************************************************** + * * + * CoreSight (Light?) SerialWireJtagDebugPort * + * * + * CoreSightâ„¢ DAP-Lite TRM, ARM DDI 0316A * + * Cortex-M3â„¢ TRM, ARM DDI 0337C * + * * +***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "cortex_m3.h" +#include "cortex_swjdp.h" +#include "jtag.h" +#include "log.h" +#include + +/* + +Transaction Mode: +swjdp->trans_mode = TRANS_MODE_COMPOSITE; +Uses Overrun checking mode and does not do actual JTAG send/receive or transaction +result checking until swjdp_end_transaction() +This must be done before using or deallocating any return variables. + +swjdp->trans_mode == TRANS_MODE_ATOMIC +All reads and writes to the AHB bus are checked for valid completion, and return values +are immediatley available. + +*/ + +/*************************************************************************** + * * + * DPACC and APACC scanchain access through JTAG-DR * + * * +***************************************************************************/ + +/* Scan out and in from target ordered u8 buffers */ +int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + 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 = outvalue; + fields[1].out_mask = NULL; + fields[1].in_value = invalue; + 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); + + return ERROR_OK; +} + +/* Scan out and in from host ordered u32 variables */ +int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_value_buf[4]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + 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; + buf_set_u32(out_value_buf, 0, 32, outvalue); + fields[1].out_value = out_value_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (invalue) + { + fields[1].in_handler = arm_jtag_buf_to_u32; + fields[1].in_handler_priv = invalue; + } + else + { + 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); + + return ERROR_OK; +} + +/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ +int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue) +{ + swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW == DPAP_READ) && (invalue != NULL)) + { + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue) +{ + + swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW==DPAP_READ) && (invalue != NULL)) + { + swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int swjdp_transaction_endcheck(swjdp_common_t *swjdp) +{ + int waitcount = 0; + u32 ctrlstat; + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + swjdp->ack = swjdp->ack & 0x7; + + while (swjdp->ack != 2) + { + if (swjdp->ack == 1) + { + waitcount++; + if (waitcount > 100) + { + WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction"); + + return ERROR_JTAG_DEVICE_ERROR; + } + } + else + { + WARNING("Invalid ACK in SWJDP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + swjdp->ack = swjdp->ack & 0x7; + } + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) + { + DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) + { + ahbap_debugport_init(swjdp); + } + else + { + u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr; + + if (ctrlstat & SSTICKYORUN) + ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed"); + + if (ctrlstat & SSTICKYERR) + ERROR("SWJ-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + DEBUG("swjdp: status 0x%x", ctrlstat); + + /* Can we find out the reason for the error ?? */ + ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar); + ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar); + } + jtag_execute_queue(); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/*************************************************************************** + * * + * DP and AHB-AP register access through APACC and DPACC * + * * +***************************************************************************/ + +int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); +} + +int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr) +{ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr) +{ + u32 select; + select = (reg_addr & 0xFF0000F0); + + if (select != swjdp->dp_select_value) + { + swjdp_write_dpacc(swjdp, select, DP_SELECT); + swjdp->dp_select_value = select; + } + + return ERROR_OK; +} + +int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf); + + return ERROR_OK; +} +int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +/*************************************************************************** + * * + * AHB-AP access to memory and system registers on AHB bus * + * * +***************************************************************************/ + +int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar) +{ + csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; + if (csw != swjdp->ap_csw_value) + { + //DEBUG("swjdp : Set CSW %x",csw); + ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw ); + swjdp->ap_csw_value = csw; + } + if (tar != swjdp->ap_tar_value) + { + //DEBUG("swjdp : Set TAR %x",tar); + ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar ); + swjdp->ap_tar_value = tar; + } + if (csw & CSW_ADDRINC_MASK) + { + /* Do not cache TAR value when autoincrementing */ + swjdp->ap_tar_value = -1; + } + return ERROR_OK; +} + +/***************************************************************************** +* * +* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) * +* * +* Read a u32 value from memory or system register * +* Functionally equivalent to target_read_u32(target, address, u32 *value), * +* but with less overhead * +*****************************************************************************/ +int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + ahbap_read_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) * +* * +* Write a u32 value to memory or system register * +* * +*****************************************************************************/ +int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + ahbap_write_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Write a buffer in target order (little endian) * +* * +*****************************************************************************/ +int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to write blocks within 4K aligned boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (writecount=0; writecount 1) + { + WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + + return retval; +} + +int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + outvalue = *((u16*)buffer) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +/***************************************************************************** +* * +* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Read block fast in target order (little endian) into a buffer * +* * +*****************************************************************************/ +int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue); + swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + /* Scan out first read */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL); + for (readcount = 0; readcount < blocksize - 1; readcount++) + { + /* Scan out read instruction and scan in previous value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + } + /* Scan in last value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address += 4 * blocksize; + buffer += 4 * blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + + return retval; +} + +int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *((u16*)buffer) = (invalue >> 8 * (address & 0x3)); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address) +{ + int readcount, errorcount = 0; + u32 blocksize; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (count < blocksize) + blocksize = count; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (readcount = 0; readcount < blocksize; readcount++) + { + ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount ); + } + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + count = count - blocksize; + address = address + 4 * blocksize; + buffer = buffer + blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + return ERROR_OK; +} + +int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum ); + + /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_debugport_init(swjdp_common_t *swjdp) +{ + u32 idreg, romaddr, dummy; + u32 ctrlstat; + int cnt = 0; + + DEBUG(" "); + + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + swjdp->trans_mode = TRANS_MODE_ATOMIC; + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + + /* Check that we have debug power domains activated */ + while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CDBGPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CSYSPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + /* With debug power on we can activate OVERRUN checking */ + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + ahbap_read_reg_u32(swjdp, 0xFC, &idreg); + ahbap_read_reg_u32(swjdp, 0xF8, &romaddr); + + DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr); + + return ERROR_OK; +} diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 07b965b0..333c1c46 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -1,565 +1,565 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#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 - -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, - 0x2 -}; - -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", - - "vector catch" -}; - -int embeddedice_reg_arch_type = -1; - -int embeddedice_get_reg(reg_t *reg); -int embeddedice_set_reg(reg_t *reg, u32 value); -int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf); - -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, arm7_9_common_t *arm7_9) -{ - reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); - reg_t *reg_list = NULL; - embeddedice_reg_t *arch_info = NULL; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - int num_regs; - int i; - int eice_version = 0; - - /* 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); - - if (arm7_9->has_vector_catch) - num_regs = 17; - else - num_regs = 16; - - /* 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; 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; - } - - /* identify EmbeddedICE version by reading DCC control register */ - embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); - jtag_execute_queue(); - - eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); - - switch (eice_version) - { - case 1: - reg_list[EICE_DBG_CTRL].size = 3; - reg_list[EICE_DBG_STAT].size = 5; - break; - case 2: - reg_list[EICE_DBG_CTRL].size = 4; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - break; - case 3: - ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken"); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 4: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - case 5: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 6: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 10; - arm7_9->has_monitor_mode = 1; - break; - case 7: - WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken"); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - default: - ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); - } - - /* explicitly disable monitor mode */ - if (arm7_9->has_monitor_mode) - { - embeddedice_read_reg(®_list[EICE_DBG_CTRL]); - jtag_execute_queue(); - buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0); - embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value); - } - - 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]; - u8 field1_out[1]; - u8 field2_out[1]; - - 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, NULL); - - 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 = field1_out; - 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 = field2_out; - 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; - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - /* 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); - - return ERROR_OK; -} - -/* receive words of 32 bit from the DCC - * we pretend the target is always going to be fast enough - * (relative to the JTAG clock), so we don't need to handshake - */ -int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size) -{ - scan_field_t fields[3]; - u8 field1_out[1]; - u8 field2_out[1]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - 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 = 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 = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); - 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 = 1; - fields[2].out_value = field2_out; - 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); - - while (size > 0) - { - /* when reading the last item, set the register address to the DCC control reg, - * to avoid reading additional data from the DCC data reg - */ - if (size == 1) - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); - - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = data; - jtag_add_dr_scan(3, fields, -1); - - data++; - size--; - } - - return jtag_execute_queue(); -} - -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, u8 *buf) -{ - embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - 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]; - u8 field0_out[4]; - u8 field1_out[1]; - u8 field2_out[1]; - - 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, NULL); - - fields[0].device = ice_reg->jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = field0_out; - 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 = field1_out; - 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 = field2_out; - 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); - - return ERROR_OK; -} - -int embeddedice_store_reg(reg_t *reg) -{ - return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); -} - -/* send words of 32 bit to the DCC - * we pretend the target is always going to be fast enough - * (relative to the JTAG clock), so we don't need to handshake - */ -int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size) -{ - scan_field_t fields[3]; - u8 field0_out[4]; - u8 field1_out[1]; - u8 field2_out[1]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = field0_out; - 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 = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); - 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 = 1; - fields[2].out_value = field2_out; - 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; - - while (size > 0) - { - buf_set_u32(fields[0].out_value, 0, 32, *data); - jtag_add_dr_scan(3, fields, -1); - - data++; - size--; - } - - /* call to jtag_execute_queue() intentionally omitted */ - return ERROR_OK; -} - -/* wait for DCC control register R/W handshake bit to become active - */ -int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout) -{ - scan_field_t fields[3]; - u8 field0_in[4]; - u8 field1_out[1]; - u8 field2_out[1]; - int retval; - int hsact; - struct timeval lap; - struct timeval now; - - if (hsbit == EICE_COMM_CTRL_WBIT) - hsact = 1; - else if (hsbit == EICE_COMM_CTRL_RBIT) - hsact = 0; - else - return ERROR_INVALID_ARGUMENTS; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - 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 = field0_in; - 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 = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); - 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 = 1; - fields[2].out_value = field2_out; - 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); - gettimeofday(&lap, NULL); - do - { - jtag_add_dr_scan(3, fields, -1); - if ((retval = jtag_execute_queue()) != ERROR_OK) - return retval; - - if (buf_get_u32(field0_in, hsbit, 1) == hsact) - return ERROR_OK; - - gettimeofday(&now, NULL); - } - while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout); - - return ERROR_TARGET_TIMEOUT; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 + +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, + 0x2 +}; + +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", + + "vector catch" +}; + +int embeddedice_reg_arch_type = -1; + +int embeddedice_get_reg(reg_t *reg); +int embeddedice_set_reg(reg_t *reg, u32 value); +int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf); + +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, arm7_9_common_t *arm7_9) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + embeddedice_reg_t *arch_info = NULL; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int num_regs; + int i; + int eice_version = 0; + + /* 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); + + if (arm7_9->has_vector_catch) + num_regs = 17; + else + num_regs = 16; + + /* 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; 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; + } + + /* identify EmbeddedICE version by reading DCC control register */ + embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); + jtag_execute_queue(); + + eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); + + switch (eice_version) + { + case 1: + reg_list[EICE_DBG_CTRL].size = 3; + reg_list[EICE_DBG_STAT].size = 5; + break; + case 2: + reg_list[EICE_DBG_CTRL].size = 4; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + break; + case 3: + ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 4: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + case 5: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 6: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 10; + arm7_9->has_monitor_mode = 1; + break; + case 7: + WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + default: + ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); + } + + /* explicitly disable monitor mode */ + if (arm7_9->has_monitor_mode) + { + embeddedice_read_reg(®_list[EICE_DBG_CTRL]); + jtag_execute_queue(); + buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0); + embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value); + } + + 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]; + u8 field1_out[1]; + u8 field2_out[1]; + + 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, NULL); + + 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 = field1_out; + 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 = field2_out; + 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; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + /* 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); + + return ERROR_OK; +} + +/* receive words of 32 bit from the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + 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 = 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 = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + 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 = 1; + fields[2].out_value = field2_out; + 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); + + while (size > 0) + { + /* when reading the last item, set the register address to the DCC control reg, + * to avoid reading additional data from the DCC data reg + */ + if (size == 1) + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = data; + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + return jtag_execute_queue(); +} + +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, u8 *buf) +{ + embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + 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]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + 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, NULL); + + fields[0].device = ice_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + 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 = field1_out; + 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 = field2_out; + 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); + + return ERROR_OK; +} + +int embeddedice_store_reg(reg_t *reg) +{ + return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +/* send words of 32 bit to the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + 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 = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + 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 = 1; + fields[2].out_value = field2_out; + 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; + + while (size > 0) + { + buf_set_u32(fields[0].out_value, 0, 32, *data); + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + /* call to jtag_execute_queue() intentionally omitted */ + return ERROR_OK; +} + +/* wait for DCC control register R/W handshake bit to become active + */ +int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout) +{ + scan_field_t fields[3]; + u8 field0_in[4]; + u8 field1_out[1]; + u8 field2_out[1]; + int retval; + int hsact; + struct timeval lap; + struct timeval now; + + if (hsbit == EICE_COMM_CTRL_WBIT) + hsact = 1; + else if (hsbit == EICE_COMM_CTRL_RBIT) + hsact = 0; + else + return ERROR_INVALID_ARGUMENTS; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + 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 = field0_in; + 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 = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + 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 = 1; + fields[2].out_value = field2_out; + 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); + gettimeofday(&lap, NULL); + do + { + jtag_add_dr_scan(3, fields, -1); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + if (buf_get_u32(field0_in, hsbit, 1) == hsact) + return ERROR_OK; + + gettimeofday(&now, NULL); + } + while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout); + + return ERROR_TARGET_TIMEOUT; +} diff --git a/src/target/etb.c b/src/target/etb.c index 6c9d3a0c..ff4113e5 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -1,741 +1,741 @@ -/*************************************************************************** - * Copyright (C) 2007 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "arm7_9_common.h" -#include "etb.h" -#include "etm.h" - -#include "log.h" -#include "types.h" -#include "binarybuffer.h" -#include "target.h" -#include "register.h" -#include "jtag.h" - -#include - -char* etb_reg_list[] = -{ - "ETB_identification", - "ETB_ram_depth", - "ETB_ram_width", - "ETB_status", - "ETB_ram_data", - "ETB_ram_read_pointer", - "ETB_ram_write_pointer", - "ETB_trigger_counter", - "ETB_control", -}; - -int etb_reg_arch_type = -1; - -int etb_get_reg(reg_t *reg); -int etb_set_reg(reg_t *reg, u32 value); -int etb_set_reg_w_exec(reg_t *reg, u8 *buf); - -int etb_write_reg(reg_t *reg, u32 value); -int etb_read_reg(reg_t *reg); - -int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int etb_set_instr(etb_t *etb, u32 new_instr) -{ - jtag_device_t *device = jtag_get_device(etb->chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = etb->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 etb_scann(etb_t *etb, u32 new_scan_chain) -{ - if(etb->cur_scan_chain != new_scan_chain) - { - scan_field_t field; - - field.device = etb->chain_pos; - field.num_bits = 5; - 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 = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - /* select INTEST instruction */ - etb_set_instr(etb, 0x2); - jtag_add_dr_scan(1, &field, -1); - - etb->cur_scan_chain = new_scan_chain; - - free(field.out_value); - } - - return ERROR_OK; -} - -reg_cache_t* etb_build_reg_cache(etb_t *etb) -{ - reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); - reg_t *reg_list = NULL; - etb_reg_t *arch_info = NULL; - int num_regs = 9; - int i; - - /* register a register arch-type for etm registers only once */ - if (etb_reg_arch_type == -1) - etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_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(etb_reg_t)); - - /* fill in values for the reg cache */ - reg_cache->name = "etb 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 = etb_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 = etb_reg_arch_type; - reg_list[i].size = 32; - arch_info[i].addr = i; - arch_info[i].etb = etb; - } - - return reg_cache; -} - -int etb_get_reg(reg_t *reg) -{ - if (etb_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 etb_read_ram(etb_t *etb, u32 *data, int num_frames) -{ - scan_field_t fields[3]; - int i; - - jtag_add_end_state(TAP_RTI); - etb_scann(etb, 0x0); - etb_set_instr(etb, 0xc); - - fields[0].device = etb->chain_pos; - fields[0].num_bits = 32; - 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 = etb->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, 4); - 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 = etb->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_handler = buf_to_u32_handler; - - for (i = 0; i < num_frames; i++) - { - /* ensure nR/W reamins set to read */ - buf_set_u32(fields[2].out_value, 0, 1, 0); - - /* address remains set to 0x4 (RAM data) until we read the last frame */ - if (i < num_frames - 1) - buf_set_u32(fields[1].out_value, 0, 7, 4); - else - buf_set_u32(fields[1].out_value, 0, 7, 0); - - fields[0].in_handler_priv = &data[i]; - jtag_add_dr_scan(3, fields, -1); - } - - jtag_execute_queue(); - - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) -{ - etb_reg_t *etb_reg = reg->arch_info; - u8 reg_addr = etb_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i", etb_reg->addr); - - jtag_add_end_state(TAP_RTI); - etb_scann(etb_reg->etb, 0x0); - etb_set_instr(etb_reg->etb, 0xc); - - fields[0].device = etb_reg->etb->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 = etb_reg->etb->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 = etb_reg->etb->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); - - /* read the identification register in the second run, to make sure we - * don't read the ETB data register twice, skipping every second entry - */ - buf_set_u32(fields[1].out_value, 0, 7, 0x0); - fields[0].in_value = reg->value; - - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1); - - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etb_read_reg(reg_t *reg) -{ - return etb_read_reg_w_check(reg, NULL, NULL); -} - -int etb_set_reg(reg_t *reg, u32 value) -{ - if (etb_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 etb_set_reg_w_exec(reg_t *reg, u8 *buf) -{ - etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register write failed"); - exit(-1); - } - return ERROR_OK; -} - -int etb_write_reg(reg_t *reg, u32 value) -{ - etb_reg_t *etb_reg = reg->arch_info; - u8 reg_addr = etb_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i: 0x%8.8x", etb_reg->addr, value); - - jtag_add_end_state(TAP_RTI); - etb_scann(etb_reg->etb, 0x0); - etb_set_instr(etb_reg->etb, 0xc); - - fields[0].device = etb_reg->etb->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 = etb_reg->etb->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 = etb_reg->etb->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 etb_store_reg(reg_t *reg) -{ - return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); -} - -int etb_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *etb_cmd; - - etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); - - register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); - - return ERROR_OK; -} - -int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - jtag_device_t *jtag_device; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - if (argc != 2) - { - ERROR("incomplete 'etb config ' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); - - if (!jtag_device) - { - ERROR("jtag device number '%s' not defined", args[1]); - exit(-1); - } - - if (arm7_9->etm_ctx) - { - etb_t *etb = malloc(sizeof(etb_t)); - - arm7_9->etm_ctx->capture_driver_priv = etb; - - etb->chain_pos = strtoul(args[1], NULL, 0); - etb->cur_scan_chain = -1; - etb->reg_cache = NULL; - etb->ram_width = 0; - etb->ram_depth = 0; - } - else - { - ERROR("target has no ETM defined, ETB left unconfigured"); - } - - return ERROR_OK; -} - -int etb_init(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - - etb->etm_ctx = etm_ctx; - - /* identify ETB RAM depth and width */ - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); - jtag_execute_queue(); - - etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); - etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); - - return ERROR_OK; -} - -trace_status_t etb_status(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - - etb->etm_ctx = etm_ctx; - - /* if tracing is currently idle, return this information */ - if (etm_ctx->capture_status == TRACE_IDLE) - { - return etm_ctx->capture_status; - } - else if (etm_ctx->capture_status & TRACE_RUNNING) - { - reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; - int etb_timeout = 100; - - /* trace is running, check the ETB status flags */ - etb_get_reg(etb_status_reg); - - /* check Full bit to identify an overflow */ - if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) - etm_ctx->capture_status |= TRACE_OVERFLOWED; - - /* check Triggered bit to identify trigger condition */ - if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) - etm_ctx->capture_status |= TRACE_TRIGGERED; - - /* check AcqComp to identify trace completion */ - if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) - { - while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) - { - /* wait for data formatter idle */ - etb_get_reg(etb_status_reg); - } - - if (etb_timeout == 0) - { - ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", - buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); - } - - if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) - { - ERROR("trace completed, but no trigger condition detected"); - } - - etm_ctx->capture_status &= ~TRACE_RUNNING; - etm_ctx->capture_status |= TRACE_COMPLETED; - } - } - - return etm_ctx->capture_status; -} - -int etb_read_trace(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - int first_frame = 0; - int num_frames = etb->ram_depth; - u32 *trace_data = NULL; - int i, j; - - etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); - jtag_execute_queue(); - - /* check if we overflowed, and adjust first frame of the trace accordingly - * if we didn't overflow, read only up to the frame that would be written next, - * i.e. don't read invalid entries - */ - if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) - { - first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); - } - else - { - num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); - } - - etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); - - /* read data into temporary array for unpacking */ - trace_data = malloc(sizeof(u32) * num_frames); - etb_read_ram(etb, trace_data, num_frames); - - if (etm_ctx->trace_depth > 0) - { - free(etm_ctx->trace_data); - } - - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) - etm_ctx->trace_depth = num_frames * 3; - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - etm_ctx->trace_depth = num_frames * 2; - else - etm_ctx->trace_depth = num_frames; - - etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); - - for (i = 0, j = 0; i < num_frames; i++) - { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x80) >> 7) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+1 */ - etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8; - etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11; - etm_ctx->trace_data[j+1].flags = 0; - if ((trace_data[i] & 0x8000) >> 15) - { - etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; - etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+2 */ - etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16; - etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19; - etm_ctx->trace_data[j+2].flags = 0; - if ((trace_data[i] & 0x800000) >> 23) - { - etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+2].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7; - etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 3; - } - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x800) >> 11) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+1 */ - etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12; - etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15; - etm_ctx->trace_data[j+1].flags = 0; - if ((trace_data[i] & 0x800000) >> 23) - { - etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; - etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 2; - } - else - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x80000) >> 19) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 1; - } - } - - free(trace_data); - - return ERROR_OK; -} - -int etb_start_capture(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - u32 etb_ctrl_value = 0x1; - u32 trigger_count; - - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) - { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) - { - ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - } - etb_ctrl_value |= 0x2; - } - - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - - trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; - - etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); - etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); - etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); - jtag_execute_queue(); - - /* we're starting a new trace, initialize capture status */ - etm_ctx->capture_status = TRACE_RUNNING; - - return ERROR_OK; -} - -int etb_stop_capture(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; - - etb_write_reg(etb_ctrl_reg, 0x0); - jtag_execute_queue(); - - /* trace stopped, just clear running flag, but preserve others */ - etm_ctx->capture_status &= ~TRACE_RUNNING; - - return ERROR_OK; -} - -etm_capture_driver_t etb_capture_driver = -{ - .name = "etb", - .register_commands = etb_register_commands, - .init = etb_init, - .status = etb_status, - .start_capture = etb_start_capture, - .stop_capture = etb_stop_capture, - .read_trace = etb_read_trace, -}; +/*************************************************************************** + * Copyright (C) 2007 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "arm7_9_common.h" +#include "etb.h" +#include "etm.h" + +#include "log.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" + +#include + +char* etb_reg_list[] = +{ + "ETB_identification", + "ETB_ram_depth", + "ETB_ram_width", + "ETB_status", + "ETB_ram_data", + "ETB_ram_read_pointer", + "ETB_ram_write_pointer", + "ETB_trigger_counter", + "ETB_control", +}; + +int etb_reg_arch_type = -1; + +int etb_get_reg(reg_t *reg); +int etb_set_reg(reg_t *reg, u32 value); +int etb_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etb_write_reg(reg_t *reg, u32 value); +int etb_read_reg(reg_t *reg); + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int etb_set_instr(etb_t *etb, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(etb->chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = etb->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 etb_scann(etb_t *etb, u32 new_scan_chain) +{ + if(etb->cur_scan_chain != new_scan_chain) + { + scan_field_t field; + + field.device = etb->chain_pos; + field.num_bits = 5; + 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 = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + /* select INTEST instruction */ + etb_set_instr(etb, 0x2); + jtag_add_dr_scan(1, &field, -1); + + etb->cur_scan_chain = new_scan_chain; + + free(field.out_value); + } + + return ERROR_OK; +} + +reg_cache_t* etb_build_reg_cache(etb_t *etb) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + etb_reg_t *arch_info = NULL; + int num_regs = 9; + int i; + + /* register a register arch-type for etm registers only once */ + if (etb_reg_arch_type == -1) + etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_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(etb_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "etb 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 = etb_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 = etb_reg_arch_type; + reg_list[i].size = 32; + arch_info[i].addr = i; + arch_info[i].etb = etb; + } + + return reg_cache; +} + +int etb_get_reg(reg_t *reg) +{ + if (etb_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 etb_read_ram(etb_t *etb, u32 *data, int num_frames) +{ + scan_field_t fields[3]; + int i; + + jtag_add_end_state(TAP_RTI); + etb_scann(etb, 0x0); + etb_set_instr(etb, 0xc); + + fields[0].device = etb->chain_pos; + fields[0].num_bits = 32; + 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 = etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, 4); + 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 = etb->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_handler = buf_to_u32_handler; + + for (i = 0; i < num_frames; i++) + { + /* ensure nR/W reamins set to read */ + buf_set_u32(fields[2].out_value, 0, 1, 0); + + /* address remains set to 0x4 (RAM data) until we read the last frame */ + if (i < num_frames - 1) + buf_set_u32(fields[1].out_value, 0, 7, 4); + else + buf_set_u32(fields[1].out_value, 0, 7, 0); + + fields[0].in_handler_priv = &data[i]; + jtag_add_dr_scan(3, fields, -1); + } + + jtag_execute_queue(); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i", etb_reg->addr); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->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 = etb_reg->etb->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 = etb_reg->etb->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); + + /* read the identification register in the second run, to make sure we + * don't read the ETB data register twice, skipping every second entry + */ + buf_set_u32(fields[1].out_value, 0, 7, 0x0); + fields[0].in_value = reg->value; + + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg(reg_t *reg) +{ + return etb_read_reg_w_check(reg, NULL, NULL); +} + +int etb_set_reg(reg_t *reg, u32 value) +{ + if (etb_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 etb_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int etb_write_reg(reg_t *reg, u32 value) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i: 0x%8.8x", etb_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->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 = etb_reg->etb->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 = etb_reg->etb->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 etb_store_reg(reg_t *reg) +{ + return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +int etb_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *etb_cmd; + + etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); + + register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + jtag_device_t *jtag_device; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + if (argc != 2) + { + ERROR("incomplete 'etb config ' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); + + if (!jtag_device) + { + ERROR("jtag device number '%s' not defined", args[1]); + exit(-1); + } + + if (arm7_9->etm_ctx) + { + etb_t *etb = malloc(sizeof(etb_t)); + + arm7_9->etm_ctx->capture_driver_priv = etb; + + etb->chain_pos = strtoul(args[1], NULL, 0); + etb->cur_scan_chain = -1; + etb->reg_cache = NULL; + etb->ram_width = 0; + etb->ram_depth = 0; + } + else + { + ERROR("target has no ETM defined, ETB left unconfigured"); + } + + return ERROR_OK; +} + +int etb_init(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* identify ETB RAM depth and width */ + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); + jtag_execute_queue(); + + etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); + etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + + return ERROR_OK; +} + +trace_status_t etb_status(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* if tracing is currently idle, return this information */ + if (etm_ctx->capture_status == TRACE_IDLE) + { + return etm_ctx->capture_status; + } + else if (etm_ctx->capture_status & TRACE_RUNNING) + { + reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; + int etb_timeout = 100; + + /* trace is running, check the ETB status flags */ + etb_get_reg(etb_status_reg); + + /* check Full bit to identify an overflow */ + if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) + etm_ctx->capture_status |= TRACE_OVERFLOWED; + + /* check Triggered bit to identify trigger condition */ + if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) + etm_ctx->capture_status |= TRACE_TRIGGERED; + + /* check AcqComp to identify trace completion */ + if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) + { + while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) + { + /* wait for data formatter idle */ + etb_get_reg(etb_status_reg); + } + + if (etb_timeout == 0) + { + ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", + buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); + } + + if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) + { + ERROR("trace completed, but no trigger condition detected"); + } + + etm_ctx->capture_status &= ~TRACE_RUNNING; + etm_ctx->capture_status |= TRACE_COMPLETED; + } + } + + return etm_ctx->capture_status; +} + +int etb_read_trace(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + int first_frame = 0; + int num_frames = etb->ram_depth; + u32 *trace_data = NULL; + int i, j; + + etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); + jtag_execute_queue(); + + /* check if we overflowed, and adjust first frame of the trace accordingly + * if we didn't overflow, read only up to the frame that would be written next, + * i.e. don't read invalid entries + */ + if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) + { + first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + else + { + num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); + + /* read data into temporary array for unpacking */ + trace_data = malloc(sizeof(u32) * num_frames); + etb_read_ram(etb, trace_data, num_frames); + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + etm_ctx->trace_depth = num_frames * 3; + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + etm_ctx->trace_depth = num_frames * 2; + else + etm_ctx->trace_depth = num_frames; + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0, j = 0; i < num_frames; i++) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80) >> 7) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x8000) >> 15) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+2 */ + etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16; + etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19; + etm_ctx->trace_data[j+2].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+2].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7; + etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 3; + } + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x800) >> 11) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 2; + } + else + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80000) >> 19) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 1; + } + } + + free(trace_data); + + return ERROR_OK; +} + +int etb_start_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + u32 etb_ctrl_value = 0x1; + u32 trigger_count; + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) + { + ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + } + etb_ctrl_value |= 0x2; + } + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + + trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; + + etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); + etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); + jtag_execute_queue(); + + /* we're starting a new trace, initialize capture status */ + etm_ctx->capture_status = TRACE_RUNNING; + + return ERROR_OK; +} + +int etb_stop_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; + + etb_write_reg(etb_ctrl_reg, 0x0); + jtag_execute_queue(); + + /* trace stopped, just clear running flag, but preserve others */ + etm_ctx->capture_status &= ~TRACE_RUNNING; + + return ERROR_OK; +} + +etm_capture_driver_t etb_capture_driver = +{ + .name = "etb", + .register_commands = etb_register_commands, + .init = etb_init, + .status = etb_status, + .start_capture = etb_start_capture, + .stop_capture = etb_stop_capture, + .read_trace = etb_read_trace, +}; diff --git a/src/target/etb.h b/src/target/etb.h index 1a579cb3..e3dcb1d7 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -1,75 +1,75 @@ -/*************************************************************************** - * Copyright (C) 2007 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 ETB_H -#define ETB_H - -#include "command.h" -#include "target.h" -#include "register.h" -#include "arm_jtag.h" - -#include "etb.h" -#include "etm.h" - -/* ETB registers */ -enum -{ - ETB_ID = 0x00, - ETB_RAM_DEPTH = 0x01, - ETB_RAM_WIDTH = 0x02, - ETB_STATUS = 0x03, - ETB_RAM_DATA = 0x04, - ETB_RAM_READ_POINTER = 0x05, - ETB_RAM_WRITE_POINTER = 0x06, - ETB_TRIGGER_COUNTER = 0x07, - ETB_CTRL = 0x08, -}; - -typedef struct etb_s -{ - etm_context_t *etm_ctx; - int chain_pos; - int cur_scan_chain; - reg_cache_t *reg_cache; - - /* ETB parameters */ - int ram_depth; - int ram_width; -} etb_t; - -typedef struct etb_reg_s -{ - int addr; - etb_t *etb; -} etb_reg_t; - -extern etm_capture_driver_t etb_capture_driver; - -extern reg_cache_t* etb_build_reg_cache(etb_t *etb); -extern int etb_read_reg(reg_t *reg); -extern int etb_write_reg(reg_t *reg, u32 value); -extern int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask); -extern int etb_store_reg(reg_t *reg); -extern int etb_set_reg(reg_t *reg, u32 value); -extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf); - -extern int etb_register_commands(struct command_context_s *cmd_ctx); - -#endif /* ETB_H */ +/*************************************************************************** + * Copyright (C) 2007 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 ETB_H +#define ETB_H + +#include "command.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "etb.h" +#include "etm.h" + +/* ETB registers */ +enum +{ + ETB_ID = 0x00, + ETB_RAM_DEPTH = 0x01, + ETB_RAM_WIDTH = 0x02, + ETB_STATUS = 0x03, + ETB_RAM_DATA = 0x04, + ETB_RAM_READ_POINTER = 0x05, + ETB_RAM_WRITE_POINTER = 0x06, + ETB_TRIGGER_COUNTER = 0x07, + ETB_CTRL = 0x08, +}; + +typedef struct etb_s +{ + etm_context_t *etm_ctx; + int chain_pos; + int cur_scan_chain; + reg_cache_t *reg_cache; + + /* ETB parameters */ + int ram_depth; + int ram_width; +} etb_t; + +typedef struct etb_reg_s +{ + int addr; + etb_t *etb; +} etb_reg_t; + +extern etm_capture_driver_t etb_capture_driver; + +extern reg_cache_t* etb_build_reg_cache(etb_t *etb); +extern int etb_read_reg(reg_t *reg); +extern int etb_write_reg(reg_t *reg, u32 value); +extern int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask); +extern int etb_store_reg(reg_t *reg); +extern int etb_set_reg(reg_t *reg, u32 value); +extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf); + +extern int etb_register_commands(struct command_context_s *cmd_ctx); + +#endif /* ETB_H */ diff --git a/src/target/etm.c b/src/target/etm.c index fe4ac77f..8475a99f 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1,1863 +1,1863 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "etm.h" -#include "etb.h" - -#include "armv4_5.h" -#include "arm7_9_common.h" -#include "arm_disassembler.h" -#include "arm_simulator.h" - -#include "log.h" -#include "arm_jtag.h" -#include "types.h" -#include "binarybuffer.h" -#include "target.h" -#include "register.h" -#include "jtag.h" -#include "fileio.h" - -#include - -/* ETM register access functionality - * - */ - -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, 16, - 17, 26, 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_set_reg_w_exec(reg_t *reg, u8 *buf); - -int etm_write_reg(reg_t *reg, u32 value); -int etm_read_reg(reg_t *reg); - -command_t *etm_cmd = NULL; - -reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) -{ - 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; - u32 etm_ctrl_value; - - /* 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; - } - - /* initialize some ETM control register settings */ - etm_get_reg(®_list[ETM_CTRL]); - etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); - - /* clear the ETM powerdown bit (0) */ - etm_ctrl_value &= ~0x1; - - /* configure port width (6:4), mode (17:16) and clocking (13) */ - etm_ctrl_value = (etm_ctrl_value & - ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) - | etm_ctx->portmode; - - buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); - etm_store_reg(®_list[ETM_CTRL]); - - /* the ETM might have an ETB connected */ - if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) - { - etb_t *etb = etm_ctx->capture_driver_priv; - - if (!etb) - { - ERROR("etb selected as etm capture driver, but no ETB configured"); - return ERROR_OK; - } - - reg_cache->next = etb_build_reg_cache(etb); - - etb->reg_cache = reg_cache->next; - } - - if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) - { - ERROR("ETM capture driver initialization failed"); - exit(-1); - } - - 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, NULL); - - 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; - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - 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, u8 *buf) -{ - etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - 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, NULL); - - 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)); -} - -/* ETM trace analysis functionality - * - */ -extern etm_capture_driver_t etb_capture_driver; -extern etm_capture_driver_t etm_dummy_capture_driver; -#if BUILD_OOCD_TRACE == 1 -extern etm_capture_driver_t oocd_trace_capture_driver; -#endif - -etm_capture_driver_t *etm_capture_drivers[] = -{ - &etb_capture_driver, - &etm_dummy_capture_driver, -#if BUILD_OOCD_TRACE == 1 - &oocd_trace_capture_driver, -#endif - NULL -}; - -char *etmv1v1_branch_reason_strings[] = -{ - "normal PC change", - "tracing enabled", - "trace restarted after overflow", - "exit from debug", - "periodic synchronization", - "reserved", - "reserved", - "reserved", -}; - -int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) -{ - int i; - int section = -1; - u32 size_read; - u32 opcode; - int retval; - - if (!ctx->image) - return ERROR_TRACE_IMAGE_UNAVAILABLE; - - /* search for the section the current instruction belongs to */ - for (i = 0; i < ctx->image->num_sections; i++) - { - if ((ctx->image->sections[i].base_address <= ctx->current_pc) && - (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) - { - section = i; - break; - } - } - - if (section == -1) - { - /* current instruction couldn't be found in the image */ - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - - if (ctx->core_state == ARMV4_5_STATE_ARM) - { - u8 buf[4]; - if ((retval = image_read_section(ctx->image, section, - ctx->current_pc - ctx->image->sections[section].base_address, - 4, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u32(ctx->target, buf); - arm_evaluate_opcode(opcode, ctx->current_pc, instruction); - } - else if (ctx->core_state == ARMV4_5_STATE_THUMB) - { - u8 buf[2]; - if ((retval = image_read_section(ctx->image, section, - ctx->current_pc - ctx->image->sections[section].base_address, - 2, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u16(ctx->target, buf); - thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); - } - else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) - { - ERROR("BUG: tracing of jazelle code not supported"); - exit(-1); - } - else - { - ERROR("BUG: unknown core state encountered"); - exit(-1); - } - - return ERROR_OK; -} - -int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo) -{ - while (ctx->data_index < ctx->trace_depth) - { - /* if the caller specified an address packet offset, skip until the - * we reach the n-th cycle marked with tracesync */ - if (apo > 0) - { - if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) - apo--; - - if (apo > 0) - { - ctx->data_index++; - ctx->data_half = 0; - } - continue; - } - - /* no tracedata output during a TD cycle - * or in a trigger cycle */ - if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) - || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) - { - ctx->data_index++; - ctx->data_half = 0; - continue; - } - - if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) - { - if (ctx->data_half == 0) - { - *packet = ctx->trace_data[ctx->data_index].packet & 0xff; - ctx->data_half = 1; - } - else - { - *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; - ctx->data_half = 0; - ctx->data_index++; - } - } - else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - { - *packet = ctx->trace_data[ctx->data_index].packet & 0xff; - ctx->data_index++; - } - else - { - /* on a 4-bit port, a packet will be output during two consecutive cycles */ - if (ctx->data_index > (ctx->trace_depth - 2)) - return -1; - - *packet = ctx->trace_data[ctx->data_index].packet & 0xf; - *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; - ctx->data_index += 2; - } - - return 0; - } - - return -1; -} - -int etmv1_branch_address(etm_context_t *ctx) -{ - int retval; - u8 packet; - int shift = 0; - int apo; - int i; - - /* quit analysis if less than two cycles are left in the trace - * because we can't extract the APO */ - if (ctx->data_index > (ctx->trace_depth - 2)) - return -1; - - /* a BE could be output during an APO cycle, skip the current - * and continue with the new one */ - if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) - return 1; - if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) - return 2; - - /* address packet offset encoded in the next two cycles' pipestat bits */ - apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; - apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; - - /* count number of tracesync cycles between current pipe_index and data_index - * i.e. the number of tracesyncs that data_index already passed by - * to subtract them from the APO */ - for (i = ctx->pipe_index; i < ctx->data_index; i++) - { - if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) - apo--; - } - - /* extract up to four 7-bit packets */ - do { - if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0) - return -1; - ctx->last_branch &= ~(0x7f << shift); - ctx->last_branch |= (packet & 0x7f) << shift; - shift += 7; - } while ((packet & 0x80) && (shift < 28)); - - /* one last packet holding 4 bits of the address, plus the branch reason code */ - if ((shift == 28) && (packet & 0x80)) - { - if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) - return -1; - ctx->last_branch &= 0x0fffffff; - ctx->last_branch |= (packet & 0x0f) << 28; - ctx->last_branch_reason = (packet & 0x70) >> 4; - shift += 4; - } - else - { - ctx->last_branch_reason = 0; - } - - if (shift == 32) - { - ctx->pc_ok = 1; - } - - /* if a full address was output, we might have branched into Jazelle state */ - if ((shift == 32) && (packet & 0x80)) - { - ctx->core_state = ARMV4_5_STATE_JAZELLE; - } - else - { - /* if we didn't branch into Jazelle state, the current processor state is - * encoded in bit 0 of the branch target address */ - if (ctx->last_branch & 0x1) - { - ctx->core_state = ARMV4_5_STATE_THUMB; - ctx->last_branch &= ~0x1; - } - else - { - ctx->core_state = ARMV4_5_STATE_ARM; - ctx->last_branch &= ~0x3; - } - } - - return 0; -} - -int etmv1_data(etm_context_t *ctx, int size, u32 *data) -{ - int j; - u8 buf[4]; - int retval; - - for (j = 0; j < size; j++) - { - if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0) - return -1; - } - - if (size == 8) - ERROR("TODO: add support for 64-bit values"); - else if (size == 4) - *data = target_buffer_get_u32(ctx->target, buf); - else if (size == 2) - *data = target_buffer_get_u16(ctx->target, buf); - else if (size == 1) - *data = buf[0]; - - return 0; -} - -int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) -{ - int retval; - arm_instruction_t instruction; - - /* read the trace data if it wasn't read already */ - if (ctx->trace_depth == 0) - ctx->capture_driver->read_trace(ctx); - - /* start at the beginning of the captured trace */ - ctx->pipe_index = 0; - ctx->data_index = 0; - ctx->data_half = 0; - - /* neither the PC nor the data pointer are valid */ - ctx->pc_ok = 0; - ctx->ptr_ok = 0; - - while (ctx->pipe_index < ctx->trace_depth) - { - u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat; - u32 next_pc = ctx->current_pc; - u32 old_data_index = ctx->data_index; - u32 old_data_half = ctx->data_half; - u32 old_index = ctx->pipe_index; - u32 last_instruction = ctx->last_instruction; - u32 cycles = 0; - int current_pc_ok = ctx->pc_ok; - - if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) - { - command_print(cmd_ctx, "--- trigger ---"); - } - - /* instructions execute in IE/D or BE/D cycles */ - if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) - ctx->last_instruction = ctx->pipe_index; - - /* if we don't have a valid pc skip until we reach an indirect branch */ - if ((!ctx->pc_ok) && (pipestat != STAT_BE)) - { - ctx->pipe_index++; - continue; - } - - /* any indirect branch could have interrupted instruction flow - * - the branch reason code could indicate a trace discontinuity - * - a branch to the exception vectors indicates an exception - */ - if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) - { - /* backup current data index, to be able to consume the branch address - * before examining data address and values - */ - old_data_index = ctx->data_index; - old_data_half = ctx->data_half; - - ctx->last_instruction = ctx->pipe_index; - - if ((retval = etmv1_branch_address(ctx)) != 0) - { - /* negative return value from etmv1_branch_address means we ran out of packets, - * quit analysing the trace */ - if (retval < 0) - break; - - /* a positive return values means the current branch was abandoned, - * and a new branch was encountered in cycle ctx->pipe_index + retval; - */ - WARNING("abandoned branch encountered, correctnes of analysis uncertain"); - ctx->pipe_index += retval; - continue; - } - - /* skip over APO cycles */ - ctx->pipe_index += 2; - - switch (ctx->last_branch_reason) - { - case 0x0: /* normal PC change */ - next_pc = ctx->last_branch; - break; - case 0x1: /* tracing enabled */ - command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x2: /* trace restarted after FIFO overflow */ - command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x3: /* exit from debug state */ - command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x4: /* periodic synchronization point */ - next_pc = ctx->last_branch; - /* if we had no valid PC prior to this synchronization point, - * we have to move on with the next trace cycle - */ - if (!current_pc_ok) - { - command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); - ctx->current_pc = next_pc; - ctx->pipe_index++; - continue; - } - break; - default: /* reserved */ - ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); - exit(-1); - break; - } - - /* if we got here the branch was a normal PC change - * (or a periodic synchronization point, which means the same for that matter) - * if we didn't accquire a complete PC continue with the next cycle - */ - if (!ctx->pc_ok) - continue; - - /* indirect branch to the exception vector means an exception occured */ - if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20)) - || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) - { - if ((ctx->last_branch & 0xff) == 0x10) - { - command_print(cmd_ctx, "data abort"); - } - else - { - command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - } - } - } - - /* an instruction was executed (or not, depending on the condition flags) - * retrieve it from the image for displaying */ - if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && - !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && - ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) - { - if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images - * for now we just quit the analsysis*/ - return retval; - } - } - - cycles = old_index - last_instruction; - } - - if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) - { - u32 new_data_index = ctx->data_index; - u32 new_data_half = ctx->data_half; - - /* in case of a branch with data, the branch target address was consumed before - * we temporarily go back to the saved data index */ - if (pipestat == STAT_BD) - { - ctx->data_index = old_data_index; - ctx->data_half = old_data_half; - } - - if (ctx->tracemode & ETMV1_TRACE_ADDR) - { - u8 packet; - int shift = 0; - - do { - if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - ctx->last_ptr &= ~(0x7f << shift); - ctx->last_ptr |= (packet & 0x7f) << shift; - shift += 7; - } while ((packet & 0x80) && (shift < 32)); - - if (shift >= 32) - ctx->ptr_ok = 1; - - if (ctx->ptr_ok) - { - command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr); - } - } - - if (ctx->tracemode & ETMV1_TRACE_DATA) - { - if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) - { - int i; - for (i = 0; i < 16; i++) - { - if (instruction.info.load_store_multiple.register_list & (1 << i)) - { - u32 data; - if (etmv1_data(ctx, 4, &data) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd_ctx, "data: 0x%8.8x", data); - } - } - } - else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) - { - u32 data; - if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd_ctx, "data: 0x%8.8x", data); - } - } - - /* restore data index after consuming BD address and data */ - if (pipestat == STAT_BD) - { - ctx->data_index = new_data_index; - ctx->data_half = new_data_half; - } - } - - /* adjust PC */ - if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) - { - if (((instruction.type == ARM_B) || - (instruction.type == ARM_BL) || - (instruction.type == ARM_BLX)) && - (instruction.info.b_bl_bx_blx.target_address != -1)) - { - next_pc = instruction.info.b_bl_bx_blx.target_address; - } - else - { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - } - else if (pipestat == STAT_IN) - { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - - if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) - { - char cycles_text[32] = ""; - - /* if the trace was captured with cycle accurate tracing enabled, - * output the number of cycles since the last executed instruction - */ - if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) - { - snprintf(cycles_text, 32, " (%i %s)", - cycles, - (cycles == 1) ? "cycle" : "cycles"); - } - - command_print(cmd_ctx, "%s%s%s", - instruction.text, - (pipestat == STAT_IN) ? " (not executed)" : "", - cycles_text); - - ctx->current_pc = next_pc; - - /* packets for an instruction don't start on or before the preceding - * functional pipestat (i.e. other than WT or TD) - */ - if (ctx->data_index <= ctx->pipe_index) - { - ctx->data_index = ctx->pipe_index + 1; - ctx->data_half = 0; - } - } - - ctx->pipe_index += 1; - } - - return ERROR_OK; -} - -int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etmv1_tracemode_t tracemode; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - tracemode = arm7_9->etm_ctx->tracemode; - - if (argc == 4) - { - if (strcmp(args[0], "none") == 0) - { - tracemode = ETMV1_TRACE_NONE; - } - else if (strcmp(args[0], "data") == 0) - { - tracemode = ETMV1_TRACE_DATA; - } - else if (strcmp(args[0], "address") == 0) - { - tracemode = ETMV1_TRACE_ADDR; - } - else if (strcmp(args[0], "all") == 0) - { - tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[0]); - return ERROR_OK; - } - - switch (strtol(args[1], NULL, 0)) - { - case 0: - tracemode |= ETMV1_CONTEXTID_NONE; - break; - case 8: - tracemode |= ETMV1_CONTEXTID_8; - break; - case 16: - tracemode |= ETMV1_CONTEXTID_16; - break; - case 32: - tracemode |= ETMV1_CONTEXTID_32; - break; - default: - command_print(cmd_ctx, "invalid option '%s'", args[1]); - return ERROR_OK; - } - - if (strcmp(args[2], "enable") == 0) - { - tracemode |= ETMV1_CYCLE_ACCURATE; - } - else if (strcmp(args[2], "disable") == 0) - { - tracemode |= 0; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[2]); - return ERROR_OK; - } - - if (strcmp(args[3], "enable") == 0) - { - tracemode |= ETMV1_BRANCH_OUTPUT; - } - else if (strcmp(args[3], "disable") == 0) - { - tracemode |= 0; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[2]); - return ERROR_OK; - } - } - else if (argc != 0) - { - command_print(cmd_ctx, "usage: configure trace mode "); - return ERROR_OK; - } - - command_print(cmd_ctx, "current tracemode configuration:"); - - switch (tracemode & ETMV1_TRACE_MASK) - { - case ETMV1_TRACE_NONE: - command_print(cmd_ctx, "data tracing: none"); - break; - case ETMV1_TRACE_DATA: - command_print(cmd_ctx, "data tracing: data only"); - break; - case ETMV1_TRACE_ADDR: - command_print(cmd_ctx, "data tracing: address only"); - break; - case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: - command_print(cmd_ctx, "data tracing: address and data"); - break; - } - - switch (tracemode & ETMV1_CONTEXTID_MASK) - { - case ETMV1_CONTEXTID_NONE: - command_print(cmd_ctx, "contextid tracing: none"); - break; - case ETMV1_CONTEXTID_8: - command_print(cmd_ctx, "contextid tracing: 8 bit"); - break; - case ETMV1_CONTEXTID_16: - command_print(cmd_ctx, "contextid tracing: 16 bit"); - break; - case ETMV1_CONTEXTID_32: - command_print(cmd_ctx, "contextid tracing: 32 bit"); - break; - } - - if (tracemode & ETMV1_CYCLE_ACCURATE) - { - command_print(cmd_ctx, "cycle-accurate tracing enabled"); - } - else - { - command_print(cmd_ctx, "cycle-accurate tracing disabled"); - } - - if (tracemode & ETMV1_BRANCH_OUTPUT) - { - command_print(cmd_ctx, "full branch address output enabled"); - } - else - { - command_print(cmd_ctx, "full branch address output disabled"); - } - - /* only update ETM_CTRL register if tracemode changed */ - if (arm7_9->etm_ctx->tracemode != tracemode) - { - reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - - etm_get_reg(etm_ctrl_reg); - - buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); - buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); - buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); - buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); - etm_store_reg(etm_ctrl_reg); - - arm7_9->etm_ctx->tracemode = tracemode; - - /* invalidate old trace data */ - arm7_9->etm_ctx->capture_status = TRACE_IDLE; - if (arm7_9->etm_ctx->trace_depth > 0) - { - free(arm7_9->etm_ctx->trace_data); - arm7_9->etm_ctx->trace_data = NULL; - } - arm7_9->etm_ctx->trace_depth = 0; - } - - return ERROR_OK; -} - -int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_portmode_t portmode = 0x0; - etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); - int i; - - if (argc != 5) - { - ERROR("incomplete 'etm config ' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - switch (strtoul(args[1], NULL, 0)) - { - case 4: - portmode |= ETM_PORT_4BIT; - break; - case 8: - portmode |= ETM_PORT_8BIT; - break; - case 16: - portmode |= ETM_PORT_16BIT; - break; - default: - command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); - return ERROR_OK; - } - - if (strcmp("normal", args[2]) == 0) - { - portmode |= ETM_PORT_NORMAL; - } - else if (strcmp("multiplexed", args[2]) == 0) - { - portmode |= ETM_PORT_MUXED; - } - else if (strcmp("demultiplexed", args[2]) == 0) - { - portmode |= ETM_PORT_DEMUXED; - } - else - { - command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); - return ERROR_OK; - } - - if (strcmp("half", args[3]) == 0) - { - portmode |= ETM_PORT_HALF_CLOCK; - } - else if (strcmp("full", args[3]) == 0) - { - portmode |= ETM_PORT_FULL_CLOCK; - } - else - { - command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); - return ERROR_OK; - } - - for (i=0; etm_capture_drivers[i]; i++) - { - if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) - { - if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) - { - free(etm_ctx); - exit(-1); - } - - etm_ctx->capture_driver = etm_capture_drivers[i]; - - break; - } - } - - if (!etm_capture_drivers[i]) - { - /* no supported capture driver found, don't register an ETM */ - free(etm_ctx); - ERROR("trace capture driver '%s' not found", args[4]); - return ERROR_OK; - } - - etm_ctx->target = target; - etm_ctx->trigger_percent = 50; - etm_ctx->trace_data = NULL; - etm_ctx->trace_depth = 0; - etm_ctx->portmode = portmode; - etm_ctx->tracemode = 0x0; - etm_ctx->core_state = ARMV4_5_STATE_ARM; - etm_ctx->image = NULL; - etm_ctx->pipe_index = 0; - etm_ctx->data_index = 0; - etm_ctx->current_pc = 0x0; - etm_ctx->pc_ok = 0; - etm_ctx->last_branch = 0x0; - etm_ctx->last_branch_reason = 0x0; - etm_ctx->last_ptr = 0x0; - etm_ctx->ptr_ok = 0x0; - etm_ctx->context_id = 0x0; - etm_ctx->last_instruction = 0; - - arm7_9->etm_ctx = etm_ctx; - - etm_register_user_commands(cmd_ctx); - - return ERROR_OK; -} - -int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - reg_t *etm_config_reg; - reg_t *etm_sys_config_reg; - - int max_port_size; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; - etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; - - etm_get_reg(etm_config_reg); - command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); - command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); - command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); - command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); - command_print(cmd_ctx, "sequencer %spresent", - (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); - command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); - command_print(cmd_ctx, "FIFO full %spresent", - (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); - - etm_get_reg(etm_sys_config_reg); - - switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) - { - case 0: - max_port_size = 4; - break; - case 1: - max_port_size = 8; - break; - case 2: - max_port_size = 16; - break; - } - command_print(cmd_ctx, "max. port size: %i", max_port_size); - - command_print(cmd_ctx, "half-rate clocking %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "full-rate clocking %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "normal trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "multiplex trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "demultiplex trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "FIFO full %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); - - return ERROR_OK; -} - -int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - trace_status_t trace_status; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); - - if (trace_status == TRACE_IDLE) - { - command_print(cmd_ctx, "tracing is idle"); - } - else - { - static char *completed = " completed"; - static char *running = " is running"; - static char *overflowed = ", trace overflowed"; - static char *triggered = ", trace triggered"; - - command_print(cmd_ctx, "trace collection%s%s%s", - (trace_status & TRACE_RUNNING) ? running : completed, - (trace_status & TRACE_OVERFLOWED) ? overflowed : "", - (trace_status & TRACE_TRIGGERED) ? triggered : ""); - - if (arm7_9->etm_ctx->trace_depth > 0) - { - command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); - } - } - - return ERROR_OK; -} - -int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - - if (argc < 1) - { - command_print(cmd_ctx, "usage: etm image [base address] [type]"); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->image) - { - image_close(etm_ctx->image); - free(etm_ctx->image); - command_print(cmd_ctx, "previously loaded image found and closed"); - } - - etm_ctx->image = malloc(sizeof(image_t)); - etm_ctx->image->base_address_set = 0; - etm_ctx->image->start_address_set = 0; - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - etm_ctx->image->base_address_set = 1; - etm_ctx->image->base_address = strtoul(args[1], NULL, 0); - } - else - { - etm_ctx->image->base_address_set = 0; - } - - if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); - free(etm_ctx->image); - etm_ctx->image = NULL; - return ERROR_OK; - } - - return ERROR_OK; -} - -int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t file; - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int i; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: etm dump "); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status == TRACE_IDLE) - { - command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) - { - /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ - command_print(cmd_ctx, "trace capture not completed"); - return ERROR_OK; - } - - /* read the trace data if it wasn't read already */ - if (etm_ctx->trace_depth == 0) - etm_ctx->capture_driver->read_trace(etm_ctx); - - if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - fileio_write_u32(&file, etm_ctx->capture_status); - fileio_write_u32(&file, etm_ctx->portmode); - fileio_write_u32(&file, etm_ctx->tracemode); - fileio_write_u32(&file, etm_ctx->trace_depth); - - for (i = 0; i < etm_ctx->trace_depth; i++) - { - fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); - fileio_write_u32(&file, etm_ctx->trace_data[i].packet); - fileio_write_u32(&file, etm_ctx->trace_data[i].flags); - } - - fileio_close(&file); - - return ERROR_OK; -} - -int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t file; - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int i; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: etm load "); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) - { - command_print(cmd_ctx, "trace capture running, stop first"); - return ERROR_OK; - } - - if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - if (file.size % 4) - { - command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); - return ERROR_OK; - } - - if (etm_ctx->trace_depth > 0) - { - free(etm_ctx->trace_data); - } - - fileio_read_u32(&file, &etm_ctx->capture_status); - fileio_read_u32(&file, &etm_ctx->portmode); - fileio_read_u32(&file, &etm_ctx->tracemode); - fileio_read_u32(&file, &etm_ctx->trace_depth); - - etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); - - for (i = 0; i < etm_ctx->trace_depth; i++) - { - u32 pipestat, packet, flags; - fileio_read_u32(&file, &pipestat); - fileio_read_u32(&file, &packet); - fileio_read_u32(&file, &flags); - etm_ctx->trace_data[i].pipestat = pipestat & 0xff; - etm_ctx->trace_data[i].packet = packet & 0xffff; - etm_ctx->trace_data[i].flags = flags; - } - - fileio_close(&file); - - return ERROR_OK; -} - -int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (argc > 0) - { - u32 new_value = strtoul(args[0], NULL, 0); - - if ((new_value < 2) || (new_value > 100)) - { - command_print(cmd_ctx, "valid settings are 2% to 100%"); - } - else - { - etm_ctx->trigger_percent = new_value; - } - } - - command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); - - return ERROR_OK; -} - -int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - reg_t *etm_ctrl_reg; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - /* invalidate old tracing data */ - arm7_9->etm_ctx->capture_status = TRACE_IDLE; - if (arm7_9->etm_ctx->trace_depth > 0) - { - free(arm7_9->etm_ctx->trace_data); - arm7_9->etm_ctx->trace_data = NULL; - } - arm7_9->etm_ctx->trace_depth = 0; - - etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - etm_get_reg(etm_ctrl_reg); - - /* Clear programming bit (10), set port selection bit (11) */ - buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); - - etm_store_reg(etm_ctrl_reg); - jtag_execute_queue(); - - etm_ctx->capture_driver->start_capture(etm_ctx); - - return ERROR_OK; -} - -int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - reg_t *etm_ctrl_reg; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - etm_get_reg(etm_ctrl_reg); - - /* Set programming bit (10), clear port selection bit (11) */ - buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); - - etm_store_reg(etm_ctrl_reg); - jtag_execute_queue(); - - etm_ctx->capture_driver->stop_capture(etm_ctx); - - return ERROR_OK; -} - -int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int retval; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) - { - switch(retval) - { - case ERROR_ETM_ANALYSIS_FAILED: - command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); - break; - case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: - command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); - break; - case ERROR_TRACE_IMAGE_UNAVAILABLE: - command_print(cmd_ctx, "no image available for trace analysis"); - break; - default: - command_print(cmd_ctx, "unknown error: %i", retval); - } - } - - return ERROR_OK; -} - -int etm_register_commands(struct command_context_s *cmd_ctx) -{ - etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); - - register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); - - return ERROR_OK; -} - -int etm_register_user_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, - COMMAND_EXEC, "configure trace mode ", handle_etm_trigger_percent_command, - COMMAND_EXEC, "amount () of trace buffer to be filled after the trigger occured"); - register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, - COMMAND_EXEC, "display current target's ETM status"); - register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, - COMMAND_EXEC, "start ETM trace collection"); - register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, - COMMAND_EXEC, "stop ETM trace collection"); - - register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command, - COMMAND_EXEC, "anaylze collected ETM trace"); - - register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command, - COMMAND_EXEC, "load image from [base address]"); - - register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, - COMMAND_EXEC, "dump captured trace data "); - register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, - COMMAND_EXEC, "load trace data for analysis "); - - return ERROR_OK; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "etm.h" +#include "etb.h" + +#include "armv4_5.h" +#include "arm7_9_common.h" +#include "arm_disassembler.h" +#include "arm_simulator.h" + +#include "log.h" +#include "arm_jtag.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" +#include "fileio.h" + +#include + +/* ETM register access functionality + * + */ + +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, 16, + 17, 26, 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_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etm_write_reg(reg_t *reg, u32 value); +int etm_read_reg(reg_t *reg); + +command_t *etm_cmd = NULL; + +reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) +{ + 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; + u32 etm_ctrl_value; + + /* 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; + } + + /* initialize some ETM control register settings */ + etm_get_reg(®_list[ETM_CTRL]); + etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); + + /* clear the ETM powerdown bit (0) */ + etm_ctrl_value &= ~0x1; + + /* configure port width (6:4), mode (17:16) and clocking (13) */ + etm_ctrl_value = (etm_ctrl_value & + ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) + | etm_ctx->portmode; + + buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); + etm_store_reg(®_list[ETM_CTRL]); + + /* the ETM might have an ETB connected */ + if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) + { + etb_t *etb = etm_ctx->capture_driver_priv; + + if (!etb) + { + ERROR("etb selected as etm capture driver, but no ETB configured"); + return ERROR_OK; + } + + reg_cache->next = etb_build_reg_cache(etb); + + etb->reg_cache = reg_cache->next; + } + + if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) + { + ERROR("ETM capture driver initialization failed"); + exit(-1); + } + + 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, NULL); + + 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; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + 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, u8 *buf) +{ + etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + 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, NULL); + + 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)); +} + +/* ETM trace analysis functionality + * + */ +extern etm_capture_driver_t etb_capture_driver; +extern etm_capture_driver_t etm_dummy_capture_driver; +#if BUILD_OOCD_TRACE == 1 +extern etm_capture_driver_t oocd_trace_capture_driver; +#endif + +etm_capture_driver_t *etm_capture_drivers[] = +{ + &etb_capture_driver, + &etm_dummy_capture_driver, +#if BUILD_OOCD_TRACE == 1 + &oocd_trace_capture_driver, +#endif + NULL +}; + +char *etmv1v1_branch_reason_strings[] = +{ + "normal PC change", + "tracing enabled", + "trace restarted after overflow", + "exit from debug", + "periodic synchronization", + "reserved", + "reserved", + "reserved", +}; + +int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) +{ + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!ctx->image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < ctx->image->num_sections; i++) + { + if ((ctx->image->sections[i].base_address <= ctx->current_pc) && + (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (ctx->core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(ctx->target, buf); + arm_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(ctx->target, buf); + thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) + { + ERROR("BUG: tracing of jazelle code not supported"); + exit(-1); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo) +{ + while (ctx->data_index < ctx->trace_depth) + { + /* if the caller specified an address packet offset, skip until the + * we reach the n-th cycle marked with tracesync */ + if (apo > 0) + { + if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) + apo--; + + if (apo > 0) + { + ctx->data_index++; + ctx->data_half = 0; + } + continue; + } + + /* no tracedata output during a TD cycle + * or in a trigger cycle */ + if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) + || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) + { + ctx->data_index++; + ctx->data_half = 0; + continue; + } + + if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) + { + if (ctx->data_half == 0) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_half = 1; + } + else + { + *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; + ctx->data_half = 0; + ctx->data_index++; + } + } + else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_index++; + } + else + { + /* on a 4-bit port, a packet will be output during two consecutive cycles */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + *packet = ctx->trace_data[ctx->data_index].packet & 0xf; + *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; + ctx->data_index += 2; + } + + return 0; + } + + return -1; +} + +int etmv1_branch_address(etm_context_t *ctx) +{ + int retval; + u8 packet; + int shift = 0; + int apo; + int i; + + /* quit analysis if less than two cycles are left in the trace + * because we can't extract the APO */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + /* a BE could be output during an APO cycle, skip the current + * and continue with the new one */ + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) + return 1; + if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) + return 2; + + /* address packet offset encoded in the next two cycles' pipestat bits */ + apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; + apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; + + /* count number of tracesync cycles between current pipe_index and data_index + * i.e. the number of tracesyncs that data_index already passed by + * to subtract them from the APO */ + for (i = ctx->pipe_index; i < ctx->data_index; i++) + { + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) + apo--; + } + + /* extract up to four 7-bit packets */ + do { + if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0) + return -1; + ctx->last_branch &= ~(0x7f << shift); + ctx->last_branch |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 28)); + + /* one last packet holding 4 bits of the address, plus the branch reason code */ + if ((shift == 28) && (packet & 0x80)) + { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return -1; + ctx->last_branch &= 0x0fffffff; + ctx->last_branch |= (packet & 0x0f) << 28; + ctx->last_branch_reason = (packet & 0x70) >> 4; + shift += 4; + } + else + { + ctx->last_branch_reason = 0; + } + + if (shift == 32) + { + ctx->pc_ok = 1; + } + + /* if a full address was output, we might have branched into Jazelle state */ + if ((shift == 32) && (packet & 0x80)) + { + ctx->core_state = ARMV4_5_STATE_JAZELLE; + } + else + { + /* if we didn't branch into Jazelle state, the current processor state is + * encoded in bit 0 of the branch target address */ + if (ctx->last_branch & 0x1) + { + ctx->core_state = ARMV4_5_STATE_THUMB; + ctx->last_branch &= ~0x1; + } + else + { + ctx->core_state = ARMV4_5_STATE_ARM; + ctx->last_branch &= ~0x3; + } + } + + return 0; +} + +int etmv1_data(etm_context_t *ctx, int size, u32 *data) +{ + int j; + u8 buf[4]; + int retval; + + for (j = 0; j < size; j++) + { + if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0) + return -1; + } + + if (size == 8) + ERROR("TODO: add support for 64-bit values"); + else if (size == 4) + *data = target_buffer_get_u32(ctx->target, buf); + else if (size == 2) + *data = target_buffer_get_u16(ctx->target, buf); + else if (size == 1) + *data = buf[0]; + + return 0; +} + +int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) +{ + int retval; + arm_instruction_t instruction; + + /* read the trace data if it wasn't read already */ + if (ctx->trace_depth == 0) + ctx->capture_driver->read_trace(ctx); + + /* start at the beginning of the captured trace */ + ctx->pipe_index = 0; + ctx->data_index = 0; + ctx->data_half = 0; + + /* neither the PC nor the data pointer are valid */ + ctx->pc_ok = 0; + ctx->ptr_ok = 0; + + while (ctx->pipe_index < ctx->trace_depth) + { + u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat; + u32 next_pc = ctx->current_pc; + u32 old_data_index = ctx->data_index; + u32 old_data_half = ctx->data_half; + u32 old_index = ctx->pipe_index; + u32 last_instruction = ctx->last_instruction; + u32 cycles = 0; + int current_pc_ok = ctx->pc_ok; + + if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) + { + command_print(cmd_ctx, "--- trigger ---"); + } + + /* instructions execute in IE/D or BE/D cycles */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + ctx->last_instruction = ctx->pipe_index; + + /* if we don't have a valid pc skip until we reach an indirect branch */ + if ((!ctx->pc_ok) && (pipestat != STAT_BE)) + { + ctx->pipe_index++; + continue; + } + + /* any indirect branch could have interrupted instruction flow + * - the branch reason code could indicate a trace discontinuity + * - a branch to the exception vectors indicates an exception + */ + if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) + { + /* backup current data index, to be able to consume the branch address + * before examining data address and values + */ + old_data_index = ctx->data_index; + old_data_half = ctx->data_half; + + ctx->last_instruction = ctx->pipe_index; + + if ((retval = etmv1_branch_address(ctx)) != 0) + { + /* negative return value from etmv1_branch_address means we ran out of packets, + * quit analysing the trace */ + if (retval < 0) + break; + + /* a positive return values means the current branch was abandoned, + * and a new branch was encountered in cycle ctx->pipe_index + retval; + */ + WARNING("abandoned branch encountered, correctnes of analysis uncertain"); + ctx->pipe_index += retval; + continue; + } + + /* skip over APO cycles */ + ctx->pipe_index += 2; + + switch (ctx->last_branch_reason) + { + case 0x0: /* normal PC change */ + next_pc = ctx->last_branch; + break; + case 0x1: /* tracing enabled */ + command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x2: /* trace restarted after FIFO overflow */ + command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x3: /* exit from debug state */ + command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x4: /* periodic synchronization point */ + next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) + { + command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); + ctx->current_pc = next_pc; + ctx->pipe_index++; + continue; + } + break; + default: /* reserved */ + ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); + exit(-1); + break; + } + + /* if we got here the branch was a normal PC change + * (or a periodic synchronization point, which means the same for that matter) + * if we didn't accquire a complete PC continue with the next cycle + */ + if (!ctx->pc_ok) + continue; + + /* indirect branch to the exception vector means an exception occured */ + if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20)) + || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) + { + if ((ctx->last_branch & 0xff) == 0x10) + { + command_print(cmd_ctx, "data abort"); + } + else + { + command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + } + } + } + + /* an instruction was executed (or not, depending on the condition flags) + * retrieve it from the image for displaying */ + if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && + !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && + ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) + { + if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images + * for now we just quit the analsysis*/ + return retval; + } + } + + cycles = old_index - last_instruction; + } + + if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) + { + u32 new_data_index = ctx->data_index; + u32 new_data_half = ctx->data_half; + + /* in case of a branch with data, the branch target address was consumed before + * we temporarily go back to the saved data index */ + if (pipestat == STAT_BD) + { + ctx->data_index = old_data_index; + ctx->data_half = old_data_half; + } + + if (ctx->tracemode & ETMV1_TRACE_ADDR) + { + u8 packet; + int shift = 0; + + do { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + ctx->last_ptr &= ~(0x7f << shift); + ctx->last_ptr |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 32)); + + if (shift >= 32) + ctx->ptr_ok = 1; + + if (ctx->ptr_ok) + { + command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr); + } + } + + if (ctx->tracemode & ETMV1_TRACE_DATA) + { + if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) + { + int i; + for (i = 0; i < 16; i++) + { + if (instruction.info.load_store_multiple.register_list & (1 << i)) + { + u32 data; + if (etmv1_data(ctx, 4, &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + } + else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) + { + u32 data; + if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + + /* restore data index after consuming BD address and data */ + if (pipestat == STAT_BD) + { + ctx->data_index = new_data_index; + ctx->data_half = new_data_half; + } + } + + /* adjust PC */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + { + if (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1)) + { + next_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + } + else if (pipestat == STAT_IN) + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + + if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) + { + char cycles_text[32] = ""; + + /* if the trace was captured with cycle accurate tracing enabled, + * output the number of cycles since the last executed instruction + */ + if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + { + snprintf(cycles_text, 32, " (%i %s)", + cycles, + (cycles == 1) ? "cycle" : "cycles"); + } + + command_print(cmd_ctx, "%s%s%s", + instruction.text, + (pipestat == STAT_IN) ? " (not executed)" : "", + cycles_text); + + ctx->current_pc = next_pc; + + /* packets for an instruction don't start on or before the preceding + * functional pipestat (i.e. other than WT or TD) + */ + if (ctx->data_index <= ctx->pipe_index) + { + ctx->data_index = ctx->pipe_index + 1; + ctx->data_half = 0; + } + } + + ctx->pipe_index += 1; + } + + return ERROR_OK; +} + +int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etmv1_tracemode_t tracemode; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + tracemode = arm7_9->etm_ctx->tracemode; + + if (argc == 4) + { + if (strcmp(args[0], "none") == 0) + { + tracemode = ETMV1_TRACE_NONE; + } + else if (strcmp(args[0], "data") == 0) + { + tracemode = ETMV1_TRACE_DATA; + } + else if (strcmp(args[0], "address") == 0) + { + tracemode = ETMV1_TRACE_ADDR; + } + else if (strcmp(args[0], "all") == 0) + { + tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[0]); + return ERROR_OK; + } + + switch (strtol(args[1], NULL, 0)) + { + case 0: + tracemode |= ETMV1_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETMV1_CONTEXTID_8; + break; + case 16: + tracemode |= ETMV1_CONTEXTID_16; + break; + case 32: + tracemode |= ETMV1_CONTEXTID_32; + break; + default: + command_print(cmd_ctx, "invalid option '%s'", args[1]); + return ERROR_OK; + } + + if (strcmp(args[2], "enable") == 0) + { + tracemode |= ETMV1_CYCLE_ACCURATE; + } + else if (strcmp(args[2], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + + if (strcmp(args[3], "enable") == 0) + { + tracemode |= ETMV1_BRANCH_OUTPUT; + } + else if (strcmp(args[3], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + } + else if (argc != 0) + { + command_print(cmd_ctx, "usage: configure trace mode "); + return ERROR_OK; + } + + command_print(cmd_ctx, "current tracemode configuration:"); + + switch (tracemode & ETMV1_TRACE_MASK) + { + case ETMV1_TRACE_NONE: + command_print(cmd_ctx, "data tracing: none"); + break; + case ETMV1_TRACE_DATA: + command_print(cmd_ctx, "data tracing: data only"); + break; + case ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address only"); + break; + case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address and data"); + break; + } + + switch (tracemode & ETMV1_CONTEXTID_MASK) + { + case ETMV1_CONTEXTID_NONE: + command_print(cmd_ctx, "contextid tracing: none"); + break; + case ETMV1_CONTEXTID_8: + command_print(cmd_ctx, "contextid tracing: 8 bit"); + break; + case ETMV1_CONTEXTID_16: + command_print(cmd_ctx, "contextid tracing: 16 bit"); + break; + case ETMV1_CONTEXTID_32: + command_print(cmd_ctx, "contextid tracing: 32 bit"); + break; + } + + if (tracemode & ETMV1_CYCLE_ACCURATE) + { + command_print(cmd_ctx, "cycle-accurate tracing enabled"); + } + else + { + command_print(cmd_ctx, "cycle-accurate tracing disabled"); + } + + if (tracemode & ETMV1_BRANCH_OUTPUT) + { + command_print(cmd_ctx, "full branch address output enabled"); + } + else + { + command_print(cmd_ctx, "full branch address output disabled"); + } + + /* only update ETM_CTRL register if tracemode changed */ + if (arm7_9->etm_ctx->tracemode != tracemode) + { + reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + + etm_get_reg(etm_ctrl_reg); + + buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); + buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); + buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); + buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); + etm_store_reg(etm_ctrl_reg); + + arm7_9->etm_ctx->tracemode = tracemode; + + /* invalidate old trace data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + } + + return ERROR_OK; +} + +int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_portmode_t portmode = 0x0; + etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); + int i; + + if (argc != 5) + { + ERROR("incomplete 'etm config ' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + switch (strtoul(args[1], NULL, 0)) + { + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + default: + command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); + return ERROR_OK; + } + + if (strcmp("normal", args[2]) == 0) + { + portmode |= ETM_PORT_NORMAL; + } + else if (strcmp("multiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_MUXED; + } + else if (strcmp("demultiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_DEMUXED; + } + else + { + command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); + return ERROR_OK; + } + + if (strcmp("half", args[3]) == 0) + { + portmode |= ETM_PORT_HALF_CLOCK; + } + else if (strcmp("full", args[3]) == 0) + { + portmode |= ETM_PORT_FULL_CLOCK; + } + else + { + command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); + return ERROR_OK; + } + + for (i=0; etm_capture_drivers[i]; i++) + { + if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) + { + if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) + { + free(etm_ctx); + exit(-1); + } + + etm_ctx->capture_driver = etm_capture_drivers[i]; + + break; + } + } + + if (!etm_capture_drivers[i]) + { + /* no supported capture driver found, don't register an ETM */ + free(etm_ctx); + ERROR("trace capture driver '%s' not found", args[4]); + return ERROR_OK; + } + + etm_ctx->target = target; + etm_ctx->trigger_percent = 50; + etm_ctx->trace_data = NULL; + etm_ctx->trace_depth = 0; + etm_ctx->portmode = portmode; + etm_ctx->tracemode = 0x0; + etm_ctx->core_state = ARMV4_5_STATE_ARM; + etm_ctx->image = NULL; + etm_ctx->pipe_index = 0; + etm_ctx->data_index = 0; + etm_ctx->current_pc = 0x0; + etm_ctx->pc_ok = 0; + etm_ctx->last_branch = 0x0; + etm_ctx->last_branch_reason = 0x0; + etm_ctx->last_ptr = 0x0; + etm_ctx->ptr_ok = 0x0; + etm_ctx->context_id = 0x0; + etm_ctx->last_instruction = 0; + + arm7_9->etm_ctx = etm_ctx; + + etm_register_user_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + reg_t *etm_config_reg; + reg_t *etm_sys_config_reg; + + int max_port_size; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; + etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; + + etm_get_reg(etm_config_reg); + command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); + command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); + command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); + command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); + command_print(cmd_ctx, "sequencer %spresent", + (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); + command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); + command_print(cmd_ctx, "FIFO full %spresent", + (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); + + etm_get_reg(etm_sys_config_reg); + + switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) + { + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + } + command_print(cmd_ctx, "max. port size: %i", max_port_size); + + command_print(cmd_ctx, "half-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "full-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "normal trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "multiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "demultiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "FIFO full %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); + + return ERROR_OK; +} + +int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + trace_status_t trace_status; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); + + if (trace_status == TRACE_IDLE) + { + command_print(cmd_ctx, "tracing is idle"); + } + else + { + static char *completed = " completed"; + static char *running = " is running"; + static char *overflowed = ", trace overflowed"; + static char *triggered = ", trace triggered"; + + command_print(cmd_ctx, "trace collection%s%s%s", + (trace_status & TRACE_RUNNING) ? running : completed, + (trace_status & TRACE_OVERFLOWED) ? overflowed : "", + (trace_status & TRACE_TRIGGERED) ? triggered : ""); + + if (arm7_9->etm_ctx->trace_depth > 0) + { + command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); + } + } + + return ERROR_OK; +} + +int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: etm image [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->image) + { + image_close(etm_ctx->image); + free(etm_ctx->image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + etm_ctx->image = malloc(sizeof(image_t)); + etm_ctx->image->base_address_set = 0; + etm_ctx->image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + etm_ctx->image->base_address_set = 1; + etm_ctx->image->base_address = strtoul(args[1], NULL, 0); + } + else + { + etm_ctx->image->base_address_set = 0; + } + + if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); + free(etm_ctx->image); + etm_ctx->image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm dump "); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status == TRACE_IDLE) + { + command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ + command_print(cmd_ctx, "trace capture not completed"); + return ERROR_OK; + } + + /* read the trace data if it wasn't read already */ + if (etm_ctx->trace_depth == 0) + etm_ctx->capture_driver->read_trace(etm_ctx); + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + fileio_write_u32(&file, etm_ctx->capture_status); + fileio_write_u32(&file, etm_ctx->portmode); + fileio_write_u32(&file, etm_ctx->tracemode); + fileio_write_u32(&file, etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); + fileio_write_u32(&file, etm_ctx->trace_data[i].packet); + fileio_write_u32(&file, etm_ctx->trace_data[i].flags); + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm load "); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + command_print(cmd_ctx, "trace capture running, stop first"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + if (file.size % 4) + { + command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + return ERROR_OK; + } + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + fileio_read_u32(&file, &etm_ctx->capture_status); + fileio_read_u32(&file, &etm_ctx->portmode); + fileio_read_u32(&file, &etm_ctx->tracemode); + fileio_read_u32(&file, &etm_ctx->trace_depth); + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + u32 pipestat, packet, flags; + fileio_read_u32(&file, &pipestat); + fileio_read_u32(&file, &packet); + fileio_read_u32(&file, &flags); + etm_ctx->trace_data[i].pipestat = pipestat & 0xff; + etm_ctx->trace_data[i].packet = packet & 0xffff; + etm_ctx->trace_data[i].flags = flags; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (argc > 0) + { + u32 new_value = strtoul(args[0], NULL, 0); + + if ((new_value < 2) || (new_value > 100)) + { + command_print(cmd_ctx, "valid settings are 2% to 100%"); + } + else + { + etm_ctx->trigger_percent = new_value; + } + } + + command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); + + return ERROR_OK; +} + +int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + /* invalidate old tracing data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Clear programming bit (10), set port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->start_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Set programming bit (10), clear port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->stop_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int retval; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) + { + switch(retval) + { + case ERROR_ETM_ANALYSIS_FAILED: + command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(cmd_ctx, "no image available for trace analysis"); + break; + default: + command_print(cmd_ctx, "unknown error: %i", retval); + } + } + + return ERROR_OK; +} + +int etm_register_commands(struct command_context_s *cmd_ctx) +{ + etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); + + register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int etm_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, + COMMAND_EXEC, "configure trace mode ", handle_etm_trigger_percent_command, + COMMAND_EXEC, "amount () of trace buffer to be filled after the trigger occured"); + register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, + COMMAND_EXEC, "display current target's ETM status"); + register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, + COMMAND_EXEC, "start ETM trace collection"); + register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, + COMMAND_EXEC, "stop ETM trace collection"); + + register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command, + COMMAND_EXEC, "anaylze collected ETM trace"); + + register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command, + COMMAND_EXEC, "load image from [base address]"); + + register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, + COMMAND_EXEC, "dump captured trace data "); + register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, + COMMAND_EXEC, "load trace data for analysis "); + + return ERROR_OK; +} diff --git a/src/target/etm.h b/src/target/etm.h index bfa1252b..da47ff13 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -1,214 +1,214 @@ -/*************************************************************************** - * Copyright (C) 2005, 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * Copyright (C) 2007 by Vincent Palatin * - * vincent.palatin_openocd@m4x.org * - * * - * 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 "image.h" -#include "trace.h" -#include "target.h" -#include "register.h" -#include "arm_jtag.h" - -#include "armv4_5.h" - -/* ETM registers (V1.3 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; - -typedef enum -{ - /* Port width */ - ETM_PORT_4BIT = 0x00, - ETM_PORT_8BIT = 0x10, - ETM_PORT_16BIT = 0x20, - ETM_PORT_WIDTH_MASK = 0x70, - /* Port modes */ - ETM_PORT_NORMAL = 0x00000, - ETM_PORT_MUXED = 0x10000, - ETM_PORT_DEMUXED = 0x20000, - ETM_PORT_MODE_MASK = 0x30000, - /* Clocking modes */ - ETM_PORT_FULL_CLOCK = 0x0000, - ETM_PORT_HALF_CLOCK = 0x1000, - ETM_PORT_CLOCK_MASK = 0x1000, -} etm_portmode_t; - -typedef enum -{ - /* Data trace */ - ETMV1_TRACE_NONE = 0x00, - ETMV1_TRACE_DATA = 0x01, - ETMV1_TRACE_ADDR = 0x02, - ETMV1_TRACE_MASK = 0x03, - /* ContextID */ - ETMV1_CONTEXTID_NONE = 0x00, - ETMV1_CONTEXTID_8 = 0x10, - ETMV1_CONTEXTID_16 = 0x20, - ETMV1_CONTEXTID_32 = 0x30, - ETMV1_CONTEXTID_MASK = 0x30, - /* Misc */ - ETMV1_CYCLE_ACCURATE = 0x100, - ETMV1_BRANCH_OUTPUT = 0x200 -} etmv1_tracemode_t; - -/* forward-declare ETM context */ -struct etm_context_s; - -typedef struct etm_capture_driver_s -{ - char *name; - int (*register_commands)(struct command_context_s *cmd_ctx); - int (*init)(struct etm_context_s *etm_ctx); - trace_status_t (*status)(struct etm_context_s *etm_ctx); - int (*read_trace)(struct etm_context_s *etm_ctx); - int (*start_capture)(struct etm_context_s *etm_ctx); - int (*stop_capture)(struct etm_context_s *etm_ctx); -} etm_capture_driver_t; - -enum -{ - ETMV1_TRACESYNC_CYCLE = 0x1, - ETMV1_TRIGGER_CYCLE = 0x2, -}; - -typedef struct etmv1_trace_data_s -{ - u8 pipestat; /* bits 0-2 pipeline status */ - u16 packet; /* packet data (4, 8 or 16 bit) */ - int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */ -} etmv1_trace_data_t; - -/* describe a trace context - * if support for ETMv2 or ETMv3 is to be implemented, - * this will have to be split into version independent elements - * and a version specific part - */ -typedef struct etm_context_s -{ - target_t *target; /* target this ETM is connected to */ - reg_cache_t *reg_cache; /* ETM register cache */ - etm_capture_driver_t *capture_driver; /* driver used to access ETM data */ - void *capture_driver_priv; /* capture driver private data */ - u32 trigger_percent; /* percent of trace buffer to be filled after the trigger */ - trace_status_t capture_status; /* current state of capture run */ - etmv1_trace_data_t *trace_data; /* trace data */ - u32 trace_depth; /* number of trace cycles to be analyzed, 0 if no trace data available */ - etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */ - etmv1_tracemode_t tracemode; /* type of information the trace contains (data, addres, contextID, ...) */ - armv4_5_state_t core_state; /* current core state (ARM, Thumb, Jazelle) */ - image_t *image; /* source for target opcodes */ - u32 pipe_index; /* current trace cycle */ - u32 data_index; /* cycle holding next data packet */ - int data_half; /* port half on a 16 bit port */ - u32 current_pc; /* current program counter */ - u32 pc_ok; /* full PC has been acquired */ - u32 last_branch; /* last branch address output */ - u32 last_branch_reason; /* branch reason code for the last branch encountered */ - u32 last_ptr; /* address of the last data access */ - u32 ptr_ok; /* whether last_ptr is valid */ - u32 context_id; /* context ID of the code being traced */ - u32 last_instruction; /* index of last instruction executed (to calculate cycle timings) */ -} etm_context_t; - -/* PIPESTAT values */ -typedef enum -{ - STAT_IE = 0x0, - STAT_ID = 0x1, - STAT_IN = 0x2, - STAT_WT = 0x3, - STAT_BE = 0x4, - STAT_BD = 0x5, - STAT_TR = 0x6, - STAT_TD = 0x7 -} etmv1_pipestat_t; - -/* branch reason values */ -typedef enum -{ - BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ - BR_ENABLE = 0x1, /* Trace has been enabled */ - BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ - BR_NODEBUG = 0x3, /* ARM has exited for debug state */ - BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/ - BR_RSVD5 = 0x5, /* reserved */ - BR_RSVD6 = 0x6, /* reserved */ - BR_RSVD7 = 0x7, /* reserved */ -} etmv1_branch_reason_t; - -extern char *etmv1v1_branch_reason_strings[]; - -extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx); -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, u8 *buf); - -int etm_register_commands(struct command_context_s *cmd_ctx); -int etm_register_user_commands(struct command_context_s *cmd_ctx); -extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name); - -#define ERROR_ETM_INVALID_DRIVER (-1300) -#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301) -#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302) -#define ERROR_ETM_ANALYSIS_FAILED (-1303) - -#endif /* ETM_H */ +/*************************************************************************** + * Copyright (C) 2005, 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * Copyright (C) 2007 by Vincent Palatin * + * vincent.palatin_openocd@m4x.org * + * * + * 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 "image.h" +#include "trace.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "armv4_5.h" + +/* ETM registers (V1.3 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; + +typedef enum +{ + /* Port width */ + ETM_PORT_4BIT = 0x00, + ETM_PORT_8BIT = 0x10, + ETM_PORT_16BIT = 0x20, + ETM_PORT_WIDTH_MASK = 0x70, + /* Port modes */ + ETM_PORT_NORMAL = 0x00000, + ETM_PORT_MUXED = 0x10000, + ETM_PORT_DEMUXED = 0x20000, + ETM_PORT_MODE_MASK = 0x30000, + /* Clocking modes */ + ETM_PORT_FULL_CLOCK = 0x0000, + ETM_PORT_HALF_CLOCK = 0x1000, + ETM_PORT_CLOCK_MASK = 0x1000, +} etm_portmode_t; + +typedef enum +{ + /* Data trace */ + ETMV1_TRACE_NONE = 0x00, + ETMV1_TRACE_DATA = 0x01, + ETMV1_TRACE_ADDR = 0x02, + ETMV1_TRACE_MASK = 0x03, + /* ContextID */ + ETMV1_CONTEXTID_NONE = 0x00, + ETMV1_CONTEXTID_8 = 0x10, + ETMV1_CONTEXTID_16 = 0x20, + ETMV1_CONTEXTID_32 = 0x30, + ETMV1_CONTEXTID_MASK = 0x30, + /* Misc */ + ETMV1_CYCLE_ACCURATE = 0x100, + ETMV1_BRANCH_OUTPUT = 0x200 +} etmv1_tracemode_t; + +/* forward-declare ETM context */ +struct etm_context_s; + +typedef struct etm_capture_driver_s +{ + char *name; + int (*register_commands)(struct command_context_s *cmd_ctx); + int (*init)(struct etm_context_s *etm_ctx); + trace_status_t (*status)(struct etm_context_s *etm_ctx); + int (*read_trace)(struct etm_context_s *etm_ctx); + int (*start_capture)(struct etm_context_s *etm_ctx); + int (*stop_capture)(struct etm_context_s *etm_ctx); +} etm_capture_driver_t; + +enum +{ + ETMV1_TRACESYNC_CYCLE = 0x1, + ETMV1_TRIGGER_CYCLE = 0x2, +}; + +typedef struct etmv1_trace_data_s +{ + u8 pipestat; /* bits 0-2 pipeline status */ + u16 packet; /* packet data (4, 8 or 16 bit) */ + int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */ +} etmv1_trace_data_t; + +/* describe a trace context + * if support for ETMv2 or ETMv3 is to be implemented, + * this will have to be split into version independent elements + * and a version specific part + */ +typedef struct etm_context_s +{ + target_t *target; /* target this ETM is connected to */ + reg_cache_t *reg_cache; /* ETM register cache */ + etm_capture_driver_t *capture_driver; /* driver used to access ETM data */ + void *capture_driver_priv; /* capture driver private data */ + u32 trigger_percent; /* percent of trace buffer to be filled after the trigger */ + trace_status_t capture_status; /* current state of capture run */ + etmv1_trace_data_t *trace_data; /* trace data */ + u32 trace_depth; /* number of trace cycles to be analyzed, 0 if no trace data available */ + etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */ + etmv1_tracemode_t tracemode; /* type of information the trace contains (data, addres, contextID, ...) */ + armv4_5_state_t core_state; /* current core state (ARM, Thumb, Jazelle) */ + image_t *image; /* source for target opcodes */ + u32 pipe_index; /* current trace cycle */ + u32 data_index; /* cycle holding next data packet */ + int data_half; /* port half on a 16 bit port */ + u32 current_pc; /* current program counter */ + u32 pc_ok; /* full PC has been acquired */ + u32 last_branch; /* last branch address output */ + u32 last_branch_reason; /* branch reason code for the last branch encountered */ + u32 last_ptr; /* address of the last data access */ + u32 ptr_ok; /* whether last_ptr is valid */ + u32 context_id; /* context ID of the code being traced */ + u32 last_instruction; /* index of last instruction executed (to calculate cycle timings) */ +} etm_context_t; + +/* PIPESTAT values */ +typedef enum +{ + STAT_IE = 0x0, + STAT_ID = 0x1, + STAT_IN = 0x2, + STAT_WT = 0x3, + STAT_BE = 0x4, + STAT_BD = 0x5, + STAT_TR = 0x6, + STAT_TD = 0x7 +} etmv1_pipestat_t; + +/* branch reason values */ +typedef enum +{ + BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ + BR_ENABLE = 0x1, /* Trace has been enabled */ + BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ + BR_NODEBUG = 0x3, /* ARM has exited for debug state */ + BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/ + BR_RSVD5 = 0x5, /* reserved */ + BR_RSVD6 = 0x6, /* reserved */ + BR_RSVD7 = 0x7, /* reserved */ +} etmv1_branch_reason_t; + +extern char *etmv1v1_branch_reason_strings[]; + +extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx); +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, u8 *buf); + +int etm_register_commands(struct command_context_s *cmd_ctx); +int etm_register_user_commands(struct command_context_s *cmd_ctx); +extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name); + +#define ERROR_ETM_INVALID_DRIVER (-1300) +#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301) +#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302) +#define ERROR_ETM_ANALYSIS_FAILED (-1303) + +#endif /* ETM_H */ diff --git a/src/target/etm_dummy.h b/src/target/etm_dummy.h index 31afeffb..006db012 100644 --- a/src/target/etm_dummy.h +++ b/src/target/etm_dummy.h @@ -1,33 +1,33 @@ -/*************************************************************************** - * Copyright (C) 2007 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_DUMMY_H -#define ETM_DUMMY_H - -#include "command.h" -#include "target.h" -#include "register.h" -#include "arm_jtag.h" - -#include "etm.h" - -extern etm_capture_driver_t etm_dummy_capture_driver; -extern int etm_dummy_register_commands(struct command_context_s *cmd_ctx); - -#endif /* ETB_H */ +/*************************************************************************** + * Copyright (C) 2007 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_DUMMY_H +#define ETM_DUMMY_H + +#include "command.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "etm.h" + +extern etm_capture_driver_t etm_dummy_capture_driver; +extern int etm_dummy_register_commands(struct command_context_s *cmd_ctx); + +#endif /* ETB_H */ diff --git a/src/target/oocd_trace.h b/src/target/oocd_trace.h index c80a7ced..77e985fb 100644 --- a/src/target/oocd_trace.h +++ b/src/target/oocd_trace.h @@ -1,64 +1,64 @@ -/*************************************************************************** - * Copyright (C) 2007 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 OOCD_TRACE_H -#define OOCD_TRACE_H - -#include "command.h" - -#include "etm.h" - -#include -#include - -/* registers */ -enum -{ - OOCD_TRACE_ID = 0x7, - OOCD_TRACE_ADDRESS = 0x0, - OOCD_TRACE_TRIGGER_COUNTER = 0x01, - OOCD_TRACE_CONTROL = 0x2, - OOCD_TRACE_STATUS = 0x3, - OOCD_TRACE_SDRAM_COUNTER = 0x4, -}; - -/* commands */ -enum -{ - OOCD_TRACE_NOP = 0x0, - OOCD_TRACE_READ_REG = 0x10, - OOCD_TRACE_WRITE_REG = 0x18, - OOCD_TRACE_READ_RAM = 0x20, -/* OOCD_TRACE_WRITE_RAM = 0x28, */ - OOCD_TRACE_RESYNC = 0xf0, -}; - -typedef struct oocd_trace_s -{ - etm_context_t *etm_ctx; - char *tty; - int tty_fd; - struct termios oldtio, newtio; -} oocd_trace_t; - -extern etm_capture_driver_t oocd_trace_capture_driver; - -extern int oocd_trace_register_commands(struct command_context_s *cmd_ctx); - -#endif /* OOCD_TRACE_TRACE_H */ +/*************************************************************************** + * Copyright (C) 2007 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 OOCD_TRACE_H +#define OOCD_TRACE_H + +#include "command.h" + +#include "etm.h" + +#include +#include + +/* registers */ +enum +{ + OOCD_TRACE_ID = 0x7, + OOCD_TRACE_ADDRESS = 0x0, + OOCD_TRACE_TRIGGER_COUNTER = 0x01, + OOCD_TRACE_CONTROL = 0x2, + OOCD_TRACE_STATUS = 0x3, + OOCD_TRACE_SDRAM_COUNTER = 0x4, +}; + +/* commands */ +enum +{ + OOCD_TRACE_NOP = 0x0, + OOCD_TRACE_READ_REG = 0x10, + OOCD_TRACE_WRITE_REG = 0x18, + OOCD_TRACE_READ_RAM = 0x20, +/* OOCD_TRACE_WRITE_RAM = 0x28, */ + OOCD_TRACE_RESYNC = 0xf0, +}; + +typedef struct oocd_trace_s +{ + etm_context_t *etm_ctx; + char *tty; + int tty_fd; + struct termios oldtio, newtio; +} oocd_trace_t; + +extern etm_capture_driver_t oocd_trace_capture_driver; + +extern int oocd_trace_register_commands(struct command_context_s *cmd_ctx); + +#endif /* OOCD_TRACE_TRACE_H */ diff --git a/src/target/target.c b/src/target/target.c index a9f7c103..27df12fc 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1,2332 +1,2332 @@ -/*************************************************************************** - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" -#include "target.h" -#include "target_request.h" - -#include "log.h" -#include "configuration.h" -#include "binarybuffer.h" -#include "jtag.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); - - -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc); - -/* targets - */ -extern target_type_t arm7tdmi_target; -extern target_type_t arm720t_target; -extern target_type_t arm9tdmi_target; -extern target_type_t arm920t_target; -extern target_type_t arm966e_target; -extern target_type_t arm926ejs_target; -extern target_type_t feroceon_target; -extern target_type_t xscale_target; -extern target_type_t cortexm3_target; - -target_type_t *target_types[] = -{ - &arm7tdmi_target, - &arm9tdmi_target, - &arm920t_target, - &arm720t_target, - &arm966e_target, - &arm926ejs_target, - &feroceon_target, - &xscale_target, - &cortexm3_target, - NULL, -}; - -target_t *targets = NULL; -target_event_callback_t *target_event_callbacks = NULL; -target_timer_callback_t *target_timer_callbacks = NULL; - -char *target_state_strings[] = -{ - "unknown", - "running", - "halted", - "reset", - "debug_running", -}; - -char *target_debug_reason_strings[] = -{ - "debug request", "breakpoint", "watchpoint", - "watchpoint and breakpoint", "single step", - "target not halted" -}; - -char *target_endianess_strings[] = -{ - "big endian", - "little endian", -}; - -enum daemon_startup_mode startup_mode = DAEMON_ATTACH; - -static int target_continous_poll = 1; - -/* read a u32 from a buffer in target memory endianness */ -u32 target_buffer_get_u32(target_t *target, u8 *buffer) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - return le_to_h_u32(buffer); - else - return be_to_h_u32(buffer); -} - -/* read a u16 from a buffer in target memory endianness */ -u16 target_buffer_get_u16(target_t *target, u8 *buffer) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - return le_to_h_u16(buffer); - else - return be_to_h_u16(buffer); -} - -/* write a u32 to a buffer in target memory endianness */ -void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - h_u32_to_le(buffer, value); - else - h_u32_to_be(buffer, value); -} - -/* write a u16 to a buffer in target memory endianness */ -void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - h_u16_to_le(buffer, value); - else - h_u16_to_be(buffer, value); -} - -/* returns a pointer to the n-th configured target */ -target_t* get_target_by_num(int num) -{ - target_t *target = targets; - int i = 0; - - while (target) - { - if (num == i) - return target; - target = target->next; - i++; - } - - return NULL; -} - -int get_num_by_target(target_t *query_target) -{ - target_t *target = targets; - int i = 0; - - while (target) - { - if (target == query_target) - return i; - target = target->next; - i++; - } - - return -1; -} - -target_t* get_current_target(command_context_t *cmd_ctx) -{ - target_t *target = get_target_by_num(cmd_ctx->current_target); - - if (target == NULL) - { - ERROR("BUG: current_target out of bounds"); - exit(-1); - } - - return target; -} - -/* Process target initialization, when target entered debug out of reset - * the handler is unregistered at the end of this function, so it's only called once - */ -int target_init_handler(struct target_s *target, enum target_event event, void *priv) -{ - FILE *script; - struct command_context_s *cmd_ctx = priv; - - if ((event == TARGET_EVENT_HALTED) && (target->reset_script)) - { - target_unregister_event_callback(target_init_handler, priv); - - script = open_file_from_path(cmd_ctx, target->reset_script, "r"); - if (!script) - { - ERROR("couldn't open script file %s", target->reset_script); - return ERROR_OK; - } - - INFO("executing reset script '%s'", target->reset_script); - command_run_file(cmd_ctx, script, COMMAND_EXEC); - fclose(script); - - jtag_execute_queue(); - } - - return ERROR_OK; -} - -int target_run_and_halt_handler(void *priv) -{ - target_t *target = priv; - - target->type->halt(target); - - return ERROR_OK; -} - -int target_process_reset(struct command_context_s *cmd_ctx) -{ - int retval = ERROR_OK; - target_t *target; - struct timeval timeout, now; - - /* prepare reset_halt where necessary */ - target = targets; - while (target) - { - if (jtag_reset_config & RESET_SRST_PULLS_TRST) - { - switch (target->reset_mode) - { - case RESET_HALT: - command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT"); - target->reset_mode = RESET_RUN_AND_HALT; - break; - case RESET_INIT: - command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT"); - target->reset_mode = RESET_RUN_AND_INIT; - break; - default: - break; - } - } - switch (target->reset_mode) - { - case RESET_HALT: - case RESET_INIT: - target->type->prepare_reset_halt(target); - break; - default: - break; - } - target = target->next; - } - - target = targets; - while (target) - { - target->type->assert_reset(target); - target = target->next; - } - jtag_execute_queue(); - - /* request target halt if necessary, and schedule further action */ - target = targets; - while (target) - { - switch (target->reset_mode) - { - case RESET_RUN: - /* nothing to do if target just wants to be run */ - break; - case RESET_RUN_AND_HALT: - /* schedule halt */ - target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); - break; - case RESET_RUN_AND_INIT: - /* schedule halt */ - target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); - target_register_event_callback(target_init_handler, cmd_ctx); - break; - case RESET_HALT: - target->type->halt(target); - break; - case RESET_INIT: - target->type->halt(target); - target_register_event_callback(target_init_handler, cmd_ctx); - break; - default: - ERROR("BUG: unknown target->reset_mode"); - } - target = target->next; - } - - target = targets; - while (target) - { - target->type->deassert_reset(target); - target = target->next; - } - jtag_execute_queue(); - - /* Wait for reset to complete, maximum 5 seconds. */ - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - for(;;) - { - gettimeofday(&now, NULL); - - target_call_timer_callbacks(); - - target = targets; - while (target) - { - target->type->poll(target); - if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT)) - { - if (target->state != TARGET_HALTED) - { - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) - { - command_print(cmd_ctx, "Timed out waiting for reset"); - goto done; - } - usleep(100*1000); /* Do not eat all cpu */ - goto again; - } - } - target = target->next; - } - /* All targets we're waiting for are halted */ - break; - - again:; - } - done: - - - /* We want any events to be processed before the prompt */ - target_call_timer_callbacks(); - - return retval; -} - -static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - *physical = virtual; - return ERROR_OK; -} - -static int default_mmu(struct target_s *target, int *enabled) -{ - *enabled = 0; - return ERROR_OK; -} - -int target_init(struct command_context_s *cmd_ctx) -{ - target_t *target = targets; - - while (target) - { - if (target->type->init_target(cmd_ctx, target) != ERROR_OK) - { - ERROR("target '%s' init failed", target->type->name); - exit(-1); - } - - /* Set up default functions if none are provided by target */ - if (target->type->virt2phys == NULL) - { - target->type->virt2phys = default_virt2phys; - } - if (target->type->mmu == NULL) - { - target->type->mmu = default_mmu; - } - target = target->next; - } - - if (targets) - { - target_register_user_commands(cmd_ctx); - target_register_timer_callback(handle_target, 100, 1, NULL); - } - - return ERROR_OK; -} - -int target_init_reset(struct command_context_s *cmd_ctx) -{ - if (startup_mode == DAEMON_RESET) - target_process_reset(cmd_ctx); - - return ERROR_OK; -} - -int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) -{ - target_event_callback_t **callbacks_p = &target_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - if (*callbacks_p) - { - while ((*callbacks_p)->next) - callbacks_p = &((*callbacks_p)->next); - callbacks_p = &((*callbacks_p)->next); - } - - (*callbacks_p) = malloc(sizeof(target_event_callback_t)); - (*callbacks_p)->callback = callback; - (*callbacks_p)->priv = priv; - (*callbacks_p)->next = NULL; - - return ERROR_OK; -} - -int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) -{ - target_timer_callback_t **callbacks_p = &target_timer_callbacks; - struct timeval now; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - if (*callbacks_p) - { - while ((*callbacks_p)->next) - callbacks_p = &((*callbacks_p)->next); - callbacks_p = &((*callbacks_p)->next); - } - - (*callbacks_p) = malloc(sizeof(target_timer_callback_t)); - (*callbacks_p)->callback = callback; - (*callbacks_p)->periodic = periodic; - (*callbacks_p)->time_ms = time_ms; - - gettimeofday(&now, NULL); - (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; - time_ms -= (time_ms % 1000); - (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); - if ((*callbacks_p)->when.tv_usec > 1000000) - { - (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; - (*callbacks_p)->when.tv_sec += 1; - } - - (*callbacks_p)->priv = priv; - (*callbacks_p)->next = NULL; - - return ERROR_OK; -} - -int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) -{ - target_event_callback_t **p = &target_event_callbacks; - target_event_callback_t *c = target_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - while (c) - { - target_event_callback_t *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { - *p = next; - free(c); - return ERROR_OK; - } - else - p = &(c->next); - c = next; - } - - return ERROR_OK; -} - -int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) -{ - target_timer_callback_t **p = &target_timer_callbacks; - target_timer_callback_t *c = target_timer_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - while (c) - { - target_timer_callback_t *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { - *p = next; - free(c); - return ERROR_OK; - } - else - p = &(c->next); - c = next; - } - - return ERROR_OK; -} - -int target_call_event_callbacks(target_t *target, enum target_event event) -{ - target_event_callback_t *callback = target_event_callbacks; - target_event_callback_t *next_callback; - - DEBUG("target event %i", event); - - while (callback) - { - next_callback = callback->next; - callback->callback(target, event, callback->priv); - callback = next_callback; - } - - return ERROR_OK; -} - -int target_call_timer_callbacks() -{ - target_timer_callback_t *callback = target_timer_callbacks; - target_timer_callback_t *next_callback; - struct timeval now; - - gettimeofday(&now, NULL); - - while (callback) - { - next_callback = callback->next; - - if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec)) - || (now.tv_sec > callback->when.tv_sec)) - { - callback->callback(callback->priv); - if (callback->periodic) - { - int time_ms = callback->time_ms; - callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; - time_ms -= (time_ms % 1000); - callback->when.tv_sec = now.tv_sec + time_ms / 1000; - if (callback->when.tv_usec > 1000000) - { - callback->when.tv_usec = callback->when.tv_usec - 1000000; - callback->when.tv_sec += 1; - } - } - else - target_unregister_timer_callback(callback->callback, callback->priv); - } - - callback = next_callback; - } - - return ERROR_OK; -} - -int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) -{ - working_area_t *c = target->working_areas; - working_area_t *new_wa = NULL; - - /* Reevaluate working area address based on MMU state*/ - if (target->working_areas == NULL) - { - int retval; - int enabled; - retval = target->type->mmu(target, &enabled); - if (retval != ERROR_OK) - { - return retval; - } - if (enabled) - { - target->working_area = target->working_area_virt; - } - else - { - target->working_area = target->working_area_phys; - } - } - - /* only allocate multiples of 4 byte */ - if (size % 4) - { - ERROR("BUG: code tried to allocate unaligned number of bytes, padding"); - size = CEIL(size, 4); - } - - /* see if there's already a matching working area */ - while (c) - { - if ((c->free) && (c->size == size)) - { - new_wa = c; - break; - } - c = c->next; - } - - /* if not, allocate a new one */ - if (!new_wa) - { - working_area_t **p = &target->working_areas; - u32 first_free = target->working_area; - u32 free_size = target->working_area_size; - - DEBUG("allocating new working area"); - - c = target->working_areas; - while (c) - { - first_free += c->size; - free_size -= c->size; - p = &c->next; - c = c->next; - } - - if (free_size < size) - { - WARNING("not enough working area available(requested %d, free %d)", size, free_size); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - new_wa = malloc(sizeof(working_area_t)); - new_wa->next = NULL; - new_wa->size = size; - new_wa->address = first_free; - - if (target->backup_working_area) - { - new_wa->backup = malloc(new_wa->size); - target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); - } - else - { - new_wa->backup = NULL; - } - - /* put new entry in list */ - *p = new_wa; - } - - /* mark as used, and return the new (reused) area */ - new_wa->free = 0; - *area = new_wa; - - /* user pointer */ - new_wa->user = area; - - return ERROR_OK; -} - -int target_free_working_area(struct target_s *target, working_area_t *area) -{ - if (area->free) - return ERROR_OK; - - if (target->backup_working_area) - target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); - - area->free = 1; - - /* mark user pointer invalid */ - *area->user = NULL; - area->user = NULL; - - return ERROR_OK; -} - -int target_free_all_working_areas(struct target_s *target) -{ - working_area_t *c = target->working_areas; - - while (c) - { - working_area_t *next = c->next; - target_free_working_area(target, c); - - if (c->backup) - free(c->backup); - - free(c); - - c = next; - } - - target->working_areas = NULL; - - return ERROR_OK; -} - -int target_register_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area
<'backup'|'nobackup'> [virtual address]"); - register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys "); - - return ERROR_OK; -} - -int target_arch_state(struct target_s *target) -{ - int retval; - if (target==NULL) - { - USER("No target has been configured"); - return ERROR_OK; - } - - USER("target state: %s", target_state_strings[target->state]); - - if (target->state!=TARGET_HALTED) - return ERROR_OK; - - retval=target->type->arch_state(target); - return retval; -} - -/* Single aligned words are guaranteed to use 16 or 32 bit access - * mode respectively, otherwise data is handled as quickly as - * possible - */ -int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) -{ - int retval; - - DEBUG("writing buffer of %i byte at 0x%8.8x", size, address); - - if (((address % 2) == 0) && (size == 2)) - { - return target->type->write_memory(target, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) - { - int unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - /* use bulk writes above a certain limit. This may have to be changed */ - if (aligned > 128) - { - if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) - return retval; - } - else - { - if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) - return retval; - } - - buffer += aligned; - address += aligned; - size -= aligned; - } - - /* handle tail writes of less than 4 bytes */ - if (size > 0) - { - if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - - -/* Single aligned words are guaranteed to use 16 or 32 bit access - * mode respectively, otherwise data is handled as quickly as - * possible - */ -int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) -{ - int retval; - - DEBUG("reading buffer of %i byte at 0x%8.8x", size, address); - - if (((address % 2) == 0) && (size == 2)) - { - return target->type->read_memory(target, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) - { - int unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) - return retval; - - buffer += aligned; - address += aligned; - size -= aligned; - } - - /* handle tail writes of less than 4 bytes */ - if (size > 0) - { - if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - -int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc) -{ - u8 *buffer; - int retval; - int i; - u32 checksum = 0; - - if ((retval = target->type->checksum_memory(target, address, - size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - buffer = malloc(size); - if (buffer == NULL) - { - ERROR("error allocating buffer for section (%d bytes)", size); - return ERROR_INVALID_ARGUMENTS; - } - retval = target_read_buffer(target, address, size, buffer); - if (retval != ERROR_OK) - { - free(buffer); - return retval; - } - - /* convert to target endianess */ - for (i = 0; i < (size/sizeof(u32)); i++) - { - u32 target_data; - target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]); - target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data); - } - - retval = image_calculate_checksum( buffer, size, &checksum ); - free(buffer); - } - - *crc = checksum; - - return retval; -} - -int target_read_u32(struct target_s *target, u32 address, u32 *value) -{ - u8 value_buf[4]; - - int retval = target->type->read_memory(target, address, 4, 1, value_buf); - - if (retval == ERROR_OK) - { - *value = target_buffer_get_u32(target, value_buf); - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_read_u16(struct target_s *target, u32 address, u16 *value) -{ - u8 value_buf[2]; - - int retval = target->type->read_memory(target, address, 2, 1, value_buf); - - if (retval == ERROR_OK) - { - *value = target_buffer_get_u16(target, value_buf); - DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_read_u8(struct target_s *target, u32 address, u8 *value) -{ - int retval = target->type->read_memory(target, address, 1, 1, value); - - if (retval == ERROR_OK) - { - DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_write_u32(struct target_s *target, u32 address, u32 value) -{ - int retval; - u8 value_buf[4]; - - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); - - target_buffer_set_u32(target, value_buf, value); - if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_write_u16(struct target_s *target, u32 address, u16 value) -{ - int retval; - u8 value_buf[2]; - - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); - - target_buffer_set_u16(target, value_buf, value); - if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_write_u8(struct target_s *target, u32 address, u8 value) -{ - int retval; - - DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); - - if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_register_user_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); - register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); - register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); - register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]"); - register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]"); - register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]"); - register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset"); - - register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte "); - - register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint
[hw]"); - register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint "); - register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint
[value] [mask]"); - register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint "); - - register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image
['bin'|'ihex'|'elf'|'s19']"); - register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image
"); - register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image [offset] [type]"); - register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary
"); - register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary
"); - - target_request_register_commands(cmd_ctx); - trace_register_commands(cmd_ctx); - - return ERROR_OK; -} - -int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = targets; - int count = 0; - - if (argc == 1) - { - int num = strtoul(args[0], NULL, 0); - - while (target) - { - count++; - target = target->next; - } - - if (num < count) - cmd_ctx->current_target = num; - else - command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count); - - return ERROR_OK; - } - - while (target) - { - command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]); - target = target->next; - } - - return ERROR_OK; -} - -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int i; - int found = 0; - - if (argc < 3) - { - ERROR("target command requires at least three arguments: "); - exit(-1); - } - - /* search for the specified target */ - if (args[0] && (args[0][0] != 0)) - { - for (i = 0; target_types[i]; i++) - { - if (strcmp(args[0], target_types[i]->name) == 0) - { - target_t **last_target_p = &targets; - - /* register target specific commands */ - if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) - { - ERROR("couldn't register '%s' commands", args[0]); - exit(-1); - } - - if (*last_target_p) - { - while ((*last_target_p)->next) - last_target_p = &((*last_target_p)->next); - last_target_p = &((*last_target_p)->next); - } - - *last_target_p = malloc(sizeof(target_t)); - - (*last_target_p)->type = target_types[i]; - - if (strcmp(args[1], "big") == 0) - (*last_target_p)->endianness = TARGET_BIG_ENDIAN; - else if (strcmp(args[1], "little") == 0) - (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; - else - { - ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); - exit(-1); - } - - /* what to do on a target reset */ - if (strcmp(args[2], "reset_halt") == 0) - (*last_target_p)->reset_mode = RESET_HALT; - else if (strcmp(args[2], "reset_run") == 0) - (*last_target_p)->reset_mode = RESET_RUN; - else if (strcmp(args[2], "reset_init") == 0) - (*last_target_p)->reset_mode = RESET_INIT; - else if (strcmp(args[2], "run_and_halt") == 0) - (*last_target_p)->reset_mode = RESET_RUN_AND_HALT; - else if (strcmp(args[2], "run_and_init") == 0) - (*last_target_p)->reset_mode = RESET_RUN_AND_INIT; - else - { - ERROR("unknown target startup mode %s", args[2]); - exit(-1); - } - (*last_target_p)->run_and_halt_time = 1000; /* default 1s */ - - (*last_target_p)->reset_script = NULL; - (*last_target_p)->post_halt_script = NULL; - (*last_target_p)->pre_resume_script = NULL; - (*last_target_p)->gdb_program_script = NULL; - - (*last_target_p)->working_area = 0x0; - (*last_target_p)->working_area_size = 0x0; - (*last_target_p)->working_areas = NULL; - (*last_target_p)->backup_working_area = 0; - - (*last_target_p)->state = TARGET_UNKNOWN; - (*last_target_p)->reg_cache = NULL; - (*last_target_p)->breakpoints = NULL; - (*last_target_p)->watchpoints = NULL; - (*last_target_p)->next = NULL; - (*last_target_p)->arch_info = NULL; - - /* initialize trace information */ - (*last_target_p)->trace_info = malloc(sizeof(trace_t)); - (*last_target_p)->trace_info->num_trace_points = 0; - (*last_target_p)->trace_info->trace_points_size = 0; - (*last_target_p)->trace_info->trace_points = NULL; - (*last_target_p)->trace_info->trace_history_size = 0; - (*last_target_p)->trace_info->trace_history = NULL; - (*last_target_p)->trace_info->trace_history_pos = 0; - (*last_target_p)->trace_info->trace_history_overflowed = 0; - - (*last_target_p)->dbgmsg = NULL; - (*last_target_p)->dbg_msg_enabled = 0; - - (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); - - found = 1; - break; - } - } - } - - /* no matching target found */ - if (!found) - { - ERROR("target '%s' not found", args[0]); - exit(-1); - } - - return ERROR_OK; -} - -/* usage: target_script */ -int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if (argc < 3) - { - ERROR("incomplete target_script command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (strcmp(args[1], "reset") == 0) - { - if (target->reset_script) - free(target->reset_script); - target->reset_script = strdup(args[2]); - } - else if (strcmp(args[1], "post_halt") == 0) - { - if (target->post_halt_script) - free(target->post_halt_script); - target->post_halt_script = strdup(args[2]); - } - else if (strcmp(args[1], "pre_resume") == 0) - { - if (target->pre_resume_script) - free(target->pre_resume_script); - target->pre_resume_script = strdup(args[2]); - } - else if (strcmp(args[1], "gdb_program_config") == 0) - { - if (target->gdb_program_script) - free(target->gdb_program_script); - target->gdb_program_script = strdup(args[2]); - } - else - { - ERROR("unknown event type: '%s", args[1]); - exit(-1); - } - - return ERROR_OK; -} - -int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if (argc < 2) - { - ERROR("incomplete run_and_halt_time command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - target->run_and_halt_time = strtoul(args[1], NULL, 0); - - return ERROR_OK; -} - -int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if ((argc < 4) || (argc > 5)) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - target_free_all_working_areas(target); - - target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0); - if (argc == 5) - { - target->working_area_virt = strtoul(args[4], NULL, 0); - } - target->working_area_size = strtoul(args[2], NULL, 0); - - if (strcmp(args[3], "backup") == 0) - { - target->backup_working_area = 1; - } - else if (strcmp(args[3], "nobackup") == 0) - { - target->backup_working_area = 0; - } - else - { - ERROR("unrecognized argument (%s)", args[3]); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - - -/* process target state changes */ -int handle_target(void *priv) -{ - int retval; - target_t *target = targets; - - while (target) - { - /* only poll if target isn't already halted */ - if (target->state != TARGET_HALTED) - { - if (target_continous_poll) - if ((retval = target->type->poll(target)) != ERROR_OK) - { - ERROR("couldn't poll target(%d). It's due for a reset.", retval); - } - } - - target = target->next; - } - - return ERROR_OK; -} - -int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - reg_t *reg = NULL; - int count = 0; - char *value; - - DEBUG("-"); - - target = get_current_target(cmd_ctx); - - /* list all available registers for the current target */ - if (argc == 0) - { - reg_cache_t *cache = target->reg_cache; - - count = 0; - while(cache) - { - int i; - for (i = 0; i < cache->num_regs; i++) - { - value = buf_to_str(cache->reg_list[i].value, cache->reg_list[i].size, 16); - command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid); - free(value); - } - cache = cache->next; - } - - return ERROR_OK; - } - - /* access a single register by its ordinal number */ - if ((args[0][0] >= '0') && (args[0][0] <= '9')) - { - int num = strtoul(args[0], NULL, 0); - reg_cache_t *cache = target->reg_cache; - - count = 0; - while(cache) - { - int i; - for (i = 0; i < cache->num_regs; i++) - { - if (count++ == num) - { - reg = &cache->reg_list[i]; - break; - } - } - if (reg) - break; - cache = cache->next; - } - - if (!reg) - { - command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; - } - } else /* access a single register by its name */ - { - reg = register_get_by_name(target->reg_cache, args[0], 1); - - if (!reg) - { - command_print(cmd_ctx, "register %s not found in current target", args[0]); - return ERROR_OK; - } - } - - /* display a register */ - if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9')))) - { - if ((argc == 2) && (strcmp(args[1], "force") == 0)) - reg->valid = 0; - - if (reg->valid == 0) - { - reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } - arch_type->get(reg); - } - value = buf_to_str(reg->value, reg->size, 16); - command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); - free(value); - return ERROR_OK; - } - - /* set register value */ - if (argc == 2) - { - u8 *buf = malloc(CEIL(reg->size, 8)); - str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0); - - reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } - - arch_type->set(reg, buf); - - value = buf_to_str(reg->value, reg->size, 16); - command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); - free(value); - - free(buf); - - return ERROR_OK; - } - - command_print(cmd_ctx, "usage: reg <#|name> [value]"); - - return ERROR_OK; -} - -static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms); - -int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - { - target->type->poll(target); - target_arch_state(target); - } - else - { - if (strcmp(args[0], "on") == 0) - { - target_continous_poll = 1; - } - else if (strcmp(args[0], "off") == 0) - { - target_continous_poll = 0; - } - else - { - command_print(cmd_ctx, "arg is \"on\" or \"off\""); - } - } - - - return ERROR_OK; -} - -int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int ms = 5000; - - if (argc > 0) - { - char *end; - - ms = strtoul(args[0], &end, 0) * 1000; - if (*end) - { - command_print(cmd_ctx, "usage: %s [seconds]", cmd); - return ERROR_OK; - } - } - - return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms); -} - -static void target_process_events(struct command_context_s *cmd_ctx) -{ - target_t *target = get_current_target(cmd_ctx); - target->type->poll(target); - target_call_timer_callbacks(); -} - -static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms) -{ - int retval; - struct timeval timeout, now; - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 0, ms * 1000); - - target_t *target = get_current_target(cmd_ctx); - for (;;) - { - if ((retval=target->type->poll(target))!=ERROR_OK) - return retval; - target_call_timer_callbacks(); - if (target->state == state) - { - break; - } - command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]); - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) - { - command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]); - ERROR("timed out while waiting for target %s", target_state_strings[state]); - break; - } - } - - return ERROR_OK; -} - -int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - DEBUG("-"); - - command_print(cmd_ctx, "requesting target halt..."); - - if ((retval = target->type->halt(target)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_ALREADY_HALTED: - command_print(cmd_ctx, "target already halted"); - break; - case ERROR_TARGET_TIMEOUT: - command_print(cmd_ctx, "target timed out... shutting down"); - return retval; - default: - command_print(cmd_ctx, "unknown error... shutting down"); - return retval; - } - } - - return handle_wait_halt_command(cmd_ctx, cmd, args, argc); -} - -/* what to do on daemon startup */ -int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc == 1) - { - if (strcmp(args[0], "attach") == 0) - { - startup_mode = DAEMON_ATTACH; - return ERROR_OK; - } - else if (strcmp(args[0], "reset") == 0) - { - startup_mode = DAEMON_RESET; - return ERROR_OK; - } - } - - WARNING("invalid daemon_startup configuration directive: %s", args[0]); - return ERROR_OK; - -} - -int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - int retval; - - command_print(cmd_ctx, "requesting target halt and executing a soft reset"); - - if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_TIMEOUT: - command_print(cmd_ctx, "target timed out... shutting down"); - exit(-1); - default: - command_print(cmd_ctx, "unknown error... shutting down"); - exit(-1); - } - } - - return ERROR_OK; -} - -int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - enum target_reset_mode reset_mode = target->reset_mode; - enum target_reset_mode save = target->reset_mode; - - DEBUG("-"); - - if (argc >= 1) - { - if (strcmp("run", args[0]) == 0) - reset_mode = RESET_RUN; - else if (strcmp("halt", args[0]) == 0) - reset_mode = RESET_HALT; - else if (strcmp("init", args[0]) == 0) - reset_mode = RESET_INIT; - else if (strcmp("run_and_halt", args[0]) == 0) - { - reset_mode = RESET_RUN_AND_HALT; - if (argc >= 2) - { - target->run_and_halt_time = strtoul(args[1], NULL, 0); - } - } - else if (strcmp("run_and_init", args[0]) == 0) - { - reset_mode = RESET_RUN_AND_INIT; - if (argc >= 2) - { - target->run_and_halt_time = strtoul(args[1], NULL, 0); - } - } - else - { - command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]"); - return ERROR_OK; - } - } - - /* temporarily modify mode of current reset target */ - target->reset_mode = reset_mode; - - /* reset *all* targets */ - target_process_reset(cmd_ctx); - - /* Restore default reset mode for this target */ - target->reset_mode = save; - - return ERROR_OK; -} - -int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ - else if (argc == 1) - retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ - else - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - target_process_events(cmd_ctx); - - target_arch_state(target); - - return retval; -} - -int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - DEBUG("-"); - - if (argc == 0) - target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */ - - if (argc == 1) - target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */ - - return ERROR_OK; -} - -int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - const int line_bytecnt = 32; - int count = 1; - int size = 4; - u32 address = 0; - int line_modulo; - int i; - - char output[128]; - int output_len; - - int retval; - - u8 *buffer; - target_t *target = get_current_target(cmd_ctx); - - 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; line_modulo = line_bytecnt / 4; - break; - case 'h': - size = 2; line_modulo = line_bytecnt / 2; - break; - case 'b': - size = 1; line_modulo = line_bytecnt / 1; - break; - default: - return ERROR_OK; - } - - buffer = calloc(count, size); - retval = target->type->read_memory(target, address, size, count, buffer); - if (retval != 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"); - break; - } - return ERROR_OK; - } - - output_len = 0; - - for (i = 0; i < count; i++) - { - if (i%line_modulo == 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 ", target_buffer_get_u32(target, &buffer[i*4])); - break; - case 2: - output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2])); - break; - case 1: - output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]); - break; - } - - if ((i%line_modulo == line_modulo-1) || (i == count - 1)) - { - command_print(cmd_ctx, output); - output_len = 0; - } - } - - free(buffer); - - return ERROR_OK; -} - -int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u32 address = 0; - u32 value = 0; - int retval; - target_t *target = get_current_target(cmd_ctx); - u8 value_buf[4]; - - if (argc < 2) - return ERROR_OK; - - address = strtoul(args[0], NULL, 0); - value = strtoul(args[1], NULL, 0); - - switch (cmd[2]) - { - case 'w': - target_buffer_set_u32(target, value_buf, value); - retval = target->type->write_memory(target, address, 4, 1, value_buf); - break; - case 'h': - target_buffer_set_u16(target, value_buf, value); - retval = target->type->write_memory(target, address, 2, 1, value_buf); - break; - case 'b': - value_buf[0] = value; - retval = target->type->write_memory(target, address, 1, 1, value_buf); - 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"); - break; - } - - return ERROR_OK; - -} - -int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 *buffer; - u32 buf_cnt; - u32 image_size; - int i; - int retval; - - image_t image; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc < 1) - { - command_print(cmd_ctx, "usage: load_image [address] [type]"); - return ERROR_OK; - } - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - image.base_address_set = 1; - image.base_address = strtoul(args[1], NULL, 0); - } - else - { - image.base_address_set = 0; - } - - image.start_address_set = 0; - - duration_start_measure(&duration); - - if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "load_image error: %s", image.error_str); - return ERROR_OK; - } - - image_size = 0x0; - for (i = 0; i < image.num_sections; i++) - { - buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { - command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); - break; - } - - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("image_read_section failed with error code: %i", retval); - command_print(cmd_ctx, "image reading failed, download aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); - image_size += buf_cnt; - command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address); - - free(buffer); - } - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); - free(duration_text); - - image_close(&image); - - return ERROR_OK; - -} - -int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t fileio; - - u32 address; - u32 size; - u8 buffer[560]; - int retval; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc != 3) - { - command_print(cmd_ctx, "usage: dump_image
"); - return ERROR_OK; - } - - address = strtoul(args[1], NULL, 0); - size = strtoul(args[2], NULL, 0); - - if ((address & 3) || (size & 3)) - { - command_print(cmd_ctx, "only 32-bit aligned address and size are supported"); - return ERROR_OK; - } - - if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); - return ERROR_OK; - } - - duration_start_measure(&duration); - - while (size > 0) - { - u32 size_written; - u32 this_run_size = (size > 560) ? 560 : size; - - retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer); - if (retval != ERROR_OK) - { - command_print(cmd_ctx, "Reading memory failed %d", retval); - break; - } - - fileio_write(&fileio, this_run_size, buffer, &size_written); - - size -= this_run_size; - address += this_run_size; - } - - fileio_close(&fileio); - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); - free(duration_text); - - return ERROR_OK; -} - -int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 *buffer; - u32 buf_cnt; - u32 image_size; - int i; - int retval; - u32 checksum = 0; - u32 mem_checksum = 0; - - image_t image; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc < 1) - { - command_print(cmd_ctx, "usage: verify_image [offset] [type]"); - return ERROR_OK; - } - - if (!target) - { - ERROR("no target selected"); - return ERROR_OK; - } - - duration_start_measure(&duration); - - if (argc >= 2) - { - image.base_address_set = 1; - image.base_address = strtoul(args[1], NULL, 0); - } - else - { - image.base_address_set = 0; - image.base_address = 0x0; - } - - image.start_address_set = 0; - - if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "verify_image error: %s", image.error_str); - return ERROR_OK; - } - - image_size = 0x0; - for (i = 0; i < image.num_sections; i++) - { - buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { - command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); - break; - } - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("image_read_section failed with error code: %i", retval); - command_print(cmd_ctx, "image reading failed, verify aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - - /* calculate checksum of image */ - image_calculate_checksum( buffer, buf_cnt, &checksum ); - - retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); - - if( retval != ERROR_OK ) - { - command_print(cmd_ctx, "could not calculate checksum, verify aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - - if( checksum != mem_checksum ) - { - /* failed crc checksum, fall back to a binary compare */ - u8 *data; - - command_print(cmd_ctx, "checksum mismatch - attempting binary compare"); - - data = (u8*)malloc(buf_cnt); - - /* Can we use 32bit word accesses? */ - int size = 1; - int count = buf_cnt; - if ((count % 4) == 0) - { - size *= 4; - count /= 4; - } - retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data); - - if (retval == ERROR_OK) - { - int t; - for (t = 0; t < buf_cnt; t++) - { - if (data[t] != buffer[t]) - { - command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]); - free(data); - free(buffer); - image_close(&image); - return ERROR_OK; - } - } - } - - free(data); - } - - free(buffer); - image_size += buf_cnt; - } - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); - free(duration_text); - - image_close(&image); - - return ERROR_OK; -} - -int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - { - breakpoint_t *breakpoint = target->breakpoints; - - while (breakpoint) - { - if (breakpoint->type == BKPT_SOFT) - { - char* buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); - command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); - free(buf); - } - else - { - command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); - } - breakpoint = breakpoint->next; - } - } - else if (argc >= 2) - { - int hw = BKPT_SOFT; - u32 length = 0; - - length = strtoul(args[1], NULL, 0); - - if (argc >= 3) - if (strcmp(args[2], "hw") == 0) - hw = BKPT_HARD; - - if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "target must be halted to set breakpoints"); - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - command_print(cmd_ctx, "no more breakpoints available"); - break; - default: - command_print(cmd_ctx, "unknown error, breakpoint not set"); - break; - } - } - else - { - command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0)); - } - } - else - { - command_print(cmd_ctx, "usage: bp
['hw']"); - } - - return ERROR_OK; -} - -int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc > 0) - breakpoint_remove(target, strtoul(args[0], NULL, 0)); - - return ERROR_OK; -} - -int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - int retval; - - if (argc == 0) - { - watchpoint_t *watchpoint = target->watchpoints; - - while (watchpoint) - { - command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); - watchpoint = watchpoint->next; - } - } - else if (argc >= 2) - { - enum watchpoint_rw type = WPT_ACCESS; - u32 data_value = 0x0; - u32 data_mask = 0xffffffff; - - if (argc >= 3) - { - switch(args[2][0]) - { - case 'r': - type = WPT_READ; - break; - case 'w': - type = WPT_WRITE; - break; - case 'a': - type = WPT_ACCESS; - break; - default: - command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); - return ERROR_OK; - } - } - if (argc >= 4) - { - data_value = strtoul(args[3], NULL, 0); - } - if (argc >= 5) - { - data_mask = strtoul(args[4], NULL, 0); - } - - if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0), - strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "target must be halted to set watchpoints"); - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - command_print(cmd_ctx, "no more watchpoints available"); - break; - default: - command_print(cmd_ctx, "unknown error, watchpoint not set"); - break; - } - } - } - else - { - command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); - } - - return ERROR_OK; -} - -int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc > 0) - watchpoint_remove(target, strtoul(args[0], NULL, 0)); - - return ERROR_OK; -} - -int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - u32 va; - u32 pa; - - if (argc != 1) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - va = strtoul(args[0], NULL, 0); - - retval = target->type->virt2phys(target, va, &pa); - if (retval == ERROR_OK) - { - command_print(cmd_ctx, "Physical address 0x%08x", pa); - } - else - { - /* lower levels will have logged a detailed error which is - * forwarded to telnet/GDB session. - */ - } - return retval; -} +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" +#include "target.h" +#include "target_request.h" + +#include "log.h" +#include "configuration.h" +#include "binarybuffer.h" +#include "jtag.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); + + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc); + +/* targets + */ +extern target_type_t arm7tdmi_target; +extern target_type_t arm720t_target; +extern target_type_t arm9tdmi_target; +extern target_type_t arm920t_target; +extern target_type_t arm966e_target; +extern target_type_t arm926ejs_target; +extern target_type_t feroceon_target; +extern target_type_t xscale_target; +extern target_type_t cortexm3_target; + +target_type_t *target_types[] = +{ + &arm7tdmi_target, + &arm9tdmi_target, + &arm920t_target, + &arm720t_target, + &arm966e_target, + &arm926ejs_target, + &feroceon_target, + &xscale_target, + &cortexm3_target, + NULL, +}; + +target_t *targets = NULL; +target_event_callback_t *target_event_callbacks = NULL; +target_timer_callback_t *target_timer_callbacks = NULL; + +char *target_state_strings[] = +{ + "unknown", + "running", + "halted", + "reset", + "debug_running", +}; + +char *target_debug_reason_strings[] = +{ + "debug request", "breakpoint", "watchpoint", + "watchpoint and breakpoint", "single step", + "target not halted" +}; + +char *target_endianess_strings[] = +{ + "big endian", + "little endian", +}; + +enum daemon_startup_mode startup_mode = DAEMON_ATTACH; + +static int target_continous_poll = 1; + +/* read a u32 from a buffer in target memory endianness */ +u32 target_buffer_get_u32(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u32(buffer); + else + return be_to_h_u32(buffer); +} + +/* read a u16 from a buffer in target memory endianness */ +u16 target_buffer_get_u16(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u16(buffer); + else + return be_to_h_u16(buffer); +} + +/* write a u32 to a buffer in target memory endianness */ +void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u32_to_le(buffer, value); + else + h_u32_to_be(buffer, value); +} + +/* write a u16 to a buffer in target memory endianness */ +void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u16_to_le(buffer, value); + else + h_u16_to_be(buffer, value); +} + +/* returns a pointer to the n-th configured target */ +target_t* get_target_by_num(int num) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (num == i) + return target; + target = target->next; + i++; + } + + return NULL; +} + +int get_num_by_target(target_t *query_target) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (target == query_target) + return i; + target = target->next; + i++; + } + + return -1; +} + +target_t* get_current_target(command_context_t *cmd_ctx) +{ + target_t *target = get_target_by_num(cmd_ctx->current_target); + + if (target == NULL) + { + ERROR("BUG: current_target out of bounds"); + exit(-1); + } + + return target; +} + +/* Process target initialization, when target entered debug out of reset + * the handler is unregistered at the end of this function, so it's only called once + */ +int target_init_handler(struct target_s *target, enum target_event event, void *priv) +{ + FILE *script; + struct command_context_s *cmd_ctx = priv; + + if ((event == TARGET_EVENT_HALTED) && (target->reset_script)) + { + target_unregister_event_callback(target_init_handler, priv); + + script = open_file_from_path(cmd_ctx, target->reset_script, "r"); + if (!script) + { + ERROR("couldn't open script file %s", target->reset_script); + return ERROR_OK; + } + + INFO("executing reset script '%s'", target->reset_script); + command_run_file(cmd_ctx, script, COMMAND_EXEC); + fclose(script); + + jtag_execute_queue(); + } + + return ERROR_OK; +} + +int target_run_and_halt_handler(void *priv) +{ + target_t *target = priv; + + target->type->halt(target); + + return ERROR_OK; +} + +int target_process_reset(struct command_context_s *cmd_ctx) +{ + int retval = ERROR_OK; + target_t *target; + struct timeval timeout, now; + + /* prepare reset_halt where necessary */ + target = targets; + while (target) + { + if (jtag_reset_config & RESET_SRST_PULLS_TRST) + { + switch (target->reset_mode) + { + case RESET_HALT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT"); + target->reset_mode = RESET_RUN_AND_HALT; + break; + case RESET_INIT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT"); + target->reset_mode = RESET_RUN_AND_INIT; + break; + default: + break; + } + } + switch (target->reset_mode) + { + case RESET_HALT: + case RESET_INIT: + target->type->prepare_reset_halt(target); + break; + default: + break; + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->assert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* request target halt if necessary, and schedule further action */ + target = targets; + while (target) + { + switch (target->reset_mode) + { + case RESET_RUN: + /* nothing to do if target just wants to be run */ + break; + case RESET_RUN_AND_HALT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + break; + case RESET_RUN_AND_INIT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + case RESET_HALT: + target->type->halt(target); + break; + case RESET_INIT: + target->type->halt(target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + default: + ERROR("BUG: unknown target->reset_mode"); + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->deassert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* Wait for reset to complete, maximum 5 seconds. */ + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + for(;;) + { + gettimeofday(&now, NULL); + + target_call_timer_callbacks(); + + target = targets; + while (target) + { + target->type->poll(target); + if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT)) + { + if (target->state != TARGET_HALTED) + { + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "Timed out waiting for reset"); + goto done; + } + usleep(100*1000); /* Do not eat all cpu */ + goto again; + } + } + target = target->next; + } + /* All targets we're waiting for are halted */ + break; + + again:; + } + done: + + + /* We want any events to be processed before the prompt */ + target_call_timer_callbacks(); + + return retval; +} + +static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + *physical = virtual; + return ERROR_OK; +} + +static int default_mmu(struct target_s *target, int *enabled) +{ + *enabled = 0; + return ERROR_OK; +} + +int target_init(struct command_context_s *cmd_ctx) +{ + target_t *target = targets; + + while (target) + { + if (target->type->init_target(cmd_ctx, target) != ERROR_OK) + { + ERROR("target '%s' init failed", target->type->name); + exit(-1); + } + + /* Set up default functions if none are provided by target */ + if (target->type->virt2phys == NULL) + { + target->type->virt2phys = default_virt2phys; + } + if (target->type->mmu == NULL) + { + target->type->mmu = default_mmu; + } + target = target->next; + } + + if (targets) + { + target_register_user_commands(cmd_ctx); + target_register_timer_callback(handle_target, 100, 1, NULL); + } + + return ERROR_OK; +} + +int target_init_reset(struct command_context_s *cmd_ctx) +{ + if (startup_mode == DAEMON_RESET) + target_process_reset(cmd_ctx); + + return ERROR_OK; +} + +int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **callbacks_p = &target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_event_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) +{ + target_timer_callback_t **callbacks_p = &target_timer_callbacks; + struct timeval now; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_timer_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->periodic = periodic; + (*callbacks_p)->time_ms = time_ms; + + gettimeofday(&now, NULL); + (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); + if ((*callbacks_p)->when.tv_usec > 1000000) + { + (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; + (*callbacks_p)->when.tv_sec += 1; + } + + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **p = &target_event_callbacks; + target_event_callback_t *c = target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_event_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + target_timer_callback_t **p = &target_timer_callbacks; + target_timer_callback_t *c = target_timer_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_timer_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_call_event_callbacks(target_t *target, enum target_event event) +{ + target_event_callback_t *callback = target_event_callbacks; + target_event_callback_t *next_callback; + + DEBUG("target event %i", event); + + while (callback) + { + next_callback = callback->next; + callback->callback(target, event, callback->priv); + callback = next_callback; + } + + return ERROR_OK; +} + +int target_call_timer_callbacks() +{ + target_timer_callback_t *callback = target_timer_callbacks; + target_timer_callback_t *next_callback; + struct timeval now; + + gettimeofday(&now, NULL); + + while (callback) + { + next_callback = callback->next; + + if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec)) + || (now.tv_sec > callback->when.tv_sec)) + { + callback->callback(callback->priv); + if (callback->periodic) + { + int time_ms = callback->time_ms; + callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + callback->when.tv_sec = now.tv_sec + time_ms / 1000; + if (callback->when.tv_usec > 1000000) + { + callback->when.tv_usec = callback->when.tv_usec - 1000000; + callback->when.tv_sec += 1; + } + } + else + target_unregister_timer_callback(callback->callback, callback->priv); + } + + callback = next_callback; + } + + return ERROR_OK; +} + +int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) +{ + working_area_t *c = target->working_areas; + working_area_t *new_wa = NULL; + + /* Reevaluate working area address based on MMU state*/ + if (target->working_areas == NULL) + { + int retval; + int enabled; + retval = target->type->mmu(target, &enabled); + if (retval != ERROR_OK) + { + return retval; + } + if (enabled) + { + target->working_area = target->working_area_virt; + } + else + { + target->working_area = target->working_area_phys; + } + } + + /* only allocate multiples of 4 byte */ + if (size % 4) + { + ERROR("BUG: code tried to allocate unaligned number of bytes, padding"); + size = CEIL(size, 4); + } + + /* see if there's already a matching working area */ + while (c) + { + if ((c->free) && (c->size == size)) + { + new_wa = c; + break; + } + c = c->next; + } + + /* if not, allocate a new one */ + if (!new_wa) + { + working_area_t **p = &target->working_areas; + u32 first_free = target->working_area; + u32 free_size = target->working_area_size; + + DEBUG("allocating new working area"); + + c = target->working_areas; + while (c) + { + first_free += c->size; + free_size -= c->size; + p = &c->next; + c = c->next; + } + + if (free_size < size) + { + WARNING("not enough working area available(requested %d, free %d)", size, free_size); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + new_wa = malloc(sizeof(working_area_t)); + new_wa->next = NULL; + new_wa->size = size; + new_wa->address = first_free; + + if (target->backup_working_area) + { + new_wa->backup = malloc(new_wa->size); + target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); + } + else + { + new_wa->backup = NULL; + } + + /* put new entry in list */ + *p = new_wa; + } + + /* mark as used, and return the new (reused) area */ + new_wa->free = 0; + *area = new_wa; + + /* user pointer */ + new_wa->user = area; + + return ERROR_OK; +} + +int target_free_working_area(struct target_s *target, working_area_t *area) +{ + if (area->free) + return ERROR_OK; + + if (target->backup_working_area) + target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); + + area->free = 1; + + /* mark user pointer invalid */ + *area->user = NULL; + area->user = NULL; + + return ERROR_OK; +} + +int target_free_all_working_areas(struct target_s *target) +{ + working_area_t *c = target->working_areas; + + while (c) + { + working_area_t *next = c->next; + target_free_working_area(target, c); + + if (c->backup) + free(c->backup); + + free(c); + + c = next; + } + + target->working_areas = NULL; + + return ERROR_OK; +} + +int target_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area
<'backup'|'nobackup'> [virtual address]"); + register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys "); + + return ERROR_OK; +} + +int target_arch_state(struct target_s *target) +{ + int retval; + if (target==NULL) + { + USER("No target has been configured"); + return ERROR_OK; + } + + USER("target state: %s", target_state_strings[target->state]); + + if (target->state!=TARGET_HALTED) + return ERROR_OK; + + retval=target->type->arch_state(target); + return retval; +} + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("writing buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->write_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + /* use bulk writes above a certain limit. This may have to be changed */ + if (aligned > 128) + { + if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + else + { + if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("reading buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->read_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc) +{ + u8 *buffer; + int retval; + int i; + u32 checksum = 0; + + if ((retval = target->type->checksum_memory(target, address, + size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + buffer = malloc(size); + if (buffer == NULL) + { + ERROR("error allocating buffer for section (%d bytes)", size); + return ERROR_INVALID_ARGUMENTS; + } + retval = target_read_buffer(target, address, size, buffer); + if (retval != ERROR_OK) + { + free(buffer); + return retval; + } + + /* convert to target endianess */ + for (i = 0; i < (size/sizeof(u32)); i++) + { + u32 target_data; + target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]); + target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data); + } + + retval = image_calculate_checksum( buffer, size, &checksum ); + free(buffer); + } + + *crc = checksum; + + return retval; +} + +int target_read_u32(struct target_s *target, u32 address, u32 *value) +{ + u8 value_buf[4]; + + int retval = target->type->read_memory(target, address, 4, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u32(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u16(struct target_s *target, u32 address, u16 *value) +{ + u8 value_buf[2]; + + int retval = target->type->read_memory(target, address, 2, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u16(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u8(struct target_s *target, u32 address, u8 *value) +{ + int retval = target->type->read_memory(target, address, 1, 1, value); + + if (retval == ERROR_OK) + { + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_write_u32(struct target_s *target, u32 address, u32 value) +{ + int retval; + u8 value_buf[4]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u32(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u16(struct target_s *target, u32 address, u16 value) +{ + int retval; + u8 value_buf[2]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u16(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u8(struct target_s *target, u32 address, u8 value) +{ + int retval; + + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); + + if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); + register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); + register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); + register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]"); + register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]"); + register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]"); + register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset"); + + register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte "); + + register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint
[hw]"); + register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint "); + register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint
[value] [mask]"); + register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint "); + + register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image
['bin'|'ihex'|'elf'|'s19']"); + register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image
"); + register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image [offset] [type]"); + register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary
"); + register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary
"); + + target_request_register_commands(cmd_ctx); + trace_register_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = targets; + int count = 0; + + if (argc == 1) + { + int num = strtoul(args[0], NULL, 0); + + while (target) + { + count++; + target = target->next; + } + + if (num < count) + cmd_ctx->current_target = num; + else + command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count); + + return ERROR_OK; + } + + while (target) + { + command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]); + target = target->next; + } + + return ERROR_OK; +} + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + int found = 0; + + if (argc < 3) + { + ERROR("target command requires at least three arguments: "); + exit(-1); + } + + /* search for the specified target */ + if (args[0] && (args[0][0] != 0)) + { + for (i = 0; target_types[i]; i++) + { + if (strcmp(args[0], target_types[i]->name) == 0) + { + target_t **last_target_p = &targets; + + /* register target specific commands */ + if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) + { + ERROR("couldn't register '%s' commands", args[0]); + exit(-1); + } + + if (*last_target_p) + { + while ((*last_target_p)->next) + last_target_p = &((*last_target_p)->next); + last_target_p = &((*last_target_p)->next); + } + + *last_target_p = malloc(sizeof(target_t)); + + (*last_target_p)->type = target_types[i]; + + if (strcmp(args[1], "big") == 0) + (*last_target_p)->endianness = TARGET_BIG_ENDIAN; + else if (strcmp(args[1], "little") == 0) + (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; + else + { + ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); + exit(-1); + } + + /* what to do on a target reset */ + if (strcmp(args[2], "reset_halt") == 0) + (*last_target_p)->reset_mode = RESET_HALT; + else if (strcmp(args[2], "reset_run") == 0) + (*last_target_p)->reset_mode = RESET_RUN; + else if (strcmp(args[2], "reset_init") == 0) + (*last_target_p)->reset_mode = RESET_INIT; + else if (strcmp(args[2], "run_and_halt") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_HALT; + else if (strcmp(args[2], "run_and_init") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_INIT; + else + { + ERROR("unknown target startup mode %s", args[2]); + exit(-1); + } + (*last_target_p)->run_and_halt_time = 1000; /* default 1s */ + + (*last_target_p)->reset_script = NULL; + (*last_target_p)->post_halt_script = NULL; + (*last_target_p)->pre_resume_script = NULL; + (*last_target_p)->gdb_program_script = NULL; + + (*last_target_p)->working_area = 0x0; + (*last_target_p)->working_area_size = 0x0; + (*last_target_p)->working_areas = NULL; + (*last_target_p)->backup_working_area = 0; + + (*last_target_p)->state = TARGET_UNKNOWN; + (*last_target_p)->reg_cache = NULL; + (*last_target_p)->breakpoints = NULL; + (*last_target_p)->watchpoints = NULL; + (*last_target_p)->next = NULL; + (*last_target_p)->arch_info = NULL; + + /* initialize trace information */ + (*last_target_p)->trace_info = malloc(sizeof(trace_t)); + (*last_target_p)->trace_info->num_trace_points = 0; + (*last_target_p)->trace_info->trace_points_size = 0; + (*last_target_p)->trace_info->trace_points = NULL; + (*last_target_p)->trace_info->trace_history_size = 0; + (*last_target_p)->trace_info->trace_history = NULL; + (*last_target_p)->trace_info->trace_history_pos = 0; + (*last_target_p)->trace_info->trace_history_overflowed = 0; + + (*last_target_p)->dbgmsg = NULL; + (*last_target_p)->dbg_msg_enabled = 0; + + (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); + + found = 1; + break; + } + } + } + + /* no matching target found */ + if (!found) + { + ERROR("target '%s' not found", args[0]); + exit(-1); + } + + return ERROR_OK; +} + +/* usage: target_script */ +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 3) + { + ERROR("incomplete target_script command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (strcmp(args[1], "reset") == 0) + { + if (target->reset_script) + free(target->reset_script); + target->reset_script = strdup(args[2]); + } + else if (strcmp(args[1], "post_halt") == 0) + { + if (target->post_halt_script) + free(target->post_halt_script); + target->post_halt_script = strdup(args[2]); + } + else if (strcmp(args[1], "pre_resume") == 0) + { + if (target->pre_resume_script) + free(target->pre_resume_script); + target->pre_resume_script = strdup(args[2]); + } + else if (strcmp(args[1], "gdb_program_config") == 0) + { + if (target->gdb_program_script) + free(target->gdb_program_script); + target->gdb_program_script = strdup(args[2]); + } + else + { + ERROR("unknown event type: '%s", args[1]); + exit(-1); + } + + return ERROR_OK; +} + +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 2) + { + ERROR("incomplete run_and_halt_time command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + target->run_and_halt_time = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} + +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if ((argc < 4) || (argc > 5)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + target_free_all_working_areas(target); + + target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0); + if (argc == 5) + { + target->working_area_virt = strtoul(args[4], NULL, 0); + } + target->working_area_size = strtoul(args[2], NULL, 0); + + if (strcmp(args[3], "backup") == 0) + { + target->backup_working_area = 1; + } + else if (strcmp(args[3], "nobackup") == 0) + { + target->backup_working_area = 0; + } + else + { + ERROR("unrecognized argument (%s)", args[3]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + + +/* process target state changes */ +int handle_target(void *priv) +{ + int retval; + target_t *target = targets; + + while (target) + { + /* only poll if target isn't already halted */ + if (target->state != TARGET_HALTED) + { + if (target_continous_poll) + if ((retval = target->type->poll(target)) != ERROR_OK) + { + ERROR("couldn't poll target(%d). It's due for a reset.", retval); + } + } + + target = target->next; + } + + return ERROR_OK; +} + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + reg_t *reg = NULL; + int count = 0; + char *value; + + DEBUG("-"); + + target = get_current_target(cmd_ctx); + + /* list all available registers for the current target */ + if (argc == 0) + { + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + value = buf_to_str(cache->reg_list[i].value, cache->reg_list[i].size, 16); + command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid); + free(value); + } + cache = cache->next; + } + + return ERROR_OK; + } + + /* access a single register by its ordinal number */ + if ((args[0][0] >= '0') && (args[0][0] <= '9')) + { + int num = strtoul(args[0], NULL, 0); + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + if (count++ == num) + { + reg = &cache->reg_list[i]; + break; + } + } + if (reg) + break; + cache = cache->next; + } + + if (!reg) + { + command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); + return ERROR_OK; + } + } else /* access a single register by its name */ + { + reg = register_get_by_name(target->reg_cache, args[0], 1); + + if (!reg) + { + command_print(cmd_ctx, "register %s not found in current target", args[0]); + return ERROR_OK; + } + } + + /* display a register */ + if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9')))) + { + if ((argc == 2) && (strcmp(args[1], "force") == 0)) + reg->valid = 0; + + if (reg->valid == 0) + { + reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + arch_type->get(reg); + } + value = buf_to_str(reg->value, reg->size, 16); + command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); + free(value); + return ERROR_OK; + } + + /* set register value */ + if (argc == 2) + { + u8 *buf = malloc(CEIL(reg->size, 8)); + str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0); + + reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + + arch_type->set(reg, buf); + + value = buf_to_str(reg->value, reg->size, 16); + command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); + free(value); + + free(buf); + + return ERROR_OK; + } + + command_print(cmd_ctx, "usage: reg <#|name> [value]"); + + return ERROR_OK; +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms); + +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + target->type->poll(target); + target_arch_state(target); + } + else + { + if (strcmp(args[0], "on") == 0) + { + target_continous_poll = 1; + } + else if (strcmp(args[0], "off") == 0) + { + target_continous_poll = 0; + } + else + { + command_print(cmd_ctx, "arg is \"on\" or \"off\""); + } + } + + + return ERROR_OK; +} + +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int ms = 5000; + + if (argc > 0) + { + char *end; + + ms = strtoul(args[0], &end, 0) * 1000; + if (*end) + { + command_print(cmd_ctx, "usage: %s [seconds]", cmd); + return ERROR_OK; + } + } + + return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms); +} + +static void target_process_events(struct command_context_s *cmd_ctx) +{ + target_t *target = get_current_target(cmd_ctx); + target->type->poll(target); + target_call_timer_callbacks(); +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms) +{ + int retval; + struct timeval timeout, now; + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 0, ms * 1000); + + target_t *target = get_current_target(cmd_ctx); + for (;;) + { + if ((retval=target->type->poll(target))!=ERROR_OK) + return retval; + target_call_timer_callbacks(); + if (target->state == state) + { + break; + } + command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]); + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]); + ERROR("timed out while waiting for target %s", target_state_strings[state]); + break; + } + } + + return ERROR_OK; +} + +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + command_print(cmd_ctx, "requesting target halt..."); + + if ((retval = target->type->halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_ALREADY_HALTED: + command_print(cmd_ctx, "target already halted"); + break; + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + return retval; + default: + command_print(cmd_ctx, "unknown error... shutting down"); + return retval; + } + } + + return handle_wait_halt_command(cmd_ctx, cmd, args, argc); +} + +/* what to do on daemon startup */ +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "attach") == 0) + { + startup_mode = DAEMON_ATTACH; + return ERROR_OK; + } + else if (strcmp(args[0], "reset") == 0) + { + startup_mode = DAEMON_RESET; + return ERROR_OK; + } + } + + WARNING("invalid daemon_startup configuration directive: %s", args[0]); + return ERROR_OK; + +} + +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + command_print(cmd_ctx, "requesting target halt and executing a soft reset"); + + if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + exit(-1); + default: + command_print(cmd_ctx, "unknown error... shutting down"); + exit(-1); + } + } + + return ERROR_OK; +} + +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + enum target_reset_mode reset_mode = target->reset_mode; + enum target_reset_mode save = target->reset_mode; + + DEBUG("-"); + + if (argc >= 1) + { + if (strcmp("run", args[0]) == 0) + reset_mode = RESET_RUN; + else if (strcmp("halt", args[0]) == 0) + reset_mode = RESET_HALT; + else if (strcmp("init", args[0]) == 0) + reset_mode = RESET_INIT; + else if (strcmp("run_and_halt", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_HALT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else if (strcmp("run_and_init", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_INIT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else + { + command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]"); + return ERROR_OK; + } + } + + /* temporarily modify mode of current reset target */ + target->reset_mode = reset_mode; + + /* reset *all* targets */ + target_process_reset(cmd_ctx); + + /* Restore default reset mode for this target */ + target->reset_mode = save; + + return ERROR_OK; +} + +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ + else if (argc == 1) + retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target_process_events(cmd_ctx); + + target_arch_state(target); + + return retval; +} + +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + if (argc == 0) + target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */ + + if (argc == 1) + target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */ + + return ERROR_OK; +} + +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + const int line_bytecnt = 32; + int count = 1; + int size = 4; + u32 address = 0; + int line_modulo; + int i; + + char output[128]; + int output_len; + + int retval; + + u8 *buffer; + target_t *target = get_current_target(cmd_ctx); + + 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; line_modulo = line_bytecnt / 4; + break; + case 'h': + size = 2; line_modulo = line_bytecnt / 2; + break; + case 'b': + size = 1; line_modulo = line_bytecnt / 1; + break; + default: + return ERROR_OK; + } + + buffer = calloc(count, size); + retval = target->type->read_memory(target, address, size, count, buffer); + if (retval != 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"); + break; + } + return ERROR_OK; + } + + output_len = 0; + + for (i = 0; i < count; i++) + { + if (i%line_modulo == 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 ", target_buffer_get_u32(target, &buffer[i*4])); + break; + case 2: + output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2])); + break; + case 1: + output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]); + break; + } + + if ((i%line_modulo == line_modulo-1) || (i == count - 1)) + { + command_print(cmd_ctx, output); + output_len = 0; + } + } + + free(buffer); + + return ERROR_OK; +} + +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u32 address = 0; + u32 value = 0; + int retval; + target_t *target = get_current_target(cmd_ctx); + u8 value_buf[4]; + + if (argc < 2) + return ERROR_OK; + + address = strtoul(args[0], NULL, 0); + value = strtoul(args[1], NULL, 0); + + switch (cmd[2]) + { + case 'w': + target_buffer_set_u32(target, value_buf, value); + retval = target->type->write_memory(target, address, 4, 1, value_buf); + break; + case 'h': + target_buffer_set_u16(target, value_buf, value); + retval = target->type->write_memory(target, address, 2, 1, value_buf); + break; + case 'b': + value_buf[0] = value; + retval = target->type->write_memory(target, address, 1, 1, value_buf); + 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"); + break; + } + + return ERROR_OK; + +} + +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: load_image [address] [type]"); + return ERROR_OK; + } + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + } + + image.start_address_set = 0; + + duration_start_measure(&duration); + + if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "load_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, download aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); + image_size += buf_cnt; + command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address); + + free(buffer); + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; + +} + +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t fileio; + + u32 address; + u32 size; + u8 buffer[560]; + int retval; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc != 3) + { + command_print(cmd_ctx, "usage: dump_image
"); + return ERROR_OK; + } + + address = strtoul(args[1], NULL, 0); + size = strtoul(args[2], NULL, 0); + + if ((address & 3) || (size & 3)) + { + command_print(cmd_ctx, "only 32-bit aligned address and size are supported"); + return ERROR_OK; + } + + if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); + return ERROR_OK; + } + + duration_start_measure(&duration); + + while (size > 0) + { + u32 size_written; + u32 this_run_size = (size > 560) ? 560 : size; + + retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer); + if (retval != ERROR_OK) + { + command_print(cmd_ctx, "Reading memory failed %d", retval); + break; + } + + fileio_write(&fileio, this_run_size, buffer, &size_written); + + size -= this_run_size; + address += this_run_size; + } + + fileio_close(&fileio); + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); + free(duration_text); + + return ERROR_OK; +} + +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + u32 checksum = 0; + u32 mem_checksum = 0; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: verify_image [offset] [type]"); + return ERROR_OK; + } + + if (!target) + { + ERROR("no target selected"); + return ERROR_OK; + } + + duration_start_measure(&duration); + + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + image.base_address = 0x0; + } + + image.start_address_set = 0; + + if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "verify_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + /* calculate checksum of image */ + image_calculate_checksum( buffer, buf_cnt, &checksum ); + + retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); + + if( retval != ERROR_OK ) + { + command_print(cmd_ctx, "could not calculate checksum, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + if( checksum != mem_checksum ) + { + /* failed crc checksum, fall back to a binary compare */ + u8 *data; + + command_print(cmd_ctx, "checksum mismatch - attempting binary compare"); + + data = (u8*)malloc(buf_cnt); + + /* Can we use 32bit word accesses? */ + int size = 1; + int count = buf_cnt; + if ((count % 4) == 0) + { + size *= 4; + count /= 4; + } + retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data); + + if (retval == ERROR_OK) + { + int t; + for (t = 0; t < buf_cnt; t++) + { + if (data[t] != buffer[t]) + { + command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]); + free(data); + free(buffer); + image_close(&image); + return ERROR_OK; + } + } + } + + free(data); + } + + free(buffer); + image_size += buf_cnt; + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; +} + +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + breakpoint_t *breakpoint = target->breakpoints; + + while (breakpoint) + { + if (breakpoint->type == BKPT_SOFT) + { + char* buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); + command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); + free(buf); + } + else + { + command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); + } + breakpoint = breakpoint->next; + } + } + else if (argc >= 2) + { + int hw = BKPT_SOFT; + u32 length = 0; + + length = strtoul(args[1], NULL, 0); + + if (argc >= 3) + if (strcmp(args[2], "hw") == 0) + hw = BKPT_HARD; + + if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set breakpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more breakpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, breakpoint not set"); + break; + } + } + else + { + command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0)); + } + } + else + { + command_print(cmd_ctx, "usage: bp
['hw']"); + } + + return ERROR_OK; +} + +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + breakpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + if (argc == 0) + { + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); + watchpoint = watchpoint->next; + } + } + else if (argc >= 2) + { + enum watchpoint_rw type = WPT_ACCESS; + u32 data_value = 0x0; + u32 data_mask = 0xffffffff; + + if (argc >= 3) + { + switch(args[2][0]) + { + case 'r': + type = WPT_READ; + break; + case 'w': + type = WPT_WRITE; + break; + case 'a': + type = WPT_ACCESS; + break; + default: + command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); + return ERROR_OK; + } + } + if (argc >= 4) + { + data_value = strtoul(args[3], NULL, 0); + } + if (argc >= 5) + { + data_mask = strtoul(args[4], NULL, 0); + } + + if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0), + strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set watchpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more watchpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, watchpoint not set"); + break; + } + } + } + else + { + command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); + } + + return ERROR_OK; +} + +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + watchpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + u32 va; + u32 pa; + + if (argc != 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + va = strtoul(args[0], NULL, 0); + + retval = target->type->virt2phys(target, va, &pa); + if (retval == ERROR_OK) + { + command_print(cmd_ctx, "Physical address 0x%08x", pa); + } + else + { + /* lower levels will have logged a detailed error which is + * forwarded to telnet/GDB session. + */ + } + return retval; +} diff --git a/src/target/xscale.c b/src/target/xscale.c index 11ae5eed..b156e227 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1,3799 +1,3799 @@ -/*************************************************************************** - * Copyright (C) 2006, 2007 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "xscale.h" - -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "arm_simulator.h" -#include "arm_disassembler.h" -#include "log.h" -#include "jtag.h" -#include "binarybuffer.h" -#include "time_support.h" -#include "breakpoints.h" -#include "fileio.h" - -#include -#include - -#include -#include -#include - - -/* cli handling */ -int xscale_register_commands(struct command_context_s *cmd_ctx); - -/* forward declarations */ -int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int xscale_quit(); - -int xscale_arch_state(struct target_s *target); -int xscale_poll(target_t *target); -int xscale_halt(target_t *target); -int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); -int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints); -int xscale_debug_entry(target_t *target); -int xscale_restore_context(target_t *target); - -int xscale_assert_reset(target_t *target); -int xscale_deassert_reset(target_t *target); -int xscale_soft_reset_halt(struct target_s *target); -int xscale_prepare_reset_halt(struct target_s *target); - -int xscale_set_reg_u32(reg_t *reg, u32 value); - -int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode); -int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value); - -int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer); -int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); - -int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); -int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); -void xscale_enable_watchpoints(struct target_s *target); -void xscale_enable_breakpoints(struct target_s *target); -static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical); -static int xscale_mmu(struct target_s *target, int *enabled); - -int xscale_read_trace(target_t *target); - -target_type_t xscale_target = -{ - .name = "xscale", - - .poll = xscale_poll, - .arch_state = xscale_arch_state, - - .target_request_data = NULL, - - .halt = xscale_halt, - .resume = xscale_resume, - .step = xscale_step, - - .assert_reset = xscale_assert_reset, - .deassert_reset = xscale_deassert_reset, - .soft_reset_halt = xscale_soft_reset_halt, - .prepare_reset_halt = xscale_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = xscale_read_memory, - .write_memory = xscale_write_memory, - .bulk_write_memory = xscale_bulk_write_memory, - .checksum_memory = xscale_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = xscale_add_breakpoint, - .remove_breakpoint = xscale_remove_breakpoint, - .add_watchpoint = xscale_add_watchpoint, - .remove_watchpoint = xscale_remove_watchpoint, - - .register_commands = xscale_register_commands, - .target_command = xscale_target_command, - .init_target = xscale_init_target, - .quit = xscale_quit, - - .virt2phys = xscale_virt2phys, - .mmu = xscale_mmu -}; - -char* xscale_reg_list[] = -{ - "XSCALE_MAINID", /* 0 */ - "XSCALE_CACHETYPE", - "XSCALE_CTRL", - "XSCALE_AUXCTRL", - "XSCALE_TTB", - "XSCALE_DAC", - "XSCALE_FSR", - "XSCALE_FAR", - "XSCALE_PID", - "XSCALE_CPACCESS", - "XSCALE_IBCR0", /* 10 */ - "XSCALE_IBCR1", - "XSCALE_DBR0", - "XSCALE_DBR1", - "XSCALE_DBCON", - "XSCALE_TBREG", - "XSCALE_CHKPT0", - "XSCALE_CHKPT1", - "XSCALE_DCSR", - "XSCALE_TX", - "XSCALE_RX", /* 20 */ - "XSCALE_TXRXCTRL", -}; - -xscale_reg_t xscale_reg_arch_info[] = -{ - {XSCALE_MAINID, NULL}, - {XSCALE_CACHETYPE, NULL}, - {XSCALE_CTRL, NULL}, - {XSCALE_AUXCTRL, NULL}, - {XSCALE_TTB, NULL}, - {XSCALE_DAC, NULL}, - {XSCALE_FSR, NULL}, - {XSCALE_FAR, NULL}, - {XSCALE_PID, NULL}, - {XSCALE_CPACCESS, NULL}, - {XSCALE_IBCR0, NULL}, - {XSCALE_IBCR1, NULL}, - {XSCALE_DBR0, NULL}, - {XSCALE_DBR1, NULL}, - {XSCALE_DBCON, NULL}, - {XSCALE_TBREG, NULL}, - {XSCALE_CHKPT0, NULL}, - {XSCALE_CHKPT1, NULL}, - {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ - {-1, NULL}, /* TX accessed via JTAG */ - {-1, NULL}, /* RX accessed via JTAG */ - {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ -}; - -int xscale_reg_arch_type = -1; - -int xscale_get_reg(reg_t *reg); -int xscale_set_reg(reg_t *reg, u8 *buf); - -int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("target isn't an XScale target"); - return -1; - } - - if (xscale->common_magic != XSCALE_COMMON_MAGIC) - { - ERROR("target isn't an XScale target"); - return -1; - } - - *armv4_5_p = armv4_5; - *xscale_p = xscale; - - return ERROR_OK; -} - -int xscale_jtag_set_instr(int chain_pos, u32 new_instr) -{ - jtag_device_t *device = jtag_get_device(chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = 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; - jtag_set_check_value(&field, device->expected, device->expected_mask, NULL); - - jtag_add_ir_scan(1, &field, -1); - - free(field.out_value); - } - - return ERROR_OK; -} - -int xscale_jtag_callback(enum jtag_event event, void *priv) -{ - switch (event) - { - case JTAG_TRST_ASSERTED: - break; - case JTAG_TRST_RELEASED: - break; - case JTAG_SRST_ASSERTED: - break; - case JTAG_SRST_RELEASED: - break; - default: - WARNING("unhandled JTAG event"); - } - - return ERROR_OK; -} - -int xscale_read_dcsr(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - scan_field_t fields[3]; - u8 field0 = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x7; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_PD); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - buf_set_u32(&field0, 1, 1, xscale->hold_rst); - buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - 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 = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while reading DCSR"); - return retval; - } - - xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; - xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; - - /* write the register with the value we just read - * on this second pass, only the first bit of field0 is guaranteed to be 0) - */ - field0_check_mask = 0x1; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - fields[1].in_value = NULL; - - jtag_add_end_state(TAP_RTI); - - jtag_add_dr_scan(3, fields, -1); - - return ERROR_OK; -} - -int xscale_receive(target_t *target, u32 *buffer, int num_words) -{ - int retval = ERROR_OK; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - enum tap_state path[3]; - scan_field_t fields[3]; - - u8 *field0 = malloc(num_words * 1); - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u32 *field1 = malloc(num_words * 4); - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - int words_done = 0; - int words_scheduled = 0; - - int i; - - path[0] = TAP_SDS; - path[1] = TAP_CD; - path[2] = TAP_SD; - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - /* fields[0].in_value = field0; */ - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->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_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); - jtag_add_runtest(1, -1); - - /* repeat until all words have been collected */ - int attempts = 0; - while (words_done < num_words) - { - /* schedule reads */ - words_scheduled = 0; - for (i = words_done; i < num_words; i++) - { - fields[0].in_value = &field0[i]; - fields[1].in_handler = buf_to_u32_handler; - fields[1].in_handler_priv = (u8*)&field1[i]; - - jtag_add_pathmove(3, path); - jtag_add_dr_scan(3, fields, TAP_RTI); - words_scheduled++; - } - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while receiving data from debug handler"); - break; - } - - /* examine results */ - for (i = words_done; i < num_words; i++) - { - if (!(field0[0] & 1)) - { - /* move backwards if necessary */ - int j; - for (j = i; j < num_words - 1; j++) - { - field0[j] = field0[j+1]; - field1[j] = field1[j+1]; - } - words_scheduled--; - } - } - if (words_scheduled == 0) - { - if (attempts++ == 1000) - { - ERROR("Failed to receiving data from debug handler after 1000 attempts"); - retval = ERROR_JTAG_QUEUE_FAILED; - break; - } - } - - words_done += words_scheduled; - } - - for (i = 0; i < num_words; i++) - *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32); - - free(field1); - - return retval; -} - -int xscale_read_tx(target_t *target, int consume) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - enum tap_state path[3]; - enum tap_state noconsume_path[9]; - - int retval; - struct timeval timeout, now; - - scan_field_t fields[3]; - u8 field0_in = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); - - path[0] = TAP_SDS; - path[1] = TAP_CD; - path[2] = TAP_SD; - - noconsume_path[0] = TAP_SDS; - noconsume_path[1] = TAP_CD; - noconsume_path[2] = TAP_E1D; - noconsume_path[3] = TAP_PD; - noconsume_path[4] = TAP_E2D; - noconsume_path[5] = TAP_UD; - noconsume_path[6] = TAP_SDS; - noconsume_path[7] = TAP_CD; - noconsume_path[8] = TAP_SD; - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = &field0_in; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; - 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 = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - - do - { - /* if we want to consume the register content (i.e. clear TX_READY), - * we have to go straight from Capture-DR to Shift-DR - * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR - */ - if (consume) - jtag_add_pathmove(3, path); - else - jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path); - - jtag_add_dr_scan(3, fields, TAP_RTI); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while reading TX"); - return ERROR_TARGET_TIMEOUT; - } - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) - { - ERROR("time out reading TX register"); - return ERROR_TARGET_TIMEOUT; - } - } while ((!(field0_in & 1)) && consume); - - if (!(field0_in & 1)) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - - return ERROR_OK; -} - -int xscale_write_rx(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - struct timeval timeout, now; - - scan_field_t fields[3]; - u8 field0_out = 0x0; - u8 field0_in = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0_out; - fields[0].out_mask = NULL; - fields[0].in_value = &field0_in; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; - 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 = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - - /* poll until rx_read is low */ - DEBUG("polling RX"); - do - { - jtag_add_dr_scan(3, fields, TAP_RTI); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing RX"); - return retval; - } - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) - { - ERROR("time out writing RX register"); - return ERROR_TARGET_TIMEOUT; - } - } while (field0_in & 1); - - /* set rx_valid */ - field2 = 0x1; - jtag_add_dr_scan(3, fields, TAP_RTI); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing RX"); - return retval; - } - - return ERROR_OK; -} - -/* send count elements of size byte to the debug handler */ -int xscale_send(target_t *target, u8 *buffer, int count, int size) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - int done_count = 0; - u8 output[4] = {0, 0, 0, 0}; - - scan_field_t fields[3]; - u8 field0_out = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2 = 0x1; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0_out; - fields[0].out_mask = NULL; - fields[0].in_handler = NULL; - if (!xscale->fast_memory_access) - { - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - } - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = output; - 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 = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_handler = NULL; - if (!xscale->fast_memory_access) - { - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - } - - if (size==4) - { - int endianness = target->endianness; - while (done_count++ < count) - { - if (endianness == TARGET_LITTLE_ENDIAN) - { - output[0]=buffer[0]; - output[1]=buffer[1]; - output[2]=buffer[2]; - output[3]=buffer[3]; - } else - { - output[0]=buffer[3]; - output[1]=buffer[2]; - output[2]=buffer[1]; - output[3]=buffer[0]; - } - jtag_add_dr_scan(3, fields, TAP_RTI); - buffer += size; - } - - } else - { - while (done_count++ < count) - { - /* extract sized element from target-endian buffer, and put it - * into little-endian output buffer - */ - switch (size) - { - case 2: - buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer)); - break; - case 1: - output[0] = *buffer; - break; - default: - ERROR("BUG: size neither 4, 2 nor 1"); - exit(-1); - } - - jtag_add_dr_scan(3, fields, TAP_RTI); - buffer += size; - } - - } - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while sending data to debug handler"); - return retval; - } - - return ERROR_OK; -} - -int xscale_send_u32(target_t *target, u32 value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); - return xscale_write_rx(target); -} - -int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - scan_field_t fields[3]; - u8 field0 = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x7; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - if (hold_rst != -1) - xscale->hold_rst = hold_rst; - - if (ext_dbg_brk != -1) - xscale->external_debug_break = ext_dbg_brk; - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - buf_set_u32(&field0, 1, 1, xscale->hold_rst); - buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - 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 = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing DCSR"); - return retval; - } - - xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; - xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; - - return ERROR_OK; -} - -/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ -unsigned int parity (unsigned int v) -{ - unsigned int ov = v; - v ^= v >> 16; - v ^= v >> 8; - v ^= v >> 4; - v &= 0xf; - DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); - return (0x6996 >> v) & 1; -} - -int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8]) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 packet[4]; - u8 cmd; - int word; - - scan_field_t fields[2]; - - DEBUG("loading miniIC at 0x%8.8x", va); - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ - - /* CMD is b010 for Main IC and b011 for Mini IC */ - if (mini) - buf_set_u32(&cmd, 0, 3, 0x3); - else - buf_set_u32(&cmd, 0, 3, 0x2); - - buf_set_u32(&cmd, 3, 3, 0x0); - - /* virtual address of desired cache line */ - buf_set_u32(packet, 0, 27, va >> 5); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 6; - fields[0].out_value = &cmd; - 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 = xscale->jtag_info.chain_pos; - fields[1].num_bits = 27; - fields[1].out_value = packet; - 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; - - jtag_add_dr_scan(2, fields, -1); - - fields[0].num_bits = 32; - fields[0].out_value = packet; - - fields[1].num_bits = 1; - fields[1].out_value = &cmd; - - for (word = 0; word < 8; word++) - { - buf_set_u32(packet, 0, 32, buffer[word]); - cmd = parity(*((u32*)packet)); - jtag_add_dr_scan(2, fields, -1); - } - - jtag_execute_queue(); - - return ERROR_OK; -} - -int xscale_invalidate_ic_line(target_t *target, u32 va) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 packet[4]; - u8 cmd; - - scan_field_t fields[2]; - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ - - /* CMD for invalidate IC line b000, bits [6:4] b000 */ - buf_set_u32(&cmd, 0, 6, 0x0); - - /* virtual address of desired cache line */ - buf_set_u32(packet, 0, 27, va >> 5); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 6; - fields[0].out_value = &cmd; - 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 = xscale->jtag_info.chain_pos; - fields[1].num_bits = 27; - fields[1].out_value = packet; - 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; - - jtag_add_dr_scan(2, fields, -1); - - return ERROR_OK; -} - -int xscale_update_vectors(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int i; - - u32 low_reset_branch, high_reset_branch; - - for (i = 1; i < 8; i++) - { - /* if there's a static vector specified for this exception, override */ - if (xscale->static_high_vectors_set & (1 << i)) - { - xscale->high_vectors[i] = xscale->static_high_vectors[i]; - } - else - { - if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK) - { - xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - } - } - - for (i = 1; i < 8; i++) - { - if (xscale->static_low_vectors_set & (1 << i)) - { - xscale->low_vectors[i] = xscale->static_low_vectors[i]; - } - else - { - if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK) - { - xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - } - } - - /* calculate branches to debug handler */ - low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; - high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; - - xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); - xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); - - /* invalidate and load exception vectors in mini i-cache */ - xscale_invalidate_ic_line(target, 0x0); - xscale_invalidate_ic_line(target, 0xffff0000); - - xscale_load_ic(target, 1, 0x0, xscale->low_vectors); - xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); - - return ERROR_OK; -} - -int xscale_arch_state(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - char *state[] = - { - "disabled", "enabled" - }; - - char *arch_dbg_reason[] = - { - "", "\n(processor reset)", "\n(trace buffer full)" - }; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("BUG: called for a non-ARMv4/5 target"); - exit(-1); - } - - USER("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" - "%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[xscale->armv4_5_mmu.mmu_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], - arch_dbg_reason[xscale->arch_debug_reason]); - - return ERROR_OK; -} - -int xscale_poll(target_t *target) -{ - int retval=ERROR_OK; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) - { - enum target_state previous_state = target->state; - if ((retval = xscale_read_tx(target, 0)) == ERROR_OK) - { - - /* there's data to read from the tx register, we entered debug state */ - xscale->handler_running = 1; - - target->state = TARGET_HALTED; - - /* process debug entry, fetching current mode regs */ - retval = xscale_debug_entry(target); - } - else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - USER("error while polling TX register, reset CPU"); - /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ - target->state = TARGET_HALTED; - } - - /* debug_entry could have overwritten target state (i.e. immediate resume) - * don't signal event handlers in that case - */ - if (target->state != TARGET_HALTED) - return ERROR_OK; - - /* if target was running, signal that we halted - * otherwise we reentered from debug execution */ - if (previous_state == TARGET_RUNNING) - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - else - target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); - } - return retval; -} - -int xscale_debug_entry(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 pc; - u32 buffer[10]; - int i; - - u32 moe; - - /* clear external dbg break (will be written on next DCSR read) */ - xscale->external_debug_break = 0; - xscale_read_dcsr(target); - - /* get r0, pc, r1 to r7 and cpsr */ - xscale_receive(target, buffer, 10); - - /* move r0 from buffer to register cache */ - buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - DEBUG("r0: 0x%8.8x", buffer[0]); - - /* move pc from buffer to register cache */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - DEBUG("pc: 0x%8.8x", buffer[1]); - - /* move data from buffer to register cache */ - for (i = 1; i <= 7; i++) - { - buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); - armv4_5->core_cache->reg_list[i].dirty = 1; - armv4_5->core_cache->reg_list[i].valid = 1; - DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]); - } - - buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]); - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; - DEBUG("cpsr: 0x%8.8x", buffer[9]); - - armv4_5->core_mode = buffer[9] & 0x1f; - if (armv4_5_mode_to_number(armv4_5->core_mode) == -1) - { - target->state = TARGET_UNKNOWN; - ERROR("cpsr contains invalid mode value - communication failure"); - return ERROR_TARGET_FAILURE; - } - DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]); - - if (buffer[9] & 0x20) - armv4_5->core_state = ARMV4_5_STATE_THUMB; - else - armv4_5->core_state = ARMV4_5_STATE_ARM; - - /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS)) - { - xscale_receive(target, buffer, 8); - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1; - } - else - { - /* r8 to r14, but no spsr */ - xscale_receive(target, buffer, 7); - } - - /* move data from buffer to register cache */ - for (i = 8; i <= 14; i++) - { - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1; - } - - /* examine debug reason */ - xscale_read_dcsr(target); - moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); - - /* stored PC (for calculating fixup) */ - pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - switch (moe) - { - case 0x0: /* Processor reset */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; - pc -= 4; - break; - case 0x1: /* Instruction breakpoint hit */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x2: /* Data breakpoint hit */ - target->debug_reason = DBG_REASON_WATCHPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x3: /* BKPT instruction executed */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x4: /* Ext. debug event */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x5: /* Vector trap occured */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x6: /* Trace buffer full break */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; - pc -= 4; - break; - case 0x7: /* Reserved */ - default: - ERROR("Method of Entry is 'Reserved'"); - exit(-1); - break; - } - - /* apply PC fixup */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); - - /* on the first debug entry, identify cache type */ - if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) - { - u32 cache_type_reg; - - /* read cp15 cache type register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); - cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); - - armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); - } - - /* examine MMU and Cache settings */ - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; - - /* tracing enabled, read collected trace data */ - if (xscale->trace.buffer_enabled) - { - xscale_read_trace(target); - xscale->trace.buffer_fill--; - - /* resume if we're still collecting trace data */ - if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) - && (xscale->trace.buffer_fill > 0)) - { - xscale_resume(target, 1, 0x0, 1, 0); - } - else - { - xscale->trace.buffer_enabled = 0; - } - } - - return ERROR_OK; -} - -int xscale_halt(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - if (target->state == TARGET_HALTED) - { - WARNING("target was already halted"); - return ERROR_TARGET_ALREADY_HALTED; - } - else if (target->state == TARGET_UNKNOWN) - { - /* this must not happen for a xscale target */ - ERROR("target was in unknown state when halt was requested"); - return ERROR_TARGET_INVALID; - } - else if (target->state == TARGET_RESET) - { - DEBUG("target->state == TARGET_RESET"); - } - else - { - /* assert external dbg break */ - xscale->external_debug_break = 1; - xscale_read_dcsr(target); - - target->debug_reason = DBG_REASON_DBGRQ; - } - - return ERROR_OK; -} - -int xscale_enable_single_step(struct target_s *target, u32 next_pc) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; - - if (xscale->ibcr0_used) - { - breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); - - if (ibcr0_bp) - { - xscale_unset_breakpoint(target, ibcr0_bp); - } - else - { - ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); - exit(-1); - } - } - - xscale_set_reg_u32(ibcr0, next_pc | 0x1); - - return ERROR_OK; -} - -int xscale_disable_single_step(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; - - xscale_set_reg_u32(ibcr0, 0x0); - - return ERROR_OK; -} - -int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - breakpoint_t *breakpoint = target->breakpoints; - - u32 current_pc; - - int retval; - int i; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!debug_execution) - { - target_free_all_working_areas(target); - } - - /* update vector tables */ - xscale_update_vectors(target); - - /* current = 1: continue on current pc, otherwise continue at
*/ - if (!current) - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); - - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - /* if we're at the reset vector, we have to simulate the branch */ - if (current_pc == 0x0) - { - arm_simulate_step(target, NULL); - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - } - - /* the front-end may request us not to handle breakpoints */ - if (handle_breakpoints) - { - if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) - { - u32 next_pc; - - /* there's a breakpoint at the current PC, we have to step over it */ - DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); - xscale_unset_breakpoint(target, breakpoint); - - /* calculate PC of next instruction */ - if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) - { - u32 current_opcode; - target_read_u32(target, current_pc, ¤t_opcode); - ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); - } - - DEBUG("enable single-step"); - xscale_enable_single_step(target, next_pc); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - /* wait for and process debug entry */ - xscale_debug_entry(target); - - DEBUG("disable single-step"); - xscale_disable_single_step(target); - - DEBUG("set breakpoint at 0x%8.8x", breakpoint->address); - xscale_set_breakpoint(target, breakpoint); - } - } - - /* enable any pending breakpoints and watchpoints */ - xscale_enable_breakpoints(target); - xscale_enable_watchpoints(target); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - target->debug_reason = DBG_REASON_NOTHALTED; - - if (!debug_execution) - { - /* registers are now invalid */ - armv4_5_invalidate_core_regs(target); - target->state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - } - else - { - target->state = TARGET_DEBUG_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - } - - DEBUG("target resumed"); - - xscale->handler_running = 1; - - return ERROR_OK; -} - -int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - breakpoint_t *breakpoint = target->breakpoints; - - u32 current_pc, next_pc; - int i; - int retval; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* current = 1: continue on current pc, otherwise continue at
*/ - if (!current) - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); - - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - /* if we're at the reset vector, we have to simulate the step */ - if (current_pc == 0x0) - { - arm_simulate_step(target, NULL); - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - target->debug_reason = DBG_REASON_SINGLESTEP; - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; - } - - /* the front-end may request us not to handle breakpoints */ - if (handle_breakpoints) - if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) - { - xscale_unset_breakpoint(target, breakpoint); - } - - target->debug_reason = DBG_REASON_SINGLESTEP; - - /* calculate PC of next instruction */ - if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) - { - u32 current_opcode; - target_read_u32(target, current_pc, ¤t_opcode); - ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); - } - - DEBUG("enable single-step"); - xscale_enable_single_step(target, next_pc); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - - /* registers are now invalid */ - armv4_5_invalidate_core_regs(target); - - /* wait for and process debug entry */ - xscale_debug_entry(target); - - DEBUG("disable single-step"); - xscale_disable_single_step(target); - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - if (breakpoint) - { - xscale_set_breakpoint(target, breakpoint); - } - - DEBUG("target stepped"); - - return ERROR_OK; - -} - -int xscale_assert_reset(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - /* select DCSR instruction (set endstate to R-T-I to ensure we don't - * end up in T-L-R, which would reset JTAG - */ - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f); - jtag_execute_queue(); - - /* assert reset */ - jtag_add_reset(0, 1); - - /* sleep 1ms, to be sure we fulfill any requirements */ - jtag_add_sleep(1000); - jtag_execute_queue(); - - target->state = TARGET_RESET; - - return ERROR_OK; -} - -int xscale_deassert_reset(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - fileio_t debug_handler; - u32 address; - u32 binary_size; - - u32 buf_cnt; - int i; - int retval; - - breakpoint_t *breakpoint = target->breakpoints; - - DEBUG("-"); - - xscale->ibcr_available = 2; - xscale->ibcr0_used = 0; - xscale->ibcr1_used = 0; - - xscale->dbr_available = 2; - xscale->dbr0_used = 0; - xscale->dbr1_used = 0; - - /* mark all hardware breakpoints as unset */ - while (breakpoint) - { - if (breakpoint->type == BKPT_HARD) - { - breakpoint->set = 0; - } - breakpoint = breakpoint->next; - } - - if (!xscale->handler_installed) - { - /* release SRST */ - jtag_add_reset(0, 0); - - /* wait 300ms; 150 and 100ms were not enough */ - jtag_add_sleep(300*1000); - - jtag_add_runtest(2030, TAP_RTI); - jtag_execute_queue(); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* Load debug handler */ - if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK) - { - ERROR("file open error: %s", debug_handler.error_str); - return ERROR_OK; - } - - if ((binary_size = debug_handler.size) % 4) - { - ERROR("debug_handler.bin: size not a multiple of 4"); - exit(-1); - } - - if (binary_size > 0x800) - { - ERROR("debug_handler.bin: larger than 2kb"); - exit(-1); - } - - binary_size = CEIL(binary_size, 32) * 32; - - address = xscale->handler_address; - while (binary_size > 0) - { - u32 cache_line[8]; - u8 buffer[32]; - - if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("reading debug handler failed: %s", debug_handler.error_str); - } - - for (i = 0; i < buf_cnt; i += 4) - { - /* convert LE buffer to host-endian u32 */ - cache_line[i / 4] = le_to_h_u32(&buffer[i]); - } - - for (; buf_cnt < 32; buf_cnt += 4) - { - cache_line[buf_cnt / 4] = 0xe1a08008; - } - - /* only load addresses other than the reset vectors */ - if ((address % 0x400) != 0x0) - { - xscale_load_ic(target, 1, address, cache_line); - } - - address += buf_cnt; - binary_size -= buf_cnt; - }; - - xscale_load_ic(target, 1, 0x0, xscale->low_vectors); - xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); - - jtag_add_runtest(30, TAP_RTI); - - jtag_add_sleep(100000); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* clear Hold reset to let the target run (should enter debug handler) */ - xscale_write_dcsr(target, 0, 1); - target->state = TARGET_RUNNING; - - if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT)) - { - jtag_add_sleep(10000); - - /* we should have entered debug now */ - xscale_debug_entry(target); - target->state = TARGET_HALTED; - - /* resume the target */ - xscale_resume(target, 1, 0x0, 1, 0); - } - - fileio_close(&debug_handler); - } - else - { - jtag_add_reset(0, 0); - } - - - return ERROR_OK; -} - -int xscale_soft_reset_halt(struct target_s *target) -{ - - return ERROR_OK; -} - -int xscale_prepare_reset_halt(struct target_s *target) -{ - /* nothing to be done for reset_halt on XScale targets - * we always halt after a reset to upload the debug handler - */ - return ERROR_OK; -} - -int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode) -{ - - return ERROR_OK; -} - -int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value) -{ - - return ERROR_OK; -} - -int xscale_full_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - - u32 *buffer; - - int i, j; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - buffer = malloc(4 * 8); - - /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) - * we can't enter User mode on an XScale (unpredictable), - * but User shares registers with SYS - */ - for(i = 1; i < 7; i++) - { - int valid = 1; - - /* check if there are invalid registers in the current mode - */ - for (j = 0; j <= 16; j++) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0) - valid = 0; - } - - if (!valid) - { - u32 tmp_cpsr; - - /* request banked registers */ - xscale_send_u32(target, 0x0); - - tmp_cpsr = 0x0; - tmp_cpsr |= armv4_5_number_to_mode(i); - tmp_cpsr |= 0xc0; /* I/F bits */ - - /* send CPSR for desired mode */ - xscale_send_u32(target, tmp_cpsr); - - /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - xscale_receive(target, buffer, 8); - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; - } - else - { - xscale_receive(target, buffer, 7); - } - - /* move data from buffer to register cache */ - for (j = 8; j <= 14; j++) - { - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1; - } - } - } - - free(buffer); - - return ERROR_OK; -} - -int xscale_restore_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - - int i, j; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) - * we can't enter User mode on an XScale (unpredictable), - * but User shares registers with SYS - */ - for(i = 1; i < 7; i++) - { - int dirty = 0; - - /* check if there are invalid registers in the current mode - */ - for (j = 8; j <= 14; j++) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1) - dirty = 1; - } - - /* if not USR/SYS, check if the SPSR needs to be written */ - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1) - dirty = 1; - } - - if (dirty) - { - u32 tmp_cpsr; - - /* send banked registers */ - xscale_send_u32(target, 0x1); - - tmp_cpsr = 0x0; - tmp_cpsr |= armv4_5_number_to_mode(i); - tmp_cpsr |= 0xc0; /* I/F bits */ - - /* send CPSR for desired mode */ - xscale_send_u32(target, tmp_cpsr); - - /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - for (j = 8; j <= 14; j++) - { - xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32)); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; - } - - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32)); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; - } - } - } - - return ERROR_OK; -} - -int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 *buf32; - int i; - - DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; - - if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) - return ERROR_TARGET_UNALIGNED_ACCESS; - - /* send memory read request (command 0x1n, n: access size) */ - xscale_send_u32(target, 0x10 | size); - - /* send base address for read request */ - xscale_send_u32(target, address); - - /* send number of requested data words */ - xscale_send_u32(target, count); - - /* receive data from target (count times 32-bit words in host endianness) */ - buf32 = malloc(4 * count); - xscale_receive(target, buf32, count); - - /* extract data from host-endian buffer into byte stream */ - for (i = 0; i < count; i++) - { - switch (size) - { - case 4: - target_buffer_set_u32(target, buffer, buf32[i]); - buffer += 4; - break; - case 2: - target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); - buffer += 2; - break; - case 1: - *buffer++ = buf32[i] & 0xff; - break; - default: - ERROR("should never get here"); - exit(-1); - } - } - - free(buf32); - - /* examine DCSR, to see if Sticky Abort (SA) got set */ - xscale_read_dcsr(target); - if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) - { - /* clear SA bit */ - xscale_send_u32(target, 0x60); - - return ERROR_TARGET_DATA_ABORT; - } - - return ERROR_OK; -} - -int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; - - if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) - return ERROR_TARGET_UNALIGNED_ACCESS; - - /* send memory write request (command 0x2n, n: access size) */ - xscale_send_u32(target, 0x20 | size); - - /* send base address for read request */ - xscale_send_u32(target, address); - - /* send number of requested data words to be written*/ - xscale_send_u32(target, count); - - /* extract data from host-endian buffer into byte stream */ -#if 0 - for (i = 0; i < count; i++) - { - switch (size) - { - case 4: - value = target_buffer_get_u32(target, buffer); - xscale_send_u32(target, value); - buffer += 4; - break; - case 2: - value = target_buffer_get_u16(target, buffer); - xscale_send_u32(target, value); - buffer += 2; - break; - case 1: - value = *buffer; - xscale_send_u32(target, value); - buffer += 1; - break; - default: - ERROR("should never get here"); - exit(-1); - } - } -#endif - xscale_send(target, buffer, count, size); - - /* examine DCSR, to see if Sticky Abort (SA) got set */ - xscale_read_dcsr(target); - if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) - { - /* clear SA bit */ - xscale_send_u32(target, 0x60); - - return ERROR_TARGET_DATA_ABORT; - } - - return ERROR_OK; -} - -int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer) -{ - return xscale_write_memory(target, address, 4, count, buffer); -} - -int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) -{ - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; -} - -u32 xscale_get_ttb(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 ttb; - - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); - ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); - - return ttb; -} - -void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - - if (mmu) - cp15_control &= ~0x1U; - - if (d_u_cache) - { - /* clean DCache */ - xscale_send_u32(target, 0x50); - xscale_send_u32(target, xscale->cache_clean_address); - - /* invalidate DCache */ - xscale_send_u32(target, 0x51); - - cp15_control &= ~0x4U; - } - - if (i_cache) - { - /* invalidate ICache */ - xscale_send_u32(target, 0x52); - cp15_control &= ~0x1000U; - } - - /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); -} - -void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache) - cp15_control |= 0x4U; - - if (i_cache) - cp15_control |= 0x1000U; - - /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); -} - -int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->force_hw_bkpts) - breakpoint->type = BKPT_HARD; - - if (breakpoint->set) - { - WARNING("breakpoint already set"); - return ERROR_OK; - } - - if (breakpoint->type == BKPT_HARD) - { - u32 value = breakpoint->address | 1; - if (!xscale->ibcr0_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); - xscale->ibcr0_used = 1; - breakpoint->set = 1; /* breakpoint set on first breakpoint register */ - } - else if (!xscale->ibcr1_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); - xscale->ibcr1_used = 1; - breakpoint->set = 2; /* breakpoint set on second breakpoint register */ - } - else - { - ERROR("BUG: no hardware comparator available"); - return ERROR_OK; - } - } - else if (breakpoint->type == BKPT_SOFT) - { - if (breakpoint->length == 4) - { - /* keep the original instruction in target endianness */ - target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); - /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ - target_write_u32(target, breakpoint->address, xscale->arm_bkpt); - } - else - { - /* keep the original instruction in target endianness */ - target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); - /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ - target_write_u32(target, breakpoint->address, xscale->thumb_bkpt); - } - breakpoint->set = 1; - } - - return ERROR_OK; - -} - -int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->force_hw_bkpts) - { - DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address); - breakpoint->type = BKPT_HARD; - } - - if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) - { - INFO("no breakpoint unit available for hardware breakpoint"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - else - { - xscale->ibcr_available--; - } - - if ((breakpoint->length != 2) && (breakpoint->length != 4)) - { - INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - return ERROR_OK; -} - -int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!breakpoint->set) - { - WARNING("breakpoint not set"); - return ERROR_OK; - } - - if (breakpoint->type == BKPT_HARD) - { - if (breakpoint->set == 1) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); - xscale->ibcr0_used = 0; - } - else if (breakpoint->set == 2) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); - xscale->ibcr1_used = 0; - } - breakpoint->set = 0; - } - else - { - /* restore original instruction (kept in target endianness) */ - if (breakpoint->length == 4) - { - target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); - } - else - { - target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); - } - breakpoint->set = 0; - } - - return ERROR_OK; -} - -int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (breakpoint->set) - { - xscale_unset_breakpoint(target, breakpoint); - } - - if (breakpoint->type == BKPT_HARD) - xscale->ibcr_available++; - - return ERROR_OK; -} - -int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 enable = 0; - reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; - u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - xscale_get_reg(dbcon); - - switch (watchpoint->rw) - { - case WPT_READ: - enable = 0x3; - break; - case WPT_ACCESS: - enable = 0x2; - break; - case WPT_WRITE: - enable = 0x1; - break; - default: - ERROR("BUG: watchpoint->rw neither read, write nor access"); - } - - if (!xscale->dbr0_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); - dbcon_value |= enable; - xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 1; - xscale->dbr0_used = 1; - } - else if (!xscale->dbr1_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); - dbcon_value |= enable << 2; - xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 2; - xscale->dbr1_used = 1; - } - else - { - ERROR("BUG: no hardware comparator available"); - return ERROR_OK; - } - - return ERROR_OK; -} - -int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->dbr_available < 1) - { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) - { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - xscale->dbr_available--; - - return ERROR_OK; -} - -int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; - u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!watchpoint->set) - { - WARNING("breakpoint not set"); - return ERROR_OK; - } - - if (watchpoint->set == 1) - { - dbcon_value &= ~0x3; - xscale_set_reg_u32(dbcon, dbcon_value); - xscale->dbr0_used = 0; - } - else if (watchpoint->set == 2) - { - dbcon_value &= ~0xc; - xscale_set_reg_u32(dbcon, dbcon_value); - xscale->dbr1_used = 0; - } - watchpoint->set = 0; - - return ERROR_OK; -} - -int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (watchpoint->set) - { - xscale_unset_watchpoint(target, watchpoint); - } - - xscale->dbr_available++; - - return ERROR_OK; -} - -void xscale_enable_watchpoints(struct target_s *target) -{ - watchpoint_t *watchpoint = target->watchpoints; - - while (watchpoint) - { - if (watchpoint->set == 0) - xscale_set_watchpoint(target, watchpoint); - watchpoint = watchpoint->next; - } -} - -void xscale_enable_breakpoints(struct target_s *target) -{ - breakpoint_t *breakpoint = target->breakpoints; - - /* set any pending breakpoints */ - while (breakpoint) - { - if (breakpoint->set == 0) - xscale_set_breakpoint(target, breakpoint); - breakpoint = breakpoint->next; - } -} - -int xscale_get_reg(reg_t *reg) -{ - xscale_reg_t *arch_info = reg->arch_info; - target_t *target = arch_info->target; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - /* DCSR, TX and RX are accessible via JTAG */ - if (strcmp(reg->name, "XSCALE_DCSR") == 0) - { - return xscale_read_dcsr(arch_info->target); - } - else if (strcmp(reg->name, "XSCALE_TX") == 0) - { - /* 1 = consume register content */ - return xscale_read_tx(arch_info->target, 1); - } - else if (strcmp(reg->name, "XSCALE_RX") == 0) - { - /* can't read from RX register (host -> debug handler) */ - return ERROR_OK; - } - else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) - { - /* can't (explicitly) read from TXRXCTRL register */ - return ERROR_OK; - } - else /* Other DBG registers have to be transfered by the debug handler */ - { - /* send CP read request (command 0x40) */ - xscale_send_u32(target, 0x40); - - /* send CP register number */ - xscale_send_u32(target, arch_info->dbg_handler_number); - - /* read register value */ - xscale_read_tx(target, 1); - buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); - - reg->dirty = 0; - reg->valid = 1; - } - - return ERROR_OK; -} - -int xscale_set_reg(reg_t *reg, u8* buf) -{ - xscale_reg_t *arch_info = reg->arch_info; - target_t *target = arch_info->target; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 value = buf_get_u32(buf, 0, 32); - - /* DCSR, TX and RX are accessible via JTAG */ - if (strcmp(reg->name, "XSCALE_DCSR") == 0) - { - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); - return xscale_write_dcsr(arch_info->target, -1, -1); - } - else if (strcmp(reg->name, "XSCALE_RX") == 0) - { - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); - return xscale_write_rx(arch_info->target); - } - else if (strcmp(reg->name, "XSCALE_TX") == 0) - { - /* can't write to TX register (debug-handler -> host) */ - return ERROR_OK; - } - else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) - { - /* can't (explicitly) write to TXRXCTRL register */ - return ERROR_OK; - } - else /* Other DBG registers have to be transfered by the debug handler */ - { - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, arch_info->dbg_handler_number); - - /* send CP register value */ - xscale_send_u32(target, value); - buf_set_u32(reg->value, 0, 32, value); - } - - return ERROR_OK; -} - -/* convenience wrapper to access XScale specific registers */ -int xscale_set_reg_u32(reg_t *reg, u32 value) -{ - u8 buf[4]; - - buf_set_u32(buf, 0, 32, value); - - return xscale_set_reg(reg, buf); -} - -int xscale_write_dcsr_sw(target_t *target, u32 value) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; - xscale_reg_t *dcsr_arch_info = dcsr->arch_info; - - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); - - /* send CP register value */ - xscale_send_u32(target, value); - buf_set_u32(dcsr->value, 0, 32, value); - - return ERROR_OK; -} - -int xscale_read_trace(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - xscale_trace_data_t **trace_data_p; - - /* 258 words from debug handler - * 256 trace buffer entries - * 2 checkpoint addresses - */ - u32 trace_buffer[258]; - int is_address[256]; - int i, j; - - if (target->state != TARGET_HALTED) - { - WARNING("target must be stopped to read trace data"); - return ERROR_TARGET_NOT_HALTED; - } - - /* send read trace buffer command (command 0x61) */ - xscale_send_u32(target, 0x61); - - /* receive trace buffer content */ - xscale_receive(target, trace_buffer, 258); - - /* parse buffer backwards to identify address entries */ - for (i = 255; i >= 0; i--) - { - is_address[i] = 0; - if (((trace_buffer[i] & 0xf0) == 0x90) || - ((trace_buffer[i] & 0xf0) == 0xd0)) - { - if (i >= 3) - is_address[--i] = 1; - if (i >= 2) - is_address[--i] = 1; - if (i >= 1) - is_address[--i] = 1; - if (i >= 0) - is_address[--i] = 1; - } - } - - - /* search first non-zero entry */ - for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) - ; - - if (j == 256) - { - DEBUG("no trace data collected"); - return ERROR_XSCALE_NO_TRACE_DATA; - } - - for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) - ; - - *trace_data_p = malloc(sizeof(xscale_trace_data_t)); - (*trace_data_p)->next = NULL; - (*trace_data_p)->chkpt0 = trace_buffer[256]; - (*trace_data_p)->chkpt1 = trace_buffer[257]; - (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j)); - (*trace_data_p)->depth = 256 - j; - - for (i = j; i < 256; i++) - { - (*trace_data_p)->entries[i - j].data = trace_buffer[i]; - if (is_address[i]) - (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; - else - (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; - } - - return ERROR_OK; -} - -int xscale_read_instruction(target_t *target, arm_instruction_t *instruction) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int i; - int section = -1; - u32 size_read; - u32 opcode; - int retval; - - if (!xscale->trace.image) - return ERROR_TRACE_IMAGE_UNAVAILABLE; - - /* search for the section the current instruction belongs to */ - for (i = 0; i < xscale->trace.image->num_sections; i++) - { - if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) && - (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc)) - { - section = i; - break; - } - } - - if (section == -1) - { - /* current instruction couldn't be found in the image */ - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - - if (xscale->trace.core_state == ARMV4_5_STATE_ARM) - { - u8 buf[4]; - if ((retval = image_read_section(xscale->trace.image, section, - xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, - 4, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u32(target, buf); - arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); - } - else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB) - { - u8 buf[2]; - if ((retval = image_read_section(xscale->trace.image, section, - xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, - 2, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u16(target, buf); - thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); - } - else - { - ERROR("BUG: unknown core state encountered"); - exit(-1); - } - - return ERROR_OK; -} - -int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target) -{ - /* if there are less than four entries prior to the indirect branch message - * we can't extract the address */ - if (i < 4) - { - return -1; - } - - *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | - (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); - - return 0; -} - -int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int next_pc_ok = 0; - u32 next_pc = 0x0; - xscale_trace_data_t *trace_data = xscale->trace.data; - int retval; - - while (trace_data) - { - int i, chkpt; - int rollover; - int branch; - int exception; - xscale->trace.core_state = ARMV4_5_STATE_ARM; - - chkpt = 0; - rollover = 0; - - for (i = 0; i < trace_data->depth; i++) - { - next_pc_ok = 0; - branch = 0; - exception = 0; - - if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) - continue; - - switch ((trace_data->entries[i].data & 0xf0) >> 4) - { - case 0: /* Exceptions */ - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - exception = (trace_data->entries[i].data & 0x70) >> 4; - next_pc_ok = 1; - next_pc = (trace_data->entries[i].data & 0xf0) >> 2; - command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4); - break; - case 8: /* Direct Branch */ - branch = 1; - break; - case 9: /* Indirect Branch */ - branch = 1; - if (xscale_branch_address(trace_data, i, &next_pc) == 0) - { - next_pc_ok = 1; - } - break; - case 13: /* Checkpointed Indirect Branch */ - if (xscale_branch_address(trace_data, i, &next_pc) == 0) - { - next_pc_ok = 1; - if (((chkpt == 0) && (next_pc != trace_data->chkpt0)) - || ((chkpt == 1) && (next_pc != trace_data->chkpt1))) - WARNING("checkpointed indirect branch target address doesn't match checkpoint"); - } - /* explicit fall-through */ - case 12: /* Checkpointed Direct Branch */ - branch = 1; - if (chkpt == 0) - { - next_pc_ok = 1; - next_pc = trace_data->chkpt0; - chkpt++; - } - else if (chkpt == 1) - { - next_pc_ok = 1; - next_pc = trace_data->chkpt0; - chkpt++; - } - else - { - WARNING("more than two checkpointed branches encountered"); - } - break; - case 15: /* Roll-over */ - rollover++; - continue; - default: /* Reserved */ - command_print(cmd_ctx, "--- reserved trace message ---"); - ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4); - return ERROR_OK; - } - - if (xscale->trace.pc_ok) - { - int executed = (trace_data->entries[i].data & 0xf) + rollover * 16; - arm_instruction_t instruction; - - if ((exception == 6) || (exception == 7)) - { - /* IRQ or FIQ exception, no instruction executed */ - executed -= 1; - } - - while (executed-- >= 0) - { - if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images */ - } - } - - /* a precise abort on a load to the PC is included in the incremental - * word count, other instructions causing data aborts are not included - */ - if ((executed == 0) && (exception == 4) - && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM))) - { - if ((instruction.type == ARM_LDM) - && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0)) - { - executed--; - } - else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) - && (instruction.info.load_store.Rd != 15)) - { - executed--; - } - } - - /* only the last instruction executed - * (the one that caused the control flow change) - * could be a taken branch - */ - if (((executed == -1) && (branch == 1)) && - (((instruction.type == ARM_B) || - (instruction.type == ARM_BL) || - (instruction.type == ARM_BLX)) && - (instruction.info.b_bl_bx_blx.target_address != -1))) - { - xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address; - } - else - { - xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - command_print(cmd_ctx, "%s", instruction.text); - } - - rollover = 0; - } - - if (next_pc_ok) - { - xscale->trace.current_pc = next_pc; - xscale->trace.pc_ok = 1; - } - } - - for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2) - { - arm_instruction_t instruction; - if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images */ - } - } - command_print(cmd_ctx, "%s", instruction.text); - } - - trace_data = trace_data->next; - } - - return ERROR_OK; -} - -void xscale_build_reg_cache(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); - xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info)); - int i; - int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t); - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - /* register a register arch-type for XScale dbg registers only once */ - if (xscale_reg_arch_type == -1) - xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg); - - (*cache_p)->next = malloc(sizeof(reg_cache_t)); - cache_p = &(*cache_p)->next; - - /* fill in values for the xscale reg cache */ - (*cache_p)->name = "XScale registers"; - (*cache_p)->next = NULL; - (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t)); - (*cache_p)->num_regs = num_regs; - - for (i = 0; i < num_regs; i++) - { - (*cache_p)->reg_list[i].name = xscale_reg_list[i]; - (*cache_p)->reg_list[i].value = calloc(4, 1); - (*cache_p)->reg_list[i].dirty = 0; - (*cache_p)->reg_list[i].valid = 0; - (*cache_p)->reg_list[i].size = 32; - (*cache_p)->reg_list[i].bitfield_desc = NULL; - (*cache_p)->reg_list[i].num_bitfields = 0; - (*cache_p)->reg_list[i].arch_info = &arch_info[i]; - (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type; - arch_info[i] = xscale_reg_arch_info[i]; - arch_info[i].target = target; - } - - xscale->reg_cache = (*cache_p); -} - -int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - if (startup_mode != DAEMON_RESET) - { - ERROR("XScale target requires a reset"); - ERROR("Reset target to enable debug"); - } - - /* assert TRST once during startup */ - jtag_add_reset(1, 0); - jtag_add_sleep(5000); - jtag_add_reset(0, 0); - jtag_execute_queue(); - - return ERROR_OK; -} - -int xscale_quit() -{ - - return ERROR_OK; -} - -int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant) -{ - armv4_5_common_t *armv4_5; - u32 high_reset_branch, low_reset_branch; - int i; - - armv4_5 = &xscale->armv4_5_common; - - /* store architecture specfic data (none so far) */ - xscale->arch_info = NULL; - xscale->common_magic = XSCALE_COMMON_MAGIC; - - /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */ - xscale->variant = strdup(variant); - - /* prepare JTAG information for the new target */ - xscale->jtag_info.chain_pos = chain_pos; - jtag_register_event_callback(xscale_jtag_callback, target); - - xscale->jtag_info.dbgrx = 0x02; - xscale->jtag_info.dbgtx = 0x10; - xscale->jtag_info.dcsr = 0x09; - xscale->jtag_info.ldic = 0x07; - - if ((strcmp(xscale->variant, "pxa250") == 0) || - (strcmp(xscale->variant, "pxa255") == 0) || - (strcmp(xscale->variant, "pxa26x") == 0)) - { - xscale->jtag_info.ir_length = 5; - } - else if ((strcmp(xscale->variant, "pxa27x") == 0) || - (strcmp(xscale->variant, "ixp42x") == 0) || - (strcmp(xscale->variant, "ixp45x") == 0) || - (strcmp(xscale->variant, "ixp46x") == 0)) - { - xscale->jtag_info.ir_length = 7; - } - - /* the debug handler isn't installed (and thus not running) at this time */ - xscale->handler_installed = 0; - xscale->handler_running = 0; - xscale->handler_address = 0xfe000800; - - /* clear the vectors we keep locally for reference */ - memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); - memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); - - /* no user-specified vectors have been configured yet */ - xscale->static_low_vectors_set = 0x0; - xscale->static_high_vectors_set = 0x0; - - /* calculate branches to debug handler */ - low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; - high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; - - xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); - xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); - - for (i = 1; i <= 7; i++) - { - xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); - xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - - /* 64kB aligned region used for DCache cleaning */ - xscale->cache_clean_address = 0xfffe0000; - - xscale->hold_rst = 0; - xscale->external_debug_break = 0; - - xscale->force_hw_bkpts = 1; - - xscale->ibcr_available = 2; - xscale->ibcr0_used = 0; - xscale->ibcr1_used = 0; - - xscale->dbr_available = 2; - xscale->dbr0_used = 0; - xscale->dbr1_used = 0; - - xscale->arm_bkpt = ARMV5_BKPT(0x0); - xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - xscale->vector_catch = 0x1; - - xscale->trace.capture_status = TRACE_IDLE; - xscale->trace.data = NULL; - xscale->trace.image = NULL; - xscale->trace.buffer_enabled = 0; - xscale->trace.buffer_fill = 0; - - /* prepare ARMv4/5 specific information */ - armv4_5->arch_info = xscale; - armv4_5->read_core_reg = xscale_read_core_reg; - armv4_5->write_core_reg = xscale_write_core_reg; - armv4_5->full_context = xscale_full_context; - - armv4_5_init_arch_info(target, armv4_5); - - xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; - xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; - xscale->armv4_5_mmu.read_memory = xscale_read_memory; - xscale->armv4_5_mmu.write_memory = xscale_write_memory; - xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; - xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; - xscale->armv4_5_mmu.has_tiny_pages = 1; - xscale->armv4_5_mmu.mmu_enabled = 0; - - xscale->fast_memory_access = 0; - - return ERROR_OK; -} - -/* target xscale */ -int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - xscale_common_t *xscale = malloc(sizeof(xscale_common_t)); - - if (argc < 5) - { - ERROR("'target xscale' requires four arguments: "); - return ERROR_OK; - } - - chain_pos = strtoul(args[3], NULL, 0); - - variant = args[4]; - - xscale_init_arch_info(target, xscale, chain_pos, variant); - xscale_build_reg_cache(target); - - return ERROR_OK; -} - -int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - u32 handler_address; - - if (argc < 2) - { - ERROR("'xscale debug_handler
' command takes two required operands"); - return ERROR_OK; - } - - if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) - { - ERROR("no target '%s' configured", args[0]); - return ERROR_OK; - } - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - handler_address = strtoul(args[1], NULL, 0); - - if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || - ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) - { - xscale->handler_address = handler_address; - } - else - { - ERROR("xscale debug_handler
must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); - } - - return ERROR_OK; -} - -int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - u32 cache_clean_address; - - if (argc < 2) - { - ERROR("'xscale cache_clean_address
' command takes two required operands"); - return ERROR_OK; - } - - if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) - { - ERROR("no target '%s' configured", args[0]); - return ERROR_OK; - } - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - cache_clean_address = strtoul(args[1], NULL, 0); - - if (cache_clean_address & 0xffff) - { - ERROR("xscale cache_clean_address
must be 64kb aligned"); - } - else - { - xscale->cache_clean_address = cache_clean_address; - } - - return ERROR_OK; -} - -int xscale_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache); -} - -static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - int retval; - int type; - u32 cb; - int domain; - u32 ap; - - if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK) - { - return retval; - } - u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); - if (type == -1) - { - return ret; - } - - *physical = ret; - return ERROR_OK; -} - -static int xscale_mmu(struct target_s *target, int *enabled) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_INVALID; - } - - *enabled = xscale->armv4_5_mmu.mmu_enabled; - return ERROR_OK; -} - -int xscale_handle_mmu_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc >= 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale_enable_mmu_caches(target, 1, 0, 0); - xscale->armv4_5_mmu.mmu_enabled = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale_disable_mmu_caches(target, 1, 0, 0); - xscale->armv4_5_mmu.mmu_enabled = 0; - } - } - - command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_idcache_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; - xscale_common_t *xscale; - int icache = 0, dcache = 0; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (strcmp(cmd, "icache") == 0) - icache = 1; - else if (strcmp(cmd, "dcache") == 0) - dcache = 1; - - if (argc >= 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale_enable_mmu_caches(target, 0, dcache, icache); - - if (icache) - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1; - else if (dcache) - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale_disable_mmu_caches(target, 0, dcache, icache); - - if (icache) - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - else if (dcache) - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - } - } - - if (icache) - command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled"); - - if (dcache) - command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_vector_catch_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale vector_catch [mask]"); - } - else - { - xscale->vector_catch = strtoul(args[0], NULL, 0); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); - xscale_write_dcsr(target, -1, -1); - } - - command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch); - - return ERROR_OK; -} - -int xscale_handle_force_hw_bkpts_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) - { - xscale->force_hw_bkpts = 1; - } - else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) - { - xscale->force_hw_bkpts = 0; - } - else - { - command_print(cmd_ctx, "usage: xscale force_hw_bkpts "); - } - - command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_trace_buffer_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; - xscale_common_t *xscale; - u32 dcsr_value; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) - { - xscale_trace_data_t *td, *next_td; - xscale->trace.buffer_enabled = 1; - - /* free old trace data */ - td = xscale->trace.data; - while (td) - { - next_td = td->next; - - if (td->entries) - free(td->entries); - free(td); - td = next_td; - } - xscale->trace.data = NULL; - } - else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) - { - xscale->trace.buffer_enabled = 0; - } - - if ((argc >= 2) && (strcmp("fill", args[1]) == 0)) - { - if (argc >= 3) - xscale->trace.buffer_fill = strtoul(args[2], NULL, 0); - else - xscale->trace.buffer_fill = 1; - } - else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0)) - { - xscale->trace.buffer_fill = -1; - } - - if (xscale->trace.buffer_enabled) - { - /* if we enable the trace buffer in fill-once - * mode we know the address of the first instruction */ - xscale->trace.pc_ok = 1; - xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - } - else - { - /* otherwise the address is unknown, and we have no known good PC */ - xscale->trace.pc_ok = 0; - } - - command_print(cmd_ctx, "trace buffer %s (%s)", - (xscale->trace.buffer_enabled) ? "enabled" : "disabled", - (xscale->trace.buffer_fill > 0) ? "fill" : "wrap"); - - dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); - if (xscale->trace.buffer_fill >= 0) - xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); - else - xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); - - return ERROR_OK; -} - -int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale trace_image [base address] [type]"); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (xscale->trace.image) - { - image_close(xscale->trace.image); - free(xscale->trace.image); - command_print(cmd_ctx, "previously loaded image found and closed"); - } - - xscale->trace.image = malloc(sizeof(image_t)); - xscale->trace.image->base_address_set = 0; - xscale->trace.image->start_address_set = 0; - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - xscale->trace.image->base_address_set = 1; - xscale->trace.image->base_address = strtoul(args[1], NULL, 0); - } - else - { - xscale->trace.image->base_address_set = 0; - } - - if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str); - free(xscale->trace.image); - xscale->trace.image = NULL; - return ERROR_OK; - } - - return ERROR_OK; -} - -int xscale_handle_dump_trace_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; - xscale_common_t *xscale; - xscale_trace_data_t *trace_data; - fileio_t file; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale dump_trace "); - return ERROR_OK; - } - - trace_data = xscale->trace.data; - - if (!trace_data) - { - command_print(cmd_ctx, "no trace data collected"); - return ERROR_OK; - } - - if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - while (trace_data) - { - int i; - - fileio_write_u32(&file, trace_data->chkpt0); - fileio_write_u32(&file, trace_data->chkpt1); - fileio_write_u32(&file, trace_data->last_instruction); - fileio_write_u32(&file, trace_data->depth); - - for (i = 0; i < trace_data->depth; i++) - fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); - - trace_data = trace_data->next; - } - - fileio_close(&file); - - return ERROR_OK; -} - -int xscale_handle_analyze_trace_buffer_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - xscale_analyze_trace(target, cmd_ctx); - - return ERROR_OK; -} - -int xscale_handle_cp15(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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - u32 reg_no = 0; - reg_t *reg = NULL; - if(argc > 0) - { - reg_no = strtoul(args[0], NULL, 0); - /*translate from xscale cp15 register no to openocd register*/ - switch(reg_no) - { - case 0: - reg_no = XSCALE_MAINID; - break; - case 1: - reg_no = XSCALE_CTRL; - break; - case 2: - reg_no = XSCALE_TTB; - break; - case 3: - reg_no = XSCALE_DAC; - break; - case 5: - reg_no = XSCALE_FSR; - break; - case 6: - reg_no = XSCALE_FAR; - break; - case 13: - reg_no = XSCALE_PID; - break; - case 15: - reg_no = XSCALE_CPACCESS; - break; - default: - command_print(cmd_ctx, "invalid register number"); - return ERROR_INVALID_ARGUMENTS; - } - reg = &xscale->reg_cache->reg_list[reg_no]; - - } - if(argc == 1) - { - u32 value; - - /* read cp15 control register */ - xscale_get_reg(reg); - value = buf_get_u32(reg->value, 0, 32); - command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value); - } - else if(argc == 2) - { - - u32 value = strtoul(args[1], NULL, 0); - - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, reg_no); - - /* send CP register value */ - xscale_send_u32(target, value); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); - } - else - { - command_print(cmd_ctx, "usage: cp15 [register]<, [value]>"); - } - - return ERROR_OK; -} - -int handle_xscale_fast_memory_access_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; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (argc == 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale->fast_memory_access = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale->fast_memory_access = 0; - } - else - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - } else if (argc!=0) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *xscale_cmd; - - xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands"); - - register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler
' command takes two required operands"); - register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL); - - register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU"); - register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache"); - register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache"); - - register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, " of vectors that should be catched"); - - register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, " ['fill' [n]|'wrap']"); - - register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to "); - register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer"); - register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command, - COMMAND_EXEC, "load image from [base address]"); - - register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 [value]"); - register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command, - COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses "); - - armv4_5_register_commands(cmd_ctx); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2006, 2007 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "xscale.h" + +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "arm_simulator.h" +#include "arm_disassembler.h" +#include "log.h" +#include "jtag.h" +#include "binarybuffer.h" +#include "time_support.h" +#include "breakpoints.h" +#include "fileio.h" + +#include +#include + +#include +#include +#include + + +/* cli handling */ +int xscale_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int xscale_quit(); + +int xscale_arch_state(struct target_s *target); +int xscale_poll(target_t *target); +int xscale_halt(target_t *target); +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints); +int xscale_debug_entry(target_t *target); +int xscale_restore_context(target_t *target); + +int xscale_assert_reset(target_t *target); +int xscale_deassert_reset(target_t *target); +int xscale_soft_reset_halt(struct target_s *target); +int xscale_prepare_reset_halt(struct target_s *target); + +int xscale_set_reg_u32(reg_t *reg, u32 value); + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode); +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value); + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer); +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +void xscale_enable_watchpoints(struct target_s *target); +void xscale_enable_breakpoints(struct target_s *target); +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int xscale_mmu(struct target_s *target, int *enabled); + +int xscale_read_trace(target_t *target); + +target_type_t xscale_target = +{ + .name = "xscale", + + .poll = xscale_poll, + .arch_state = xscale_arch_state, + + .target_request_data = NULL, + + .halt = xscale_halt, + .resume = xscale_resume, + .step = xscale_step, + + .assert_reset = xscale_assert_reset, + .deassert_reset = xscale_deassert_reset, + .soft_reset_halt = xscale_soft_reset_halt, + .prepare_reset_halt = xscale_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = xscale_read_memory, + .write_memory = xscale_write_memory, + .bulk_write_memory = xscale_bulk_write_memory, + .checksum_memory = xscale_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = xscale_add_breakpoint, + .remove_breakpoint = xscale_remove_breakpoint, + .add_watchpoint = xscale_add_watchpoint, + .remove_watchpoint = xscale_remove_watchpoint, + + .register_commands = xscale_register_commands, + .target_command = xscale_target_command, + .init_target = xscale_init_target, + .quit = xscale_quit, + + .virt2phys = xscale_virt2phys, + .mmu = xscale_mmu +}; + +char* xscale_reg_list[] = +{ + "XSCALE_MAINID", /* 0 */ + "XSCALE_CACHETYPE", + "XSCALE_CTRL", + "XSCALE_AUXCTRL", + "XSCALE_TTB", + "XSCALE_DAC", + "XSCALE_FSR", + "XSCALE_FAR", + "XSCALE_PID", + "XSCALE_CPACCESS", + "XSCALE_IBCR0", /* 10 */ + "XSCALE_IBCR1", + "XSCALE_DBR0", + "XSCALE_DBR1", + "XSCALE_DBCON", + "XSCALE_TBREG", + "XSCALE_CHKPT0", + "XSCALE_CHKPT1", + "XSCALE_DCSR", + "XSCALE_TX", + "XSCALE_RX", /* 20 */ + "XSCALE_TXRXCTRL", +}; + +xscale_reg_t xscale_reg_arch_info[] = +{ + {XSCALE_MAINID, NULL}, + {XSCALE_CACHETYPE, NULL}, + {XSCALE_CTRL, NULL}, + {XSCALE_AUXCTRL, NULL}, + {XSCALE_TTB, NULL}, + {XSCALE_DAC, NULL}, + {XSCALE_FSR, NULL}, + {XSCALE_FAR, NULL}, + {XSCALE_PID, NULL}, + {XSCALE_CPACCESS, NULL}, + {XSCALE_IBCR0, NULL}, + {XSCALE_IBCR1, NULL}, + {XSCALE_DBR0, NULL}, + {XSCALE_DBR1, NULL}, + {XSCALE_DBCON, NULL}, + {XSCALE_TBREG, NULL}, + {XSCALE_CHKPT0, NULL}, + {XSCALE_CHKPT1, NULL}, + {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ + {-1, NULL}, /* TX accessed via JTAG */ + {-1, NULL}, /* RX accessed via JTAG */ + {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ +}; + +int xscale_reg_arch_type = -1; + +int xscale_get_reg(reg_t *reg); +int xscale_set_reg(reg_t *reg, u8 *buf); + +int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + if (xscale->common_magic != XSCALE_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + *armv4_5_p = armv4_5; + *xscale_p = xscale; + + return ERROR_OK; +} + +int xscale_jtag_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = 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; + jtag_set_check_value(&field, device->expected, device->expected_mask, NULL); + + jtag_add_ir_scan(1, &field, -1); + + free(field.out_value); + } + + return ERROR_OK; +} + +int xscale_jtag_callback(enum jtag_event event, void *priv) +{ + switch (event) + { + case JTAG_TRST_ASSERTED: + break; + case JTAG_TRST_RELEASED: + break; + case JTAG_SRST_ASSERTED: + break; + case JTAG_SRST_RELEASED: + break; + default: + WARNING("unhandled JTAG event"); + } + + return ERROR_OK; +} + +int xscale_read_dcsr(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_PD); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + 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 = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + /* write the register with the value we just read + * on this second pass, only the first bit of field0 is guaranteed to be 0) + */ + field0_check_mask = 0x1; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].in_value = NULL; + + jtag_add_end_state(TAP_RTI); + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +int xscale_receive(target_t *target, u32 *buffer, int num_words) +{ + int retval = ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + enum tap_state path[3]; + scan_field_t fields[3]; + + u8 *field0 = malloc(num_words * 1); + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u32 *field1 = malloc(num_words * 4); + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + int words_done = 0; + int words_scheduled = 0; + + int i; + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + /* fields[0].in_value = field0; */ + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->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_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + jtag_add_runtest(1, -1); + + /* repeat until all words have been collected */ + int attempts = 0; + while (words_done < num_words) + { + /* schedule reads */ + words_scheduled = 0; + for (i = words_done; i < num_words; i++) + { + fields[0].in_value = &field0[i]; + fields[1].in_handler = buf_to_u32_handler; + fields[1].in_handler_priv = (u8*)&field1[i]; + + jtag_add_pathmove(3, path); + jtag_add_dr_scan(3, fields, TAP_RTI); + words_scheduled++; + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while receiving data from debug handler"); + break; + } + + /* examine results */ + for (i = words_done; i < num_words; i++) + { + if (!(field0[0] & 1)) + { + /* move backwards if necessary */ + int j; + for (j = i; j < num_words - 1; j++) + { + field0[j] = field0[j+1]; + field1[j] = field1[j+1]; + } + words_scheduled--; + } + } + if (words_scheduled == 0) + { + if (attempts++ == 1000) + { + ERROR("Failed to receiving data from debug handler after 1000 attempts"); + retval = ERROR_JTAG_QUEUE_FAILED; + break; + } + } + + words_done += words_scheduled; + } + + for (i = 0; i < num_words; i++) + *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32); + + free(field1); + + return retval; +} + +int xscale_read_tx(target_t *target, int consume) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + enum tap_state path[3]; + enum tap_state noconsume_path[9]; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + noconsume_path[0] = TAP_SDS; + noconsume_path[1] = TAP_CD; + noconsume_path[2] = TAP_E1D; + noconsume_path[3] = TAP_PD; + noconsume_path[4] = TAP_E2D; + noconsume_path[5] = TAP_UD; + noconsume_path[6] = TAP_SDS; + noconsume_path[7] = TAP_CD; + noconsume_path[8] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; + 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 = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + do + { + /* if we want to consume the register content (i.e. clear TX_READY), + * we have to go straight from Capture-DR to Shift-DR + * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR + */ + if (consume) + jtag_add_pathmove(3, path); + else + jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path); + + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading TX"); + return ERROR_TARGET_TIMEOUT; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out reading TX register"); + return ERROR_TARGET_TIMEOUT; + } + } while ((!(field0_in & 1)) && consume); + + if (!(field0_in & 1)) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + return ERROR_OK; +} + +int xscale_write_rx(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; + 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 = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + /* poll until rx_read is low */ + DEBUG("polling RX"); + do + { + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out writing RX register"); + return ERROR_TARGET_TIMEOUT; + } + } while (field0_in & 1); + + /* set rx_valid */ + field2 = 0x1; + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + return ERROR_OK; +} + +/* send count elements of size byte to the debug handler */ +int xscale_send(target_t *target, u8 *buffer, int count, int size) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + int done_count = 0; + u8 output[4] = {0, 0, 0, 0}; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x1; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + } + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = output; + 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 = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + } + + if (size==4) + { + int endianness = target->endianness; + while (done_count++ < count) + { + if (endianness == TARGET_LITTLE_ENDIAN) + { + output[0]=buffer[0]; + output[1]=buffer[1]; + output[2]=buffer[2]; + output[3]=buffer[3]; + } else + { + output[0]=buffer[3]; + output[1]=buffer[2]; + output[2]=buffer[1]; + output[3]=buffer[0]; + } + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } else + { + while (done_count++ < count) + { + /* extract sized element from target-endian buffer, and put it + * into little-endian output buffer + */ + switch (size) + { + case 2: + buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer)); + break; + case 1: + output[0] = *buffer; + break; + default: + ERROR("BUG: size neither 4, 2 nor 1"); + exit(-1); + } + + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while sending data to debug handler"); + return retval; + } + + return ERROR_OK; +} + +int xscale_send_u32(target_t *target, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(target); +} + +int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + if (hold_rst != -1) + xscale->hold_rst = hold_rst; + + if (ext_dbg_brk != -1) + xscale->external_debug_break = ext_dbg_brk; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + 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 = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + return ERROR_OK; +} + +/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ +unsigned int parity (unsigned int v) +{ + unsigned int ov = v; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v &= 0xf; + DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); + return (0x6996 >> v) & 1; +} + +int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8]) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + int word; + + scan_field_t fields[2]; + + DEBUG("loading miniIC at 0x%8.8x", va); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD is b010 for Main IC and b011 for Mini IC */ + if (mini) + buf_set_u32(&cmd, 0, 3, 0x3); + else + buf_set_u32(&cmd, 0, 3, 0x2); + + buf_set_u32(&cmd, 3, 3, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + 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 = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + 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; + + jtag_add_dr_scan(2, fields, -1); + + fields[0].num_bits = 32; + fields[0].out_value = packet; + + fields[1].num_bits = 1; + fields[1].out_value = &cmd; + + for (word = 0; word < 8; word++) + { + buf_set_u32(packet, 0, 32, buffer[word]); + cmd = parity(*((u32*)packet)); + jtag_add_dr_scan(2, fields, -1); + } + + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_invalidate_ic_line(target_t *target, u32 va) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + + scan_field_t fields[2]; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD for invalidate IC line b000, bits [6:4] b000 */ + buf_set_u32(&cmd, 0, 6, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + 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 = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + 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; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +int xscale_update_vectors(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + + u32 low_reset_branch, high_reset_branch; + + for (i = 1; i < 8; i++) + { + /* if there's a static vector specified for this exception, override */ + if (xscale->static_high_vectors_set & (1 << i)) + { + xscale->high_vectors[i] = xscale->static_high_vectors[i]; + } + else + { + if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK) + { + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + for (i = 1; i < 8; i++) + { + if (xscale->static_low_vectors_set & (1 << i)) + { + xscale->low_vectors[i] = xscale->static_low_vectors[i]; + } + else + { + if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + /* invalidate and load exception vectors in mini i-cache */ + xscale_invalidate_ic_line(target, 0x0); + xscale_invalidate_ic_line(target, 0xffff0000); + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + return ERROR_OK; +} + +int xscale_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + char *arch_dbg_reason[] = + { + "", "\n(processor reset)", "\n(trace buffer full)" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER("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" + "%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[xscale->armv4_5_mmu.mmu_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], + arch_dbg_reason[xscale->arch_debug_reason]); + + return ERROR_OK; +} + +int xscale_poll(target_t *target) +{ + int retval=ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) + { + enum target_state previous_state = target->state; + if ((retval = xscale_read_tx(target, 0)) == ERROR_OK) + { + + /* there's data to read from the tx register, we entered debug state */ + xscale->handler_running = 1; + + target->state = TARGET_HALTED; + + /* process debug entry, fetching current mode regs */ + retval = xscale_debug_entry(target); + } + else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + USER("error while polling TX register, reset CPU"); + /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ + target->state = TARGET_HALTED; + } + + /* debug_entry could have overwritten target state (i.e. immediate resume) + * don't signal event handlers in that case + */ + if (target->state != TARGET_HALTED) + return ERROR_OK; + + /* if target was running, signal that we halted + * otherwise we reentered from debug execution */ + if (previous_state == TARGET_RUNNING) + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + else + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + return retval; +} + +int xscale_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 pc; + u32 buffer[10]; + int i; + + u32 moe; + + /* clear external dbg break (will be written on next DCSR read) */ + xscale->external_debug_break = 0; + xscale_read_dcsr(target); + + /* get r0, pc, r1 to r7 and cpsr */ + xscale_receive(target, buffer, 10); + + /* move r0 from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("r0: 0x%8.8x", buffer[0]); + + /* move pc from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("pc: 0x%8.8x", buffer[1]); + + /* move data from buffer to register cache */ + for (i = 1; i <= 7; i++) + { + buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); + armv4_5->core_cache->reg_list[i].dirty = 1; + armv4_5->core_cache->reg_list[i].valid = 1; + DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]); + } + + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + DEBUG("cpsr: 0x%8.8x", buffer[9]); + + armv4_5->core_mode = buffer[9] & 0x1f; + if (armv4_5_mode_to_number(armv4_5->core_mode) == -1) + { + target->state = TARGET_UNKNOWN; + ERROR("cpsr contains invalid mode value - communication failure"); + return ERROR_TARGET_FAILURE; + } + DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]); + + if (buffer[9] & 0x20) + armv4_5->core_state = ARMV4_5_STATE_THUMB; + else + armv4_5->core_state = ARMV4_5_STATE_ARM; + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1; + } + else + { + /* r8 to r14, but no spsr */ + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (i = 8; i <= 14; i++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1; + } + + /* examine debug reason */ + xscale_read_dcsr(target); + moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); + + /* stored PC (for calculating fixup) */ + pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + switch (moe) + { + case 0x0: /* Processor reset */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; + pc -= 4; + break; + case 0x1: /* Instruction breakpoint hit */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x2: /* Data breakpoint hit */ + target->debug_reason = DBG_REASON_WATCHPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x3: /* BKPT instruction executed */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x4: /* Ext. debug event */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x5: /* Vector trap occured */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x6: /* Trace buffer full break */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; + pc -= 4; + break; + case 0x7: /* Reserved */ + default: + ERROR("Method of Entry is 'Reserved'"); + exit(-1); + break; + } + + /* apply PC fixup */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); + + /* on the first debug entry, identify cache type */ + if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + + /* read cp15 cache type register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); + cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); + + armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); + } + + /* examine MMU and Cache settings */ + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* tracing enabled, read collected trace data */ + if (xscale->trace.buffer_enabled) + { + xscale_read_trace(target); + xscale->trace.buffer_fill--; + + /* resume if we're still collecting trace data */ + if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) + && (xscale->trace.buffer_fill > 0)) + { + xscale_resume(target, 1, 0x0, 1, 0); + } + else + { + xscale->trace.buffer_enabled = 0; + } + } + + return ERROR_OK; +} + +int xscale_halt(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + else if (target->state == TARGET_UNKNOWN) + { + /* this must not happen for a xscale target */ + ERROR("target was in unknown state when halt was requested"); + return ERROR_TARGET_INVALID; + } + else if (target->state == TARGET_RESET) + { + DEBUG("target->state == TARGET_RESET"); + } + else + { + /* assert external dbg break */ + xscale->external_debug_break = 1; + xscale_read_dcsr(target); + + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +int xscale_enable_single_step(struct target_s *target, u32 next_pc) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + if (xscale->ibcr0_used) + { + breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); + + if (ibcr0_bp) + { + xscale_unset_breakpoint(target, ibcr0_bp); + } + else + { + ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); + exit(-1); + } + } + + xscale_set_reg_u32(ibcr0, next_pc | 0x1); + + return ERROR_OK; +} + +int xscale_disable_single_step(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + xscale_set_reg_u32(ibcr0, 0x0); + + return ERROR_OK; +} + +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc; + + int retval; + int i; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) + { + target_free_all_working_areas(target); + } + + /* update vector tables */ + xscale_update_vectors(target); + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the branch */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + { + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + u32 next_pc; + + /* there's a breakpoint at the current PC, we have to step over it */ + DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); + xscale_unset_breakpoint(target, breakpoint); + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + DEBUG("set breakpoint at 0x%8.8x", breakpoint->address); + xscale_set_breakpoint(target, breakpoint); + } + } + + /* enable any pending breakpoints and watchpoints */ + xscale_enable_breakpoints(target); + xscale_enable_watchpoints(target); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target->debug_reason = DBG_REASON_NOTHALTED; + + if (!debug_execution) + { + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + } + else + { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + } + + DEBUG("target resumed"); + + xscale->handler_running = 1; + + return ERROR_OK; +} + +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc, next_pc; + int i; + int retval; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the step */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + xscale_unset_breakpoint(target, breakpoint); + } + + target->debug_reason = DBG_REASON_SINGLESTEP; + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + if (breakpoint) + { + xscale_set_breakpoint(target, breakpoint); + } + + DEBUG("target stepped"); + + return ERROR_OK; + +} + +int xscale_assert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + /* select DCSR instruction (set endstate to R-T-I to ensure we don't + * end up in T-L-R, which would reset JTAG + */ + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f); + jtag_execute_queue(); + + /* assert reset */ + jtag_add_reset(0, 1); + + /* sleep 1ms, to be sure we fulfill any requirements */ + jtag_add_sleep(1000); + jtag_execute_queue(); + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +int xscale_deassert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + fileio_t debug_handler; + u32 address; + u32 binary_size; + + u32 buf_cnt; + int i; + int retval; + + breakpoint_t *breakpoint = target->breakpoints; + + DEBUG("-"); + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + /* mark all hardware breakpoints as unset */ + while (breakpoint) + { + if (breakpoint->type == BKPT_HARD) + { + breakpoint->set = 0; + } + breakpoint = breakpoint->next; + } + + if (!xscale->handler_installed) + { + /* release SRST */ + jtag_add_reset(0, 0); + + /* wait 300ms; 150 and 100ms were not enough */ + jtag_add_sleep(300*1000); + + jtag_add_runtest(2030, TAP_RTI); + jtag_execute_queue(); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* Load debug handler */ + if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + ERROR("file open error: %s", debug_handler.error_str); + return ERROR_OK; + } + + if ((binary_size = debug_handler.size) % 4) + { + ERROR("debug_handler.bin: size not a multiple of 4"); + exit(-1); + } + + if (binary_size > 0x800) + { + ERROR("debug_handler.bin: larger than 2kb"); + exit(-1); + } + + binary_size = CEIL(binary_size, 32) * 32; + + address = xscale->handler_address; + while (binary_size > 0) + { + u32 cache_line[8]; + u8 buffer[32]; + + if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("reading debug handler failed: %s", debug_handler.error_str); + } + + for (i = 0; i < buf_cnt; i += 4) + { + /* convert LE buffer to host-endian u32 */ + cache_line[i / 4] = le_to_h_u32(&buffer[i]); + } + + for (; buf_cnt < 32; buf_cnt += 4) + { + cache_line[buf_cnt / 4] = 0xe1a08008; + } + + /* only load addresses other than the reset vectors */ + if ((address % 0x400) != 0x0) + { + xscale_load_ic(target, 1, address, cache_line); + } + + address += buf_cnt; + binary_size -= buf_cnt; + }; + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + jtag_add_runtest(30, TAP_RTI); + + jtag_add_sleep(100000); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* clear Hold reset to let the target run (should enter debug handler) */ + xscale_write_dcsr(target, 0, 1); + target->state = TARGET_RUNNING; + + if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT)) + { + jtag_add_sleep(10000); + + /* we should have entered debug now */ + xscale_debug_entry(target); + target->state = TARGET_HALTED; + + /* resume the target */ + xscale_resume(target, 1, 0x0, 1, 0); + } + + fileio_close(&debug_handler); + } + else + { + jtag_add_reset(0, 0); + } + + + return ERROR_OK; +} + +int xscale_soft_reset_halt(struct target_s *target) +{ + + return ERROR_OK; +} + +int xscale_prepare_reset_halt(struct target_s *target) +{ + /* nothing to be done for reset_halt on XScale targets + * we always halt after a reset to upload the debug handler + */ + return ERROR_OK; +} + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode) +{ + + return ERROR_OK; +} + +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value) +{ + + return ERROR_OK; +} + +int xscale_full_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + u32 *buffer; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + buffer = malloc(4 * 8); + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int valid = 1; + + /* check if there are invalid registers in the current mode + */ + for (j = 0; j <= 16; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0) + valid = 0; + } + + if (!valid) + { + u32 tmp_cpsr; + + /* request banked registers */ + xscale_send_u32(target, 0x0); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; + } + else + { + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (j = 8; j <= 14; j++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1; + } + } + } + + free(buffer); + + return ERROR_OK; +} + +int xscale_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int dirty = 0; + + /* check if there are invalid registers in the current mode + */ + for (j = 8; j <= 14; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1) + dirty = 1; + } + + /* if not USR/SYS, check if the SPSR needs to be written */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1) + dirty = 1; + } + + if (dirty) + { + u32 tmp_cpsr; + + /* send banked registers */ + xscale_send_u32(target, 0x1); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + for (j = 8; j <= 14; j++) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + } + + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + } + } + } + + return ERROR_OK; +} + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 *buf32; + int i; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory read request (command 0x1n, n: access size) */ + xscale_send_u32(target, 0x10 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words */ + xscale_send_u32(target, count); + + /* receive data from target (count times 32-bit words in host endianness) */ + buf32 = malloc(4 * count); + xscale_receive(target, buf32, count); + + /* extract data from host-endian buffer into byte stream */ + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + target_buffer_set_u32(target, buffer, buf32[i]); + buffer += 4; + break; + case 2: + target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); + buffer += 2; + break; + case 1: + *buffer++ = buf32[i] & 0xff; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } + + free(buf32); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory write request (command 0x2n, n: access size) */ + xscale_send_u32(target, 0x20 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words to be written*/ + xscale_send_u32(target, count); + + /* extract data from host-endian buffer into byte stream */ +#if 0 + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + value = target_buffer_get_u32(target, buffer); + xscale_send_u32(target, value); + buffer += 4; + break; + case 2: + value = target_buffer_get_u16(target, buffer); + xscale_send_u32(target, value); + buffer += 2; + break; + case 1: + value = *buffer; + xscale_send_u32(target, value); + buffer += 1; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } +#endif + xscale_send(target, buffer, count, size); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer) +{ + return xscale_write_memory(target, address, 4, count, buffer); +} + +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) +{ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +u32 xscale_get_ttb(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 ttb; + + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); + ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); + + return ttb; +} + +void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache) + { + /* clean DCache */ + xscale_send_u32(target, 0x50); + xscale_send_u32(target, xscale->cache_clean_address); + + /* invalidate DCache */ + xscale_send_u32(target, 0x51); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + xscale_send_u32(target, 0x52); + cp15_control &= ~0x1000U; + } + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + breakpoint->type = BKPT_HARD; + + if (breakpoint->set) + { + WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + u32 value = breakpoint->address | 1; + if (!xscale->ibcr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); + xscale->ibcr0_used = 1; + breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + } + else if (!xscale->ibcr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); + xscale->ibcr1_used = 1; + breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + } + else if (breakpoint->type == BKPT_SOFT) + { + if (breakpoint->length == 4) + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->arm_bkpt); + } + else + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->thumb_bkpt); + } + breakpoint->set = 1; + } + + return ERROR_OK; + +} + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + { + DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address); + breakpoint->type = BKPT_HARD; + } + + if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) + { + INFO("no breakpoint unit available for hardware breakpoint"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + else + { + xscale->ibcr_available--; + } + + if ((breakpoint->length != 2) && (breakpoint->length != 4)) + { + INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!breakpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + if (breakpoint->set == 1) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); + xscale->ibcr0_used = 0; + } + else if (breakpoint->set == 2) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); + xscale->ibcr1_used = 0; + } + breakpoint->set = 0; + } + else + { + /* restore original instruction (kept in target endianness) */ + if (breakpoint->length == 4) + { + target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + } + else + { + target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + } + breakpoint->set = 0; + } + + return ERROR_OK; +} + +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (breakpoint->set) + { + xscale_unset_breakpoint(target, breakpoint); + } + + if (breakpoint->type == BKPT_HARD) + xscale->ibcr_available++; + + return ERROR_OK; +} + +int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 enable = 0; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + xscale_get_reg(dbcon); + + switch (watchpoint->rw) + { + case WPT_READ: + enable = 0x3; + break; + case WPT_ACCESS: + enable = 0x2; + break; + case WPT_WRITE: + enable = 0x1; + break; + default: + ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + if (!xscale->dbr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); + dbcon_value |= enable; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 1; + xscale->dbr0_used = 1; + } + else if (!xscale->dbr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); + dbcon_value |= enable << 2; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 2; + xscale->dbr1_used = 1; + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->dbr_available < 1) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + xscale->dbr_available--; + + return ERROR_OK; +} + +int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!watchpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (watchpoint->set == 1) + { + dbcon_value &= ~0x3; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr0_used = 0; + } + else if (watchpoint->set == 2) + { + dbcon_value &= ~0xc; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr1_used = 0; + } + watchpoint->set = 0; + + return ERROR_OK; +} + +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + { + xscale_unset_watchpoint(target, watchpoint); + } + + xscale->dbr_available++; + + return ERROR_OK; +} + +void xscale_enable_watchpoints(struct target_s *target) +{ + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + if (watchpoint->set == 0) + xscale_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } +} + +void xscale_enable_breakpoints(struct target_s *target) +{ + breakpoint_t *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) + { + if (breakpoint->set == 0) + xscale_set_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } +} + +int xscale_get_reg(reg_t *reg) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + return xscale_read_dcsr(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* 1 = consume register content */ + return xscale_read_tx(arch_info->target, 1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + /* can't read from RX register (host -> debug handler) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) read from TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP read request (command 0x40) */ + xscale_send_u32(target, 0x40); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* read register value */ + xscale_read_tx(target, 1); + buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); + + reg->dirty = 0; + reg->valid = 1; + } + + return ERROR_OK; +} + +int xscale_set_reg(reg_t *reg, u8* buf) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 value = buf_get_u32(buf, 0, 32); + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); + return xscale_write_dcsr(arch_info->target, -1, -1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* can't write to TX register (debug-handler -> host) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) write to TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(reg->value, 0, 32, value); + } + + return ERROR_OK; +} + +/* convenience wrapper to access XScale specific registers */ +int xscale_set_reg_u32(reg_t *reg, u32 value) +{ + u8 buf[4]; + + buf_set_u32(buf, 0, 32, value); + + return xscale_set_reg(reg, buf); +} + +int xscale_write_dcsr_sw(target_t *target, u32 value) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; + xscale_reg_t *dcsr_arch_info = dcsr->arch_info; + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(dcsr->value, 0, 32, value); + + return ERROR_OK; +} + +int xscale_read_trace(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + xscale_trace_data_t **trace_data_p; + + /* 258 words from debug handler + * 256 trace buffer entries + * 2 checkpoint addresses + */ + u32 trace_buffer[258]; + int is_address[256]; + int i, j; + + if (target->state != TARGET_HALTED) + { + WARNING("target must be stopped to read trace data"); + return ERROR_TARGET_NOT_HALTED; + } + + /* send read trace buffer command (command 0x61) */ + xscale_send_u32(target, 0x61); + + /* receive trace buffer content */ + xscale_receive(target, trace_buffer, 258); + + /* parse buffer backwards to identify address entries */ + for (i = 255; i >= 0; i--) + { + is_address[i] = 0; + if (((trace_buffer[i] & 0xf0) == 0x90) || + ((trace_buffer[i] & 0xf0) == 0xd0)) + { + if (i >= 3) + is_address[--i] = 1; + if (i >= 2) + is_address[--i] = 1; + if (i >= 1) + is_address[--i] = 1; + if (i >= 0) + is_address[--i] = 1; + } + } + + + /* search first non-zero entry */ + for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) + ; + + if (j == 256) + { + DEBUG("no trace data collected"); + return ERROR_XSCALE_NO_TRACE_DATA; + } + + for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) + ; + + *trace_data_p = malloc(sizeof(xscale_trace_data_t)); + (*trace_data_p)->next = NULL; + (*trace_data_p)->chkpt0 = trace_buffer[256]; + (*trace_data_p)->chkpt1 = trace_buffer[257]; + (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j)); + (*trace_data_p)->depth = 256 - j; + + for (i = j; i < 256; i++) + { + (*trace_data_p)->entries[i - j].data = trace_buffer[i]; + if (is_address[i]) + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; + else + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; + } + + return ERROR_OK; +} + +int xscale_read_instruction(target_t *target, arm_instruction_t *instruction) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!xscale->trace.image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < xscale->trace.image->num_sections; i++) + { + if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) && + (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (xscale->trace.core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(target, buf); + arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(target, buf); + thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target) +{ + /* if there are less than four entries prior to the indirect branch message + * we can't extract the address */ + if (i < 4) + { + return -1; + } + + *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | + (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); + + return 0; +} + +int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int next_pc_ok = 0; + u32 next_pc = 0x0; + xscale_trace_data_t *trace_data = xscale->trace.data; + int retval; + + while (trace_data) + { + int i, chkpt; + int rollover; + int branch; + int exception; + xscale->trace.core_state = ARMV4_5_STATE_ARM; + + chkpt = 0; + rollover = 0; + + for (i = 0; i < trace_data->depth; i++) + { + next_pc_ok = 0; + branch = 0; + exception = 0; + + if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) + continue; + + switch ((trace_data->entries[i].data & 0xf0) >> 4) + { + case 0: /* Exceptions */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + exception = (trace_data->entries[i].data & 0x70) >> 4; + next_pc_ok = 1; + next_pc = (trace_data->entries[i].data & 0xf0) >> 2; + command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4); + break; + case 8: /* Direct Branch */ + branch = 1; + break; + case 9: /* Indirect Branch */ + branch = 1; + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + } + break; + case 13: /* Checkpointed Indirect Branch */ + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + if (((chkpt == 0) && (next_pc != trace_data->chkpt0)) + || ((chkpt == 1) && (next_pc != trace_data->chkpt1))) + WARNING("checkpointed indirect branch target address doesn't match checkpoint"); + } + /* explicit fall-through */ + case 12: /* Checkpointed Direct Branch */ + branch = 1; + if (chkpt == 0) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else if (chkpt == 1) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else + { + WARNING("more than two checkpointed branches encountered"); + } + break; + case 15: /* Roll-over */ + rollover++; + continue; + default: /* Reserved */ + command_print(cmd_ctx, "--- reserved trace message ---"); + ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4); + return ERROR_OK; + } + + if (xscale->trace.pc_ok) + { + int executed = (trace_data->entries[i].data & 0xf) + rollover * 16; + arm_instruction_t instruction; + + if ((exception == 6) || (exception == 7)) + { + /* IRQ or FIQ exception, no instruction executed */ + executed -= 1; + } + + while (executed-- >= 0) + { + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + + /* a precise abort on a load to the PC is included in the incremental + * word count, other instructions causing data aborts are not included + */ + if ((executed == 0) && (exception == 4) + && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM))) + { + if ((instruction.type == ARM_LDM) + && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0)) + { + executed--; + } + else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) + && (instruction.info.load_store.Rd != 15)) + { + executed--; + } + } + + /* only the last instruction executed + * (the one that caused the control flow change) + * could be a taken branch + */ + if (((executed == -1) && (branch == 1)) && + (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1))) + { + xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + command_print(cmd_ctx, "%s", instruction.text); + } + + rollover = 0; + } + + if (next_pc_ok) + { + xscale->trace.current_pc = next_pc; + xscale->trace.pc_ok = 1; + } + } + + for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2) + { + arm_instruction_t instruction; + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + command_print(cmd_ctx, "%s", instruction.text); + } + + trace_data = trace_data->next; + } + + return ERROR_OK; +} + +void xscale_build_reg_cache(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info)); + int i; + int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t); + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* register a register arch-type for XScale dbg registers only once */ + if (xscale_reg_arch_type == -1) + xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg); + + (*cache_p)->next = malloc(sizeof(reg_cache_t)); + cache_p = &(*cache_p)->next; + + /* fill in values for the xscale reg cache */ + (*cache_p)->name = "XScale registers"; + (*cache_p)->next = NULL; + (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t)); + (*cache_p)->num_regs = num_regs; + + for (i = 0; i < num_regs; i++) + { + (*cache_p)->reg_list[i].name = xscale_reg_list[i]; + (*cache_p)->reg_list[i].value = calloc(4, 1); + (*cache_p)->reg_list[i].dirty = 0; + (*cache_p)->reg_list[i].valid = 0; + (*cache_p)->reg_list[i].size = 32; + (*cache_p)->reg_list[i].bitfield_desc = NULL; + (*cache_p)->reg_list[i].num_bitfields = 0; + (*cache_p)->reg_list[i].arch_info = &arch_info[i]; + (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type; + arch_info[i] = xscale_reg_arch_info[i]; + arch_info[i].target = target; + } + + xscale->reg_cache = (*cache_p); +} + +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + if (startup_mode != DAEMON_RESET) + { + ERROR("XScale target requires a reset"); + ERROR("Reset target to enable debug"); + } + + /* assert TRST once during startup */ + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + jtag_add_reset(0, 0); + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_quit() +{ + + return ERROR_OK; +} + +int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + u32 high_reset_branch, low_reset_branch; + int i; + + armv4_5 = &xscale->armv4_5_common; + + /* store architecture specfic data (none so far) */ + xscale->arch_info = NULL; + xscale->common_magic = XSCALE_COMMON_MAGIC; + + /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */ + xscale->variant = strdup(variant); + + /* prepare JTAG information for the new target */ + xscale->jtag_info.chain_pos = chain_pos; + jtag_register_event_callback(xscale_jtag_callback, target); + + xscale->jtag_info.dbgrx = 0x02; + xscale->jtag_info.dbgtx = 0x10; + xscale->jtag_info.dcsr = 0x09; + xscale->jtag_info.ldic = 0x07; + + if ((strcmp(xscale->variant, "pxa250") == 0) || + (strcmp(xscale->variant, "pxa255") == 0) || + (strcmp(xscale->variant, "pxa26x") == 0)) + { + xscale->jtag_info.ir_length = 5; + } + else if ((strcmp(xscale->variant, "pxa27x") == 0) || + (strcmp(xscale->variant, "ixp42x") == 0) || + (strcmp(xscale->variant, "ixp45x") == 0) || + (strcmp(xscale->variant, "ixp46x") == 0)) + { + xscale->jtag_info.ir_length = 7; + } + + /* the debug handler isn't installed (and thus not running) at this time */ + xscale->handler_installed = 0; + xscale->handler_running = 0; + xscale->handler_address = 0xfe000800; + + /* clear the vectors we keep locally for reference */ + memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); + memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); + + /* no user-specified vectors have been configured yet */ + xscale->static_low_vectors_set = 0x0; + xscale->static_high_vectors_set = 0x0; + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + for (i = 1; i <= 7; i++) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + + /* 64kB aligned region used for DCache cleaning */ + xscale->cache_clean_address = 0xfffe0000; + + xscale->hold_rst = 0; + xscale->external_debug_break = 0; + + xscale->force_hw_bkpts = 1; + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + xscale->arm_bkpt = ARMV5_BKPT(0x0); + xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + xscale->vector_catch = 0x1; + + xscale->trace.capture_status = TRACE_IDLE; + xscale->trace.data = NULL; + xscale->trace.image = NULL; + xscale->trace.buffer_enabled = 0; + xscale->trace.buffer_fill = 0; + + /* prepare ARMv4/5 specific information */ + armv4_5->arch_info = xscale; + armv4_5->read_core_reg = xscale_read_core_reg; + armv4_5->write_core_reg = xscale_write_core_reg; + armv4_5->full_context = xscale_full_context; + + armv4_5_init_arch_info(target, armv4_5); + + xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; + xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; + xscale->armv4_5_mmu.read_memory = xscale_read_memory; + xscale->armv4_5_mmu.write_memory = xscale_write_memory; + xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; + xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; + xscale->armv4_5_mmu.has_tiny_pages = 1; + xscale->armv4_5_mmu.mmu_enabled = 0; + + xscale->fast_memory_access = 0; + + return ERROR_OK; +} + +/* target xscale */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + xscale_common_t *xscale = malloc(sizeof(xscale_common_t)); + + if (argc < 5) + { + ERROR("'target xscale' requires four arguments: "); + return ERROR_OK; + } + + chain_pos = strtoul(args[3], NULL, 0); + + variant = args[4]; + + xscale_init_arch_info(target, xscale, chain_pos, variant); + xscale_build_reg_cache(target); + + return ERROR_OK; +} + +int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 handler_address; + + if (argc < 2) + { + ERROR("'xscale debug_handler
' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + handler_address = strtoul(args[1], NULL, 0); + + if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || + ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) + { + xscale->handler_address = handler_address; + } + else + { + ERROR("xscale debug_handler
must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); + } + + return ERROR_OK; +} + +int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 cache_clean_address; + + if (argc < 2) + { + ERROR("'xscale cache_clean_address
' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + cache_clean_address = strtoul(args[1], NULL, 0); + + if (cache_clean_address & 0xffff) + { + ERROR("xscale cache_clean_address
must be 64kb aligned"); + } + else + { + xscale->cache_clean_address = cache_clean_address; + } + + return ERROR_OK; +} + +int xscale_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache); +} + +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + + *physical = ret; + return ERROR_OK; +} + +static int xscale_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + + *enabled = xscale->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} + +int xscale_handle_mmu_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 0; + } + } + + command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_idcache_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; + xscale_common_t *xscale; + int icache = 0, dcache = 0; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (strcmp(cmd, "icache") == 0) + icache = 1; + else if (strcmp(cmd, "dcache") == 0) + dcache = 1; + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + } + } + + if (icache) + command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled"); + + if (dcache) + command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_vector_catch_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale vector_catch [mask]"); + } + else + { + xscale->vector_catch = strtoul(args[0], NULL, 0); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); + xscale_write_dcsr(target, -1, -1); + } + + command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch); + + return ERROR_OK; +} + +int xscale_handle_force_hw_bkpts_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 1; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 0; + } + else + { + command_print(cmd_ctx, "usage: xscale force_hw_bkpts "); + } + + command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_trace_buffer_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; + xscale_common_t *xscale; + u32 dcsr_value; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale_trace_data_t *td, *next_td; + xscale->trace.buffer_enabled = 1; + + /* free old trace data */ + td = xscale->trace.data; + while (td) + { + next_td = td->next; + + if (td->entries) + free(td->entries); + free(td); + td = next_td; + } + xscale->trace.data = NULL; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->trace.buffer_enabled = 0; + } + + if ((argc >= 2) && (strcmp("fill", args[1]) == 0)) + { + if (argc >= 3) + xscale->trace.buffer_fill = strtoul(args[2], NULL, 0); + else + xscale->trace.buffer_fill = 1; + } + else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0)) + { + xscale->trace.buffer_fill = -1; + } + + if (xscale->trace.buffer_enabled) + { + /* if we enable the trace buffer in fill-once + * mode we know the address of the first instruction */ + xscale->trace.pc_ok = 1; + xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + else + { + /* otherwise the address is unknown, and we have no known good PC */ + xscale->trace.pc_ok = 0; + } + + command_print(cmd_ctx, "trace buffer %s (%s)", + (xscale->trace.buffer_enabled) ? "enabled" : "disabled", + (xscale->trace.buffer_fill > 0) ? "fill" : "wrap"); + + dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); + if (xscale->trace.buffer_fill >= 0) + xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); + else + xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); + + return ERROR_OK; +} + +int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale trace_image [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (xscale->trace.image) + { + image_close(xscale->trace.image); + free(xscale->trace.image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + xscale->trace.image = malloc(sizeof(image_t)); + xscale->trace.image->base_address_set = 0; + xscale->trace.image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + xscale->trace.image->base_address_set = 1; + xscale->trace.image->base_address = strtoul(args[1], NULL, 0); + } + else + { + xscale->trace.image->base_address_set = 0; + } + + if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str); + free(xscale->trace.image); + xscale->trace.image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_handle_dump_trace_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; + xscale_common_t *xscale; + xscale_trace_data_t *trace_data; + fileio_t file; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale dump_trace "); + return ERROR_OK; + } + + trace_data = xscale->trace.data; + + if (!trace_data) + { + command_print(cmd_ctx, "no trace data collected"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + while (trace_data) + { + int i; + + fileio_write_u32(&file, trace_data->chkpt0); + fileio_write_u32(&file, trace_data->chkpt1); + fileio_write_u32(&file, trace_data->last_instruction); + fileio_write_u32(&file, trace_data->depth); + + for (i = 0; i < trace_data->depth; i++) + fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); + + trace_data = trace_data->next; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int xscale_handle_analyze_trace_buffer_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + xscale_analyze_trace(target, cmd_ctx); + + return ERROR_OK; +} + +int xscale_handle_cp15(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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + u32 reg_no = 0; + reg_t *reg = NULL; + if(argc > 0) + { + reg_no = strtoul(args[0], NULL, 0); + /*translate from xscale cp15 register no to openocd register*/ + switch(reg_no) + { + case 0: + reg_no = XSCALE_MAINID; + break; + case 1: + reg_no = XSCALE_CTRL; + break; + case 2: + reg_no = XSCALE_TTB; + break; + case 3: + reg_no = XSCALE_DAC; + break; + case 5: + reg_no = XSCALE_FSR; + break; + case 6: + reg_no = XSCALE_FAR; + break; + case 13: + reg_no = XSCALE_PID; + break; + case 15: + reg_no = XSCALE_CPACCESS; + break; + default: + command_print(cmd_ctx, "invalid register number"); + return ERROR_INVALID_ARGUMENTS; + } + reg = &xscale->reg_cache->reg_list[reg_no]; + + } + if(argc == 1) + { + u32 value; + + /* read cp15 control register */ + xscale_get_reg(reg); + value = buf_get_u32(reg->value, 0, 32); + command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value); + } + else if(argc == 2) + { + + u32 value = strtoul(args[1], NULL, 0); + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, reg_no); + + /* send CP register value */ + xscale_send_u32(target, value); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); + } + else + { + command_print(cmd_ctx, "usage: cp15 [register]<, [value]>"); + } + + return ERROR_OK; +} + +int handle_xscale_fast_memory_access_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; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc == 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale->fast_memory_access = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale->fast_memory_access = 0; + } + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (argc!=0) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *xscale_cmd; + + xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands"); + + register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler
' command takes two required operands"); + register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL); + + register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU"); + register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache"); + register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache"); + + register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, " of vectors that should be catched"); + + register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, " ['fill' [n]|'wrap']"); + + register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to "); + register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer"); + register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command, + COMMAND_EXEC, "load image from [base address]"); + + register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 [value]"); + register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command, + COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses "); + + armv4_5_register_commands(cmd_ctx); + + return ERROR_OK; +} -- cgit v1.2.3