X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fxscale.c;h=c0080b2b388c7c1b3d80e6ca0e7942e6c3e4dae5;hb=ee17d5c48eaca42438663405ff6d090a391fc9e6;hp=ddc73d20cd6538ae858718b65b849c2fc5aeb648;hpb=ee139164114460d5c4c1a720e28740a7dceca712;p=openocd.git diff --git a/src/target/xscale.c b/src/target/xscale.c index ddc73d20cd..c0080b2b38 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -2002,25 +2002,33 @@ static int xscale_bulk_write_memory(struct target *target, uint32_t address, return xscale_write_memory(target, address, 4, count, buffer); } -static uint32_t xscale_get_ttb(struct target *target) +static int xscale_get_ttb(struct target *target, uint32_t *result) { struct xscale_common *xscale = target_to_xscale(target); uint32_t ttb; + int retval; - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); + retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); + if (retval != ERROR_OK) + return retval; ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); - return ttb; + *result = ttb; + + return ERROR_OK; } -static void xscale_disable_mmu_caches(struct target *target, int mmu, +static int xscale_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; + int retval; /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + if (retval !=ERROR_OK) + return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) @@ -2029,11 +2037,17 @@ static void xscale_disable_mmu_caches(struct target *target, int mmu, if (d_u_cache) { /* clean DCache */ - xscale_send_u32(target, 0x50); - xscale_send_u32(target, xscale->cache_clean_address); + retval = xscale_send_u32(target, 0x50); + if (retval !=ERROR_OK) + return retval; + retval = xscale_send_u32(target, xscale->cache_clean_address); + if (retval !=ERROR_OK) + return retval; /* invalidate DCache */ - xscale_send_u32(target, 0x51); + retval = xscale_send_u32(target, 0x51); + if (retval !=ERROR_OK) + return retval; cp15_control &= ~0x4U; } @@ -2041,25 +2055,33 @@ static void xscale_disable_mmu_caches(struct target *target, int mmu, if (i_cache) { /* invalidate ICache */ - xscale_send_u32(target, 0x52); + retval = xscale_send_u32(target, 0x52); + if (retval !=ERROR_OK) + return retval; cp15_control &= ~0x1000U; } /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + if (retval !=ERROR_OK) + return retval; /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); + retval = xscale_send_u32(target, 0x53); + return retval; } -static void xscale_enable_mmu_caches(struct target *target, int mmu, +static int xscale_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; + int retval; /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + if (retval !=ERROR_OK) + return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) @@ -2072,10 +2094,13 @@ static void xscale_enable_mmu_caches(struct target *target, int mmu, cp15_control |= 0x1000U; /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + if (retval !=ERROR_OK) + return retval; /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); + retval = xscale_send_u32(target, 0x53); + return retval; } static int xscale_set_breakpoint(struct target *target, @@ -2266,7 +2291,7 @@ static int xscale_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); - uint8_t enable = 0; + uint32_t enable = 0; struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); @@ -2276,8 +2301,6 @@ static int xscale_set_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - xscale_get_reg(dbcon); - switch (watchpoint->rw) { case WPT_READ: @@ -2293,6 +2316,24 @@ static int xscale_set_watchpoint(struct target *target, LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } + /* For watchpoint across more than one word, both DBR registers must + be enlisted, with the second used as a mask. */ + if (watchpoint->length > 4) + { + if (xscale->dbr0_used || xscale->dbr1_used) + { + LOG_ERROR("BUG: sufficient hardware comparators unavailable"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Write mask value to DBR1, based on the length argument. + * Address bits ignored by the comparator are those set in mask. */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], + watchpoint->length - 1); + xscale->dbr1_used = 1; + enable |= 0x100; /* DBCON[M] */ + } + if (!xscale->dbr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); @@ -2312,7 +2353,7 @@ static int xscale_set_watchpoint(struct target *target, else { LOG_ERROR("BUG: no hardware comparator available"); - return ERROR_OK; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return ERROR_OK; @@ -2328,13 +2369,30 @@ static int xscale_add_watchpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) + if (watchpoint->value) + LOG_WARNING("xscale does not support value, mask arguments; ignoring"); + + /* check that length is a power of two */ + for (uint32_t len = watchpoint->length; len != 1; len /= 2) { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + if (len % 2) + { + LOG_ERROR("xscale requires that watchpoint length is a power of two"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } } - xscale->dbr_available--; + if (watchpoint->length == 4) /* single word watchpoint */ + { + xscale->dbr_available--; /* one DBR reg used */ + return ERROR_OK; + } + /* watchpoints across multiple words require both DBR registers */ + if (xscale->dbr_available < 2) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + xscale->dbr_available = 0; return ERROR_OK; } @@ -2359,7 +2417,14 @@ static int xscale_unset_watchpoint(struct target *target, if (watchpoint->set == 1) { - dbcon_value &= ~0x3; + if (watchpoint->length > 4) + { + dbcon_value &= ~0x103; /* clear DBCON[M] as well */ + xscale->dbr1_used = 0; /* DBR1 was used for mask */ + } + else + dbcon_value &= ~0x3; + xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; } @@ -2389,6 +2454,9 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa xscale_unset_watchpoint(target, watchpoint); } + if (watchpoint->length > 4) + xscale->dbr_available++; /* both DBR regs now available */ + xscale->dbr_available++; return ERROR_OK; @@ -3173,21 +3241,18 @@ static int xscale_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) { struct xscale_common *xscale = target_to_xscale(target); - int type; uint32_t cb; - int domain; - uint32_t ap; if (xscale->common_magic != XSCALE_COMMON_MAGIC) { LOG_ERROR(xscale_not); return ERROR_TARGET_INVALID; } - uint32_t ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); - if (type == -1) - { - return ret; - } + uint32_t ret; + int retval = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, + virtual, &cb, &ret); + if (retval != ERROR_OK) + return retval; *physical = ret; return ERROR_OK; }