X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fcortex_a.c;h=6b76656b91e0c52c0211e11486e920367257e9d3;hb=9e7b31479ba7100f41a5b88b32571cf765cdb3ee;hp=bd8e49fd9e5c0d990a1adfec71003e819de7613a;hpb=99add6227fe0a3be536f9b83ff6aa7dd63a8d2dc;p=openocd.git diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bd8e49fd9e..6b76656b91 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -23,6 +23,9 @@ * Copyright (C) 2013 Kamal Dasu * * kdasu.kdev@gmail.com * * * + * Copyright (C) 2016 Chengyu Zheng * + * chengyu.zheng@polimi.it : watchpoint support * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -58,6 +61,7 @@ #include "jtag/interface.h" #include "transport/transport.h" #include "smp.h" +#include #include static int cortex_a_poll(struct target *target); @@ -80,6 +84,16 @@ static int cortex_a_virt2phys(struct target *target, static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); +static unsigned int ilog2(unsigned int x) +{ + unsigned int y = 0; + x /= 2; + while (x) { + ++y; + x /= 2; + } + return y; +} /* restore cp15_control_reg at resume */ static int cortex_a_restore_cp15_control_reg(struct target *target) @@ -1115,7 +1129,8 @@ static int cortex_a_post_debug_entry(struct target *target) return ERROR_OK; } -int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) +static int cortex_a_set_dscr_bits(struct target *target, + unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; @@ -1657,6 +1672,200 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * return ERROR_OK; } +/** + * Sets a watchpoint for an Cortex-A target in one of the watchpoint units. It is + * considered a bug to call this function when there are no available watchpoint + * units. + * + * @param target Pointer to an Cortex-A target to set a watchpoint on + * @param watchpoint Pointer to the watchpoint to be set + * @return Error status if watchpoint set fails or the result of executing the + * JTAG queue + */ +static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + int retval = ERROR_OK; + int wrp_i = 0; + uint32_t control; + uint32_t address; + uint8_t address_mask; + uint8_t byte_address_select; + uint8_t load_store_access_control = 0x3; + 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 already set"); + return retval; + } + + /* check available context WRPs */ + 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_FAIL; + } + + if (watchpoint->length == 0 || watchpoint->length > 0x80000000U || + (watchpoint->length & (watchpoint->length - 1))) { + LOG_WARNING("watchpoint length must be a power of 2"); + return ERROR_FAIL; + } + + if (watchpoint->address & (watchpoint->length - 1)) { + LOG_WARNING("watchpoint address must be aligned at length"); + return ERROR_FAIL; + } + + /* FIXME: ARM DDI 0406C: address_mask is optional. What to do if it's missing? */ + /* handle wp length 1 and 2 through byte select */ + switch (watchpoint->length) { + case 1: + byte_address_select = BIT(watchpoint->address & 0x3); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 2: + byte_address_select = 0x03 << (watchpoint->address & 0x2); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 4: + byte_address_select = 0x0f; + address = watchpoint->address; + address_mask = 0; + break; + + default: + byte_address_select = 0xff; + address = watchpoint->address; + address_mask = ilog2(watchpoint->length); + break; + } + + watchpoint->set = wrp_i + 1; + control = (address_mask << 24) | + (byte_address_select << 5) | + (load_store_access_control << 3) | + (0x3 << 1) | 1; + wrp_list[wrp_i].used = 1; + wrp_list[wrp_i].value = address; + 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; + + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, + wrp_list[wrp_i].control, + wrp_list[wrp_i].value); + + return ERROR_OK; +} + +/** + * Unset an existing watchpoint and clear the used watchpoint unit. + * + * @param target Pointer to the target to have the watchpoint removed + * @param watchpoint Pointer to the watchpoint to be removed + * @return Error status while trying to unset the watchpoint or the result of + * executing the JTAG queue + */ +static 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 WRP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("wrp %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; +} + +/** + * Add a watchpoint to an Cortex-A target. If there are no watchpoint units + * available, an error response is returned. + * + * @param target Pointer to the Cortex-A target to add a watchpoint to + * @param watchpoint Pointer to the watchpoint to be added + * @return Error status while trying to add the watchpoint + */ +static 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 watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + int retval = cortex_a_set_watchpoint(target, watchpoint); + if (retval != ERROR_OK) + return retval; + + cortex_a->wrp_num_available--; + return ERROR_OK; +} + +/** + * Remove a watchpoint from an Cortex-A target. The watchpoint will be unset and + * the used watchpoint unit will be reopened. + * + * @param target Pointer to the target to remove a watchpoint from + * @param watchpoint Pointer to the watchpoint to be removed + * @return Result of trying to unset the watchpoint + */ +static 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) { + cortex_a->wrp_num_available++; + cortex_a_unset_watchpoint(target, watchpoint); + } + return ERROR_OK; +} + + /* * Cortex-A Reset functions */ @@ -1680,10 +1889,10 @@ static int cortex_a_assert_reset(struct target *target) */ /* - * FIXME: fix reset when transport is SWD. This is a temporary + * FIXME: fix reset when transport is not JTAG. This is a temporary * work-around for release v0.10 that is not intended to stay! */ - if (transport_is_swd() || + if (!transport_is_jtag() || (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) adapter_assert_reset(); @@ -2836,6 +3045,20 @@ static int cortex_a_examine_first(struct target *target) LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num); + /* Setup Watchpoint Register Pairs */ + 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[i].used = 0; + cortex_a->wrp_list[i].value = 0; + cortex_a->wrp_list[i].control = 0; + cortex_a->wrp_list[i].WRPn = i; + } + + LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num); + /* select debug_ap as default */ swjdp->apsel = armv7a->debug_ap->ap_num; @@ -2958,6 +3181,7 @@ static void cortex_a_deinit_target(struct target *target) dscr & ~DSCR_HALT_DBG_MODE); } + free(cortex_a->wrp_list); free(cortex_a->brp_list); arm_free_reg_cache(dpm->arm); free(dpm->dbp); @@ -3035,15 +3259,15 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const Jim_Nvp nvp_maskisr_modes[] = { + static const struct jim_nvp nvp_maskisr_modes[] = { { .name = "off", .value = CORTEX_A_ISRMASK_OFF }, { .name = "on", .value = CORTEX_A_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const Jim_Nvp *n; + const struct jim_nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); if (n->name == NULL) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -3052,7 +3276,7 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) cortex_a->isrmasking_mode = n->value; } - n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); + n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; @@ -3063,22 +3287,22 @@ COMMAND_HANDLER(handle_cortex_a_dacrfixup_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const Jim_Nvp nvp_dacrfixup_modes[] = { + static const struct jim_nvp nvp_dacrfixup_modes[] = { { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF }, { .name = "on", .value = CORTEX_A_DACRFIXUP_ON }, { .name = NULL, .value = -1 }, }; - const Jim_Nvp *n; + const struct jim_nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); + n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); if (n->name == NULL) return ERROR_COMMAND_SYNTAX_ERROR; cortex_a->dacrfixup_mode = n->value; } - n = Jim_Nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); + n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); command_print(CMD, "cortex_a domain access control fixup %s", n->name); return ERROR_OK; @@ -3142,7 +3366,6 @@ static const struct command_registration cortex_a_command_handlers[] = { struct target_type cortexa_target = { .name = "cortex_a", - .deprecated_name = "cortex_a8", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, @@ -3173,8 +3396,8 @@ struct target_type cortexa_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, @@ -3250,8 +3473,8 @@ struct target_type cortexr4_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create,