SparkFun Forums 

Where electronics enthusiasts find answers.

Open source ARM Debugger
By fatalfeel
#187676
how to implement in cortex_a.c ?

////
in cortex_m.h
#define DWT_COMP0 0xE0001020
#define DWT_MASK0 0xE0001024
#define DWT_FUNCTION0 0xE0001028
//
in cortex_m.c
for (i = 0; i < cm->dwt_num_comp; i++, comparator++)
{
int j;

comparator->dwt_comparator_address = DWT_COMP0 + 0x10 * i;

for (j = 0; j < 3; j++, reg++)
cortex_m_dwt_addreg(target, cache->reg_list + reg, dwt_comp + 3 * i + j);

target_write_u32(target, comparator->dwt_comparator_address + 8, 0);
}

//do add watchpoint
comparator->comp = watchpoint->address;
target_write_u32(target, comparator->dwt_comparator_address + 0, comparator->comp);

comparator->mask = mask;
target_write_u32(target, comparator->dwt_comparator_address + 4, comparator->mask);

switch (watchpoint->rw)
{
case WPT_READ:
comparator->function = 5;
break;
case WPT_WRITE:
comparator->function = 6;
break;
case WPT_ACCESS:
comparator->function = 7;
break;
}

target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function);

////////////////////////////
in armv7a.h for cortex a8 a9
#define CPUDBG_WVR_BASE 0x180
#define CPUDBG_WCR_BASE 0x1C0

how to implement in cortex_a.c ?
1. the address/mask/function is CPUDBG_WVR_BASE+0 / CPUDBG_WVR_BASE+4 / CPUDBG_WVR_BASE+8 ?
2. the address/mask/function is CPUDBG_WCR_BASE+0 ......+4......+8?
3. WPT_READ/WPT_WRITE/WPT_ACCESS is 5/6/7 on cortex a8 a9?
Last edited by fatalfeel on Tue Feb 09, 2016 12:04 pm, edited 1 time in total.
By fatalfeel
#187678
ok may a little idea here
break
http://infocenter.arm.com/help/index.js ... cdabj.html
watch
http://infocenter.arm.com/help/index.js ... hjfhh.html

looks
break point reg / watch point reg
Breakpoint address mask = Watchpoint address mask
Secure state access control = Secure state access control
Byte address select = Byte address select
sp =sp
B = W

only implement watch point L/S -> Load store access

good~~~ will do it right~~~
Last edited by fatalfeel on Thu Feb 04, 2016 12:46 pm, edited 1 time in total.
By fatalfeel
#187681
//ok done
you need use eclipse into GDB HARDWARE DEBUGGING console key in
After trigger watchpoint you must remove again or will be looping trigger


monitor wp address sizeof(unit) r/w/a(read/write/access)
ex:
//add wtahcpoint on 0x8144be4c sizeof(unsigned int) access
monitor wp 0x8144be4c 4 a
monitor wp 0x8144be4c 4 w

//remove wtahcpoint on 0x8144be4c
monitor rwp 0x8144be4c

patch
http://fatalfeel.blogspot.tw/2015/12/op ... el-of.html

demo photo:
https://picasaweb.google.com/1061855410 ... 8141165858
Last edited by fatalfeel on Thu Jan 28, 2016 11:51 pm, edited 3 times in total.
By fatalfeel
#187682
int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
int retval;
int wrp_i = 0;
uint32_t control;
uint8_t access_mode;
uint8_t byte_addr_select = 0x0F;
struct cortex_a_common* cortex_a = target_to_cortex_a(target);
struct armv7a_common* armv7a = &cortex_a->armv7a_common;
struct cortex_a_wrp* wrp_list = cortex_a->wrp_list;

if (watchpoint->set)
{
LOG_WARNING("breakpoint already set");
return ERROR_OK;
}

while (wrp_list[wrp_i].used && (wrp_i < cortex_a->wrp_num))
wrp_i++;

