flash/nor: Add erased_value to drivers and pass it to targets
struct flash_driver has a default_padded_value field that is similar, but it can be changed by the user for the specific purpose of padding. Add a new erased_value field and initialize it for all targets, particularly stm32lx, xmc4xxx and virtual. Use this value in core.c:default_flash_mem_blank_check(), the slow path. Extend the target API to pass erased_value down to target code. Adding an argument ensures that we catch all callers. This allows us to merge xmc4xxx.c:xmc4xxx_blank_check_memory() into armv7m:armv7m_blank_check_memory(). It further allows us to use default_flash_blank_check() in place of xmc4xxx.c:xmc4xxx_flash_blank_check(), adding a potential slow path fallback, as well as stm32lx:stm32lx_erase_check(), adding the potential armv7m fast path with fallback to default_flash_mem_blank_check(). Fix a mips32 code comment while at it (zeroed -> erased). The armv4_5 and mips32 target implementations will now error out if an erase value other than 0xff is used, causing default_flash_blank_check() to fall back to the default_flank_mem_blank_check() slow path. Change-Id: I39323fbbc4b71c256cd567e439896d0245d4745f Signed-off-by: Andreas Färber <afaerber@suse.de> Reviewed-on: http://openocd.zylin.com/3497 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
parent
b9ee6dd465
commit
eaacb900dd
|
@ -661,7 +661,7 @@ static int at91sam7_erase_check(struct flash_bank *bank)
|
|||
retval = target_blank_check_memory(target,
|
||||
bank->base + bank->sectors[nSector].offset,
|
||||
bank->sectors[nSector].size,
|
||||
&blank);
|
||||
&blank, bank->erased_value);
|
||||
if (retval != ERROR_OK) {
|
||||
fast_check = 0;
|
||||
break;
|
||||
|
|
|
@ -288,7 +288,7 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
|
|||
goto done;
|
||||
|
||||
for (nBytes = 0; nBytes < chunk; nBytes++) {
|
||||
if (buffer[nBytes] != 0xFF) {
|
||||
if (buffer[nBytes] != bank->erased_value) {
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -319,12 +319,12 @@ int default_flash_blank_check(struct flash_bank *bank)
|
|||
uint32_t address = bank->base + bank->sectors[i].offset;
|
||||
uint32_t size = bank->sectors[i].size;
|
||||
|
||||
retval = target_blank_check_memory(target, address, size, &blank);
|
||||
retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value);
|
||||
if (retval != ERROR_OK) {
|
||||
fast_check = 0;
|
||||
break;
|
||||
}
|
||||
if (blank == 0xFF)
|
||||
if (blank == bank->erased_value)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
bank->sectors[i].is_erased = 0;
|
||||
|
|
|
@ -90,6 +90,9 @@ struct flash_bank {
|
|||
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
|
||||
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
|
||||
|
||||
/** Erased value. Defaults to 0xFF. */
|
||||
uint8_t erased_value;
|
||||
|
||||
/** Default padded value used, normally this matches the flash
|
||||
* erased value. Defaults to 0xFF. */
|
||||
uint8_t default_padded_value;
|
||||
|
|
|
@ -300,7 +300,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
|
|||
stm32lx_info->user_bank_size = bank->size;
|
||||
|
||||
/* the stm32l erased value is 0x00 */
|
||||
bank->default_padded_value = 0x00;
|
||||
bank->default_padded_value = bank->erased_value = 0x00;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -884,56 +884,6 @@ static int stm32lx_auto_probe(struct flash_bank *bank)
|
|||
return stm32lx_probe(bank);
|
||||
}
|
||||
|
||||
static int stm32lx_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
const int buffer_size = 4096;
|
||||
int i;
|
||||
uint32_t nBytes;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
uint8_t *buffer = malloc(buffer_size);
|
||||
if (buffer == NULL) {
|
||||
LOG_ERROR("failed to allocate read buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
uint32_t j;
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
/* Loop chunk by chunk over the sector */
|
||||
for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
|
||||
uint32_t chunk;
|
||||
chunk = buffer_size;
|
||||
if (chunk > (j - bank->sectors[i].size))
|
||||
chunk = (j - bank->sectors[i].size);
|
||||
|
||||
retval = target_read_memory(target, bank->base
|
||||
+ bank->sectors[i].offset + j, 4, chunk / 4, buffer);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
for (nBytes = 0; nBytes < chunk; nBytes++) {
|
||||
if (buffer[nBytes] != 0x00) {
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* This method must return a string displaying information about the bank */
|
||||
static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
|
@ -1022,7 +972,7 @@ struct flash_driver stm32lx_flash = {
|
|||
.read = default_flash_read,
|
||||
.probe = stm32lx_probe,
|
||||
.auto_probe = stm32lx_auto_probe,
|
||||
.erase_check = stm32lx_erase_check,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = stm32lx_protect_check,
|
||||
.info = stm32lx_get_info,
|
||||
};
|
||||
|
|
|
@ -1012,7 +1012,7 @@ COMMAND_HANDLER(handle_flash_bank_command)
|
|||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width);
|
||||
c->default_padded_value = 0xff;
|
||||
c->default_padded_value = c->erased_value = 0xff;
|
||||
c->num_sectors = 0;
|
||||
c->sectors = NULL;
|
||||
c->num_prot_blocks = 0;
|
||||
|
|
|
@ -44,6 +44,7 @@ static void virtual_update_bank_info(struct flash_bank *bank)
|
|||
bank->size = master_bank->size;
|
||||
bank->chip_width = master_bank->chip_width;
|
||||
bank->bus_width = master_bank->bus_width;
|
||||
bank->erased_value = master_bank->erased_value;
|
||||
bank->default_padded_value = master_bank->default_padded_value;
|
||||
bank->num_sectors = master_bank->num_sectors;
|
||||
bank->sectors = master_bank->sectors;
|
||||
|
|
|
@ -319,8 +319,8 @@ static int xmc4xxx_load_bank_layout(struct flash_bank *bank)
|
|||
}
|
||||
|
||||
/* This part doesn't follow the typical standard of 0xff
|
||||
* being the default padding value.*/
|
||||
bank->default_padded_value = 0x00;
|
||||
* being the erased value.*/
|
||||
bank->default_padded_value = bank->erased_value = 0x00;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -617,99 +617,6 @@ static int xmc4xxx_enter_page_mode(struct flash_bank *bank)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* The logical erase value of an xmc4xxx memory cell is 0x00,
|
||||
* therefore, we cannot use the built in flash blank check and must
|
||||
* implement our own */
|
||||
|
||||
/** Checks whether a memory region is zeroed. */
|
||||
static int xmc4xxx_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
int retval;
|
||||
|
||||
static const uint8_t erase_check_code[] = {
|
||||
#include "../../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
|
||||
};
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, sizeof(erase_check_code),
|
||||
&erase_check_algorithm) != ERROR_OK)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target_write_buffer(target, erase_check_algorithm->address,
|
||||
sizeof(erase_check_code), (uint8_t *)erase_check_code);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup;
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0x00);
|
||||
|
||||
retval = target_run_algorithm(target,
|
||||
0,
|
||||
NULL,
|
||||
3,
|
||||
reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
|
||||
10000,
|
||||
&armv7m_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
cleanup:
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int xmc4xxx_flash_blank_check(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
int retval = ERROR_OK;
|
||||
uint32_t blank;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
uint32_t address = bank->base + bank->sectors[i].offset;
|
||||
uint32_t size = bank->sectors[i].size;
|
||||
|
||||
LOG_DEBUG("Erase checking 0x%08"PRIx32, address);
|
||||
retval = xmc4xxx_blank_check_memory(target, address, size, &blank);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
if (blank == 0x00)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
bank->sectors[i].is_erased = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int xmc4xxx_write_page(struct flash_bank *bank, const uint8_t *pg_buf,
|
||||
uint32_t offset, bool user_config)
|
||||
{
|
||||
|
@ -1439,7 +1346,7 @@ struct flash_driver xmc4xxx_flash = {
|
|||
.read = default_flash_read,
|
||||
.probe = xmc4xxx_probe,
|
||||
.auto_probe = xmc4xxx_probe,
|
||||
.erase_check = xmc4xxx_flash_blank_check,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.info = xmc4xxx_get_info_command,
|
||||
.protect_check = xmc4xxx_protect_check,
|
||||
.protect = xmc4xxx_protect,
|
||||
|
|
|
@ -232,7 +232,7 @@ int armv4_5_run_algorithm_inner(struct target *target,
|
|||
int arm_checksum_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *checksum);
|
||||
int arm_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank);
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
|
||||
void arm_set_cpsr(struct arm *arm, uint32_t cpsr);
|
||||
struct reg *arm_reg_current(struct arm *arm, unsigned regnum);
|
||||
|
|
|
@ -1486,7 +1486,7 @@ cleanup:
|
|||
*
|
||||
*/
|
||||
int arm_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
|
@ -1502,6 +1502,12 @@ int arm_blank_check_memory(struct target *target,
|
|||
|
||||
assert(sizeof(check_code_le) % 4 == 0);
|
||||
|
||||
if (erased_value != 0xff) {
|
||||
LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets",
|
||||
erased_value);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* make sure we have a working area */
|
||||
retval = target_alloc_working_area(target,
|
||||
sizeof(check_code_le), &check_algorithm);
|
||||
|
@ -1529,7 +1535,7 @@ int arm_blank_check_memory(struct target *target,
|
|||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
|
||||
/* armv4 must exit using a hardware breakpoint */
|
||||
if (arm->is_armv4)
|
||||
|
|
|
@ -726,26 +726,42 @@ cleanup:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/** Checks whether a memory region is zeroed. */
|
||||
/** Checks whether a memory region is erased. */
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
const uint8_t *code;
|
||||
uint32_t code_size;
|
||||
int retval;
|
||||
|
||||
static const uint8_t erase_check_code[] = {
|
||||
#include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
|
||||
};
|
||||
static const uint8_t zero_erase_check_code[] = {
|
||||
#include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
|
||||
};
|
||||
|
||||
switch (erased_value) {
|
||||
case 0x00:
|
||||
code = zero_erase_check_code;
|
||||
code_size = sizeof(zero_erase_check_code);
|
||||
break;
|
||||
case 0xff:
|
||||
default:
|
||||
code = erase_check_code;
|
||||
code_size = sizeof(erase_check_code);
|
||||
}
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, sizeof(erase_check_code),
|
||||
if (target_alloc_working_area(target, code_size,
|
||||
&erase_check_algorithm) != ERROR_OK)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target_write_buffer(target, erase_check_algorithm->address,
|
||||
sizeof(erase_check_code), (uint8_t *)erase_check_code);
|
||||
code_size, code);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup;
|
||||
|
||||
|
@ -759,7 +775,7 @@ int armv7m_blank_check_memory(struct target *target,
|
|||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
|
||||
retval = target_run_algorithm(target,
|
||||
0,
|
||||
|
@ -767,7 +783,7 @@ int armv7m_blank_check_memory(struct target *target,
|
|||
3,
|
||||
reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
|
||||
erase_check_algorithm->address + (code_size - 2),
|
||||
10000,
|
||||
&armv7m_info);
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ int armv7m_restore_context(struct target *target);
|
|||
int armv7m_checksum_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *checksum);
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank);
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
|
||||
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found);
|
||||
|
||||
|
|
|
@ -771,9 +771,9 @@ int mips32_checksum_memory(struct target *target, uint32_t address,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/** Checks whether a memory region is zeroed. */
|
||||
/** Checks whether a memory region is erased. */
|
||||
int mips32_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
|
@ -789,6 +789,12 @@ int mips32_blank_check_memory(struct target *target,
|
|||
0x7000003F /* sdbbp */
|
||||
};
|
||||
|
||||
if (erased_value != 0xff) {
|
||||
LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for MIPS32",
|
||||
erased_value);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
@ -810,7 +816,7 @@ int mips32_blank_check_memory(struct target *target,
|
|||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, erased_value);
|
||||
|
||||
int retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
erase_check_algorithm->address,
|
||||
|
|
|
@ -249,6 +249,6 @@ int mips32_get_gdb_reg_list(struct target *target,
|
|||
int mips32_checksum_memory(struct target *target, uint32_t address,
|
||||
uint32_t count, uint32_t *checksum);
|
||||
int mips32_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank);
|
||||
uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
|
||||
#endif /* OPENOCD_TARGET_MIPS32_H */
|
||||
|
|
|
@ -2178,7 +2178,8 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz
|
|||
return retval;
|
||||
}
|
||||
|
||||
int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank)
|
||||
int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank,
|
||||
uint8_t erased_value)
|
||||
{
|
||||
int retval;
|
||||
if (!target_was_examined(target)) {
|
||||
|
@ -2189,7 +2190,7 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t
|
|||
if (target->type->blank_check_memory == 0)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target->type->blank_check_memory(target, address, size, blank);
|
||||
retval = target->type->blank_check_memory(target, address, size, blank, erased_value);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -579,7 +579,7 @@ int target_read_buffer(struct target *target,
|
|||
int target_checksum_memory(struct target *target,
|
||||
uint32_t address, uint32_t size, uint32_t *crc);
|
||||
int target_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t size, uint32_t *blank);
|
||||
uint32_t address, uint32_t size, uint32_t *blank, uint8_t erased_value);
|
||||
int target_wait_state(struct target *target, enum target_state state, int ms);
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,7 +131,7 @@ struct target_type {
|
|||
int (*checksum_memory)(struct target *target, uint32_t address,
|
||||
uint32_t count, uint32_t *checksum);
|
||||
int (*blank_check_memory)(struct target *target, uint32_t address,
|
||||
uint32_t count, uint32_t *blank);
|
||||
uint32_t count, uint32_t *blank, uint8_t erased_value);
|
||||
|
||||
/*
|
||||
* target break-/watchpoint control
|
||||
|
|
Loading…
Reference in New Issue