2
0
mirror of git://git.code.sf.net/p/openocd/code synced 2025-08-15 15:33:46 +10:00

flash/nor/tcl: Add 'read_memory' command

This command allows to read non-memory mapped flash content directly
via Tcl script. The API is the same as for the 'read_memory' command
for targets.

Change-Id: I4a8d0d7ea2f778ac8f1501227b60b964c881cb84
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: https://review.openocd.org/c/openocd/+/8634
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Marc Schink 2024-11-23 14:43:51 +00:00 committed by Antonio Borneo
parent 2065bac380
commit 6a40fe64d6
2 changed files with 143 additions and 0 deletions

View File

@ -5870,6 +5870,24 @@ The flash bank to use is inferred from the @var{address} of
each block, and the specified length must stay within that bank.
@end deffn
@deffn {Command} {flash read_memory} address width count
This function provides an efficient way to read flash memory from a Tcl script.
A Tcl list containing the requested memory elements is returned by this function.
@itemize
@item @var{address} ... flash memory address
@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64
@item @var{count} ... number of elements to read
@end itemize
For example, the following command reads two 32 bit words from the flash
memory at address 0x08000000:
@example
flash read_memory 0x08000000 32 2
@end example
@end deffn
@deffn {Command} {flash write_bank} num filename [offset]
Write the binary @file{filename} to flash bank @var{num},
starting at @var{offset} bytes from the beginning of the bank. If @var{offset}

View File

@ -727,6 +727,124 @@ COMMAND_HANDLER(handle_flash_md_command)
return retval;
}
COMMAND_HANDLER(handle_flash_read_memory_command)
{
/*
* CMD_ARGV[0] = memory address
* CMD_ARGV[1] = desired element width in bits
* CMD_ARGV[2] = number of elements to read
*/
if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
/* Arg 1: Memory address. */
target_addr_t addr;
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr);
/* Arg 2: Bit width of one element. */
unsigned int width_bits;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits);
/* Arg 3: Number of elements to read. */
unsigned int count;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count);
switch (width_bits) {
case 8:
case 16:
case 32:
case 64:
break;
default:
command_print(CMD, "invalid width, must be 8, 16, 32 or 64");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (count > 65536) {
command_print(CMD, "too large read request, exceeds 64K elements");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
const unsigned int width = width_bits / 8;
/* -1 is needed to handle cases when (addr + count * width) results in zero
* due to overflow.
*/
if ((addr + count * width - 1) < addr) {
command_print(CMD, "memory region wraps over address zero");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
struct target *target = get_current_target(CMD_CTX);
struct flash_bank *bank;
int retval = get_flash_bank_by_addr(target, addr, true, &bank);
if (retval != ERROR_OK)
return retval;
uint32_t offset = addr - bank->base;
uint32_t sizebytes = count * width_bits;
if (offset + sizebytes > bank->size) {
command_print(CMD, "cannot cross flash bank borders");
return ERROR_FAIL;
}
const size_t buffer_size = 4096;
uint8_t *buffer = malloc(buffer_size);
if (!buffer) {
command_print(CMD, "failed to allocate memory");
return ERROR_FAIL;
}
char *separator = "";
while (count > 0) {
const unsigned int max_chunk_len = buffer_size / width;
const size_t chunk_len = MIN(count, max_chunk_len);
retval = flash_driver_read(bank, buffer, offset, chunk_len * width);
if (retval != ERROR_OK) {
LOG_DEBUG("read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
addr, width_bits, chunk_len);
/*
* FIXME: we append the errmsg to the list of value already read.
* Add a way to flush and replace old output, but LOG_DEBUG() it
*/
command_print(CMD, "failed to read memory");
free(buffer);
return retval;
}
for (size_t i = 0; i < chunk_len ; i++) {
uint64_t v = 0;
switch (width) {
case 8:
v = target_buffer_get_u64(target, &buffer[i * width]);
break;
case 4:
v = target_buffer_get_u32(target, &buffer[i * width]);
break;
case 2:
v = target_buffer_get_u16(target, &buffer[i * width]);
break;
case 1:
v = buffer[i];
break;
}
command_print_sameline(CMD, "%s0x%" PRIx64, separator, v);
separator = " ";
}
count -= chunk_len;
offset += chunk_len * width;
}
free(buffer);
return ERROR_OK;
}
COMMAND_HANDLER(handle_flash_write_bank_command)
{
@ -1170,6 +1288,13 @@ static const struct command_registration flash_exec_command_handlers[] = {
.usage = "address [count]",
.help = "Display words from flash.",
},
{
.name = "read_memory",
.mode = COMMAND_EXEC,
.handler = handle_flash_read_memory_command,
.help = "Read Tcl list of 8/16/32/64 bit numbers from flash memory",
.usage = "address width count",
},
{
.name = "write_bank",
.handler = handle_flash_write_bank_command,