shell: devmem: add devmem dump subcommand

This allows the caller to dump a region of memory rather than
dumping one byte (word, etc) at a time. Additionally, it
respects alignment requirements so it works for e.g. 32-bit
register accesses.

Signed-off-by: Chris Friedt <cfriedt@meta.com>
This commit is contained in:
Chris Friedt 2022-12-02 07:11:43 -05:00 committed by Carles Cufí
commit 510dca57da
2 changed files with 127 additions and 0 deletions

View file

@ -42,5 +42,6 @@ config DATE_SHELL
config DEVMEM_SHELL
bool "Devmem shell"
default y if !SHELL_MINIMAL
select GETOPT
help
This shell command provides read/write access to physical memory.

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2020 Intel Corporation
* Copyright (c) 2021 Antmicro <www.antmicro.com>
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -9,6 +10,11 @@
#include <zephyr/device.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/byteorder.h>
#ifdef CONFIG_ARCH_POSIX
#include <unistd.h>
#else
#include <zephyr/posix/unistd.h>
#endif
static inline bool is_ascii(uint8_t data)
{
@ -26,6 +32,122 @@ static bool littleendian;
#define CHAR_CAN 0x18
#define CHAR_DC1 0x11
#ifndef BITS_PER_BYTE
#define BITS_PER_BYTE 8
#endif
static int memory_dump(const struct shell *sh, mem_addr_t phys_addr, size_t size, uint8_t width)
{
uint32_t value;
size_t data_offset;
mm_reg_t addr;
const size_t vsize = width / BITS_PER_BYTE;
uint8_t data[SHELL_HEXDUMP_BYTES_IN_LINE];
#if defined(CONFIG_MMU) || defined(CONFIG_PCIE)
device_map((mm_reg_t *)&addr, phys_addr, size, K_MEM_CACHE_NONE);
shell_print(sh, "Mapped 0x%lx to 0x%lx\n", phys_addr, addr);
#else
addr = phys_addr;
#endif /* defined(CONFIG_MMU) || defined(CONFIG_PCIE) */
for (; size > 0;
addr += SHELL_HEXDUMP_BYTES_IN_LINE, size -= MIN(size, SHELL_HEXDUMP_BYTES_IN_LINE)) {
for (data_offset = 0;
size >= vsize && data_offset + vsize <= SHELL_HEXDUMP_BYTES_IN_LINE;
data_offset += vsize) {
switch (width) {
case 8:
value = sys_read8(addr + data_offset);
data[data_offset] = value;
break;
case 16:
value = sys_read16(addr + data_offset);
if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
value = __bswap_16(value);
}
data[data_offset] = (uint8_t)value;
value >>= 8;
data[data_offset + 1] = (uint8_t)value;
break;
case 32:
value = sys_read32(addr + data_offset);
if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
value = __bswap_32(value);
}
data[data_offset] = (uint8_t)value;
value >>= 8;
data[data_offset + 1] = (uint8_t)value;
value >>= 8;
data[data_offset + 2] = (uint8_t)value;
value >>= 8;
data[data_offset + 3] = (uint8_t)value;
break;
default:
shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n");
return -EINVAL;
}
}
shell_hexdump_line(sh, addr, data, MIN(size, SHELL_HEXDUMP_BYTES_IN_LINE));
}
return 0;
}
static int cmd_dump(const struct shell *sh, size_t argc, char **argv)
{
int rv;
size_t size = -1;
size_t width = 32;
mem_addr_t addr = -1;
optind = 1;
while ((rv = getopt(argc, argv, "a:s:w:")) != -1) {
switch (rv) {
case 'a':
addr = (mem_addr_t)strtoul(optarg, NULL, 16);
if (addr == 0 && errno == EINVAL) {
shell_error(sh, "invalid addr '%s'", optarg);
return -EINVAL;
}
break;
case 's':
size = (size_t)strtoul(optarg, NULL, 0);
if (size == 0 && errno == EINVAL) {
shell_error(sh, "invalid size '%s'", optarg);
return -EINVAL;
}
break;
case 'w':
width = (size_t)strtoul(optarg, NULL, 0);
if (width == 0 && errno == EINVAL) {
shell_error(sh, "invalid width '%s'", optarg);
return -EINVAL;
}
break;
case '?':
default:
return -EINVAL;
}
}
if (addr == -1) {
shell_error(sh, "'-a <address>' is mandatory");
return -EINVAL;
}
if (size == -1) {
shell_error(sh, "'-s <size>' is mandatory");
return -EINVAL;
}
return memory_dump(sh, addr, size, width);
}
static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
{
static bool in_use;
@ -229,6 +351,10 @@ static int cmd_devmem(const struct shell *sh, size_t argc, char **argv)
}
SHELL_STATIC_SUBCMD_SET_CREATE(sub_devmem,
SHELL_CMD_ARG(dump, NULL,
"Usage:\n"
"devmem dump -a <address> -s <size> [-w <width>]\n",
cmd_dump, 4, 6),
SHELL_CMD_ARG(load, NULL,
"Usage:\n"
"devmem load [options] [address]\n"