if (wrp_i >= cortex_a->wrp_num)
{
LOG_ERROR("ERROR Can not find free Watchpoint Register Pair");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}

watchpoint->set = wrp_i + 1;

if (watchpoint->length == 2)
byte_addr_select = (3 << (watchpoint->address & 0x02));

access_mode = watchpoint->rw+1;
control = (byte_addr_select << 5) | (access_mode << 3) | (3 << 1) | 1;
wrp_list[wrp_i].used = 1;
wrp_list[wrp_i].value = (watchpoint->address & 0xFFFFFFFC);
wrp_list[wrp_i].control = control;

retval = cortex_a_dap_write_memap_register_u32(target,
armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].WRPn,
wrp_list[wrp_i].value);
if (retval != ERROR_OK)
return retval;

retval = cortex_a_dap_write_memap_register_u32(target,
armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].WRPn,
wrp_list[wrp_i].control);

if (retval != ERROR_OK)
return retval;

return ERROR_OK;
}

int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
int retval;
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct cortex_a_wrp *wrp_list = cortex_a->wrp_list;

if (!watchpoint->set)
{
LOG_WARNING("watchpoint not set");
return ERROR_OK;
}


int wrp_i = watchpoint->set - 1;

if ((wrp_i < 0) || (wrp_i >= cortex_a->wrp_num))
{
LOG_DEBUG("Invalid BRP number in watchpoint");
return ERROR_OK;
}

LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, wrp_list[wrp_i].control, wrp_list[wrp_i].value);

wrp_list[wrp_i].used = 0;
wrp_list[wrp_i].value = 0;
wrp_list[wrp_i].control = 0;

retval = cortex_a_dap_write_memap_register_u32(target,
armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].WRPn,
wrp_list[wrp_i].control);
if (retval != ERROR_OK)
return retval;

retval = cortex_a_dap_write_memap_register_u32(target,
armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].WRPn,
wrp_list[wrp_i].value);
if (retval != ERROR_OK)
return retval;

watchpoint->set = 0;

return ERROR_OK;
}

int cortex_a_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
struct cortex_a_common* cortex_a = target_to_cortex_a(target);

if (cortex_a->wrp_num_available < 1)
{
LOG_INFO("no hardware breakpoint available");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}

//if (breakpoint->type == BKPT_HARD)
cortex_a->wrp_num_available--;

return cortex_a_set_watchpoint(target, watchpoint);
}

int cortex_a_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
struct cortex_a_common* cortex_a = target_to_cortex_a(target);

if (watchpoint->set)
{
//if (breakpoint->type == BKPT_HARD)
cortex_a_unset_watchpoint(target, watchpoint);

cortex_a->wrp_num_available++;
}

return ERROR_OK;
}
By fatalfeel
#187683
struct target_type cortexa_target = {
.name = "cortex_a",
.deprecated_name = "cortex_a8",

.poll = cortex_a_poll,
.arch_state = armv7a_arch_state,

.halt = cortex_a_halt,
.resume = cortex_a_resume,
.step = cortex_a_step,

.assert_reset = cortex_a_assert_reset,
.deassert_reset = cortex_a_deassert_reset,

/* REVISIT allow exporting VFP3 registers ... */
.get_gdb_reg_list = arm_get_gdb_reg_list,

.read_memory = cortex_a_read_memory,
.write_memory = cortex_a_write_memory,

.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,

.run_algorithm = armv4_5_run_algorithm,

.add_breakpoint = cortex_a_add_breakpoint,
.add_context_breakpoint = cortex_a_add_context_breakpoint,
.add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint,
.remove_breakpoint = cortex_a_remove_breakpoint,
.add_watchpoint = cortex_a_add_watchpoint,
.remove_watchpoint = cortex_a_remove_watchpoint,

.commands = cortex_a_command_handlers,
.target_create = cortex_a_target_create,
.init_target = cortex_a_init_target,
.examine = cortex_a_examine,

.read_phys_memory = cortex_a_read_phys_memory,
.write_phys_memory = cortex_a_write_phys_memory,
.mmu = cortex_a_mmu,
.virt2phys = cortex_a_virt2phys,
};
By fatalfeel
#187684
static int cortex_a_examine_first(struct target *target)
{
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct adiv5_dap *swjdp = armv7a->arm.dap;
int i;
int retval = ERROR_OK;
uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg;

/* We do one extra read to ensure DAP is configured,
* we call ahbap_debugport_init(swjdp) instead
*/
retval = ahbap_debugport_init(swjdp);
if (retval != ERROR_OK)
return retval;

/* Search for the APB-AB - it is needed for access to debug registers */
retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
if (retval != ERROR_OK) {
LOG_ERROR("Could not find APB-AP for debug access");
return retval;
}

/* Search for the AHB-AB */
retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap);

if (retval != ERROR_OK)
{
/* AHB-AP not found - use APB-AP */
LOG_DEBUG("Could not find AHB-AP - using APB-AP for memory access");
armv7a->memory_ap_available = false;
}
else
{
armv7a->memory_ap_available = true;
}


if (!target->dbgbase_set) {
uint32_t dbgbase;
/* Get ROM Table base */
uint32_t apid;
int32_t coreidx = target->coreid;
LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table",
target->cmd_name);
retval = dap_get_debugbase(swjdp, 1, &dbgbase, &apid);
if (retval != ERROR_OK)
return retval;
/* Lookup 0x15 -- Processor DAP */
retval = dap_lookup_cs_component(swjdp, 1, dbgbase, 0x15,
&armv7a->debug_base, &coreidx);
if (retval != ERROR_OK) {
LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.",
target->cmd_name);
return retval;
}
LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32,
coreidx, armv7a->debug_base);
} else
armv7a->debug_base = target->dbgbase;

retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_CPUID, &cpuid);
if (retval != ERROR_OK)
return retval;

retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_CPUID, &cpuid);
if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "CPUID");
return retval;
}

retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_CTYPR, &ctypr);
if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "CTYPR");
return retval;
}

retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_TTYPR, &ttypr);
if (retval != ERROR_OK) {
LOG_DEBUG("Examine %s failed", "TTYPR");
return retval;
}

retval = mem_ap_sel_read_atomic_u32(swjdp,
armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DIDR,
&didr);

if (retval != ERROR_OK)
{
LOG_DEBUG("Examine %s failed", "DIDR");
return retval;
}

LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid);
LOG_DEBUG("ctypr = 0x%08" PRIx32, ctypr);
LOG_DEBUG("ttypr = 0x%08" PRIx32, ttypr);
LOG_DEBUG("didr = 0x%08" PRIx32, didr);

cortex_a->cpuid = cpuid;
cortex_a->ctypr = ctypr;
cortex_a->ttypr = ttypr;
cortex_a->didr = didr;

/* Unlocking the debug registers */
if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT ==
CORTEX_A15_PARTNUM) {

retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_OSLAR,
0);

if (retval != ERROR_OK)
return retval;

}
/* Unlocking the debug registers */
if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT ==
CORTEX_A7_PARTNUM) {

retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_OSLAR,
0);

if (retval != ERROR_OK)
return retval;

}
retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg);

if (retval != ERROR_OK)
return retval;

LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg);

armv7a->arm.core_type = ARM_MODE_MON;
retval = cortex_a_dpm_setup(cortex_a, didr);
if (retval != ERROR_OK)
return retval;

/* Setup Breakpoint Register Pairs */
cortex_a->brp_num = ((didr >> 24) & 0x0F) + 1;
cortex_a->brp_num_context = ((didr >> 20) & 0x0F) + 1;
cortex_a->brp_num_available = cortex_a->brp_num;
free(cortex_a->brp_list);
cortex_a->brp_list = calloc(cortex_a->brp_num, sizeof(struct cortex_a_brp));

/* cortex_a->brb_enabled = ????; */
for (i = 0; i < cortex_a->brp_num; i++)
{
cortex_a->brp_list.used = 0;
if (i < (cortex_a->brp_num-cortex_a->brp_num_context))
cortex_a->brp_list.type = BRP_NORMAL;
else
cortex_a->brp_list.type = BRP_CONTEXT;
cortex_a->brp_list.value = 0;
cortex_a->brp_list.control = 0;
cortex_a->brp_list.BRPn = i;
}
LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num);

//////////////////////////////////////////////////////////////////////////////////////
cortex_a->wrp_num = ((didr >> 28) & 0x0F) + 1;
cortex_a->wrp_num_available = cortex_a->wrp_num;
free(cortex_a->wrp_list);
cortex_a->wrp_list = calloc(cortex_a->wrp_num, sizeof(struct cortex_a_wrp));

for (i = 0; i < cortex_a->wrp_num; i++)
{
cortex_a->wrp_list.used = 0;
cortex_a->wrp_list.value = 0;
cortex_a->wrp_list.control = 0;
cortex_a->wrp_list.WRPn = i;
}
LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num);

target_set_examined(target);
return ERROR_OK;
}
Last edited by fatalfeel on Thu Jan 28, 2016 9:19 pm, edited 1 time in total.
By fatalfeel
#187685
struct cortex_a_wrp
{
int used;
uint32_t value;
uint32_t control;
uint8_t WRPn;
};

struct cortex_a_common
{
int common_magic;
struct arm_jtag jtag_info;

/* Context information */
uint32_t cpudbg_dscr;

/* Saved cp15 registers */
uint32_t cp15_control_reg;
/* latest cp15 register value written and cpsr processor mode */
uint32_t cp15_control_reg_curr;
enum arm_mode curr_mode;


/* Breakpoint register pairs */
int brp_num_context;
int brp_num;
int brp_num_available;
struct cortex_a_brp *brp_list;

int wrp_num;
int wrp_num_available;
struct cortex_a_wrp* wrp_list;

/* Use cortex_a_read_regs_through_mem for fast register reads */
int fast_reg_read;

uint32_t cpuid;
uint32_t ctypr;
uint32_t ttypr;
uint32_t didr;

struct armv7a_common armv7a_common;
};
By fatalfeel
#187686
int arm_dpm_setup(struct arm_dpm *dpm)
{
struct arm *arm = dpm->arm;
struct target *target = arm->target;
struct reg_cache *cache;

arm->dpm = dpm;

/* register access setup */
arm->full_context = arm_dpm_full_context;
arm->read_core_reg = arm_dpm_read_core_reg;
arm->write_core_reg = arm_dpm_write_core_reg;

cache = arm_build_reg_cache(target, arm);
if (!cache)
return ERROR_FAIL;

*register_get_last_cache_p(&target->reg_cache) = cache;

/* coprocessor access setup */
arm->mrc = dpm_mrc;
arm->mcr = dpm_mcr;

/* breakpoint setup -- optional until it works everywhere */
if (!target->type->add_breakpoint)
{
target->type->add_breakpoint = dpm_add_breakpoint;
target->type->remove_breakpoint = dpm_remove_breakpoint;
}

/* watchpoint setup */
if (!target->type->add_watchpoint)
{
target->type->add_watchpoint = dpm_add_watchpoint;
target->type->remove_watchpoint = dpm_remove_watchpoint;
}

/* FIXME add vector catch support */

dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);

dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);

if (!dpm->dbp || !dpm->dwp) {
free(dpm->dbp);
free(dpm->dwp);
return ERROR_FAIL;
}

LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
target_name(target), dpm->nbp, dpm->nwp);

/* REVISIT ... and some of those breakpoints could match
* execution context IDs...
*/

return ERROR_OK;
}