diff options
author | Simon Glass <sjg@chromium.org> | 2020-06-02 19:26:49 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-07-08 17:21:46 -0400 |
commit | bdded2015c1e54038a86557e339b606b4a31968b (patch) | |
tree | b2f12b2694e55df93d4d144b5d2aaf56d486c38e /cmd | |
parent | a33a824227e130d81260dfd3a275af3b0daa81c1 (diff) | |
download | u-boot-bdded2015c1e54038a86557e339b606b4a31968b.tar.gz |
cmd: Add a memory-search command
It is useful to be able to find hex values and strings in a memory range.
Add a command to support this.
cmd: Fix 'md' and add a memory-search command
At present 'md.q' is broken. This series provides a fix for this. It also
implements a new memory-search command called 'ms'. It allows searching
memory for hex and string data.
END
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/Kconfig | 14 | ||||
-rw-r--r-- | cmd/mem.c | 151 |
2 files changed, 165 insertions, 0 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index 0ead88eff1..2b823dd260 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -718,6 +718,20 @@ config CMD_MEMORY base - print or set address offset loop - initialize loop on address range +config MEM_SEARCH + bool "ms - Memory search" + help + Memory-search command + + This allows searching through a region of memory looking for hex + data (byte, 16-bit word, 32-bit long, also 64-bit on machines that + support it). It is also possible to search for a string. The + command accepts a memory range and a list of values to search for. + The values need to appear in memory in the same order they are given + in the command. At most 10 matches can be returned at a time, but + pressing return will show the next 10 matches. Environment variables + are set for use with scripting (memmatches, memaddr, mempos). + config CMD_MX_CYCLIC bool "Enable cyclic md/mw commands" depends on CMD_MEMORY @@ -25,6 +25,7 @@ #include <asm/io.h> #include <linux/bitops.h> #include <linux/compiler.h> +#include <linux/ctype.h> #include <linux/delay.h> DECLARE_GLOBAL_DATA_PTR; @@ -52,6 +53,10 @@ static ulong dp_last_length = 0x40; static ulong mm_last_addr, mm_last_size; static ulong base_address = 0; +#ifdef CONFIG_MEM_SEARCH +static u8 search_buf[64]; +static uint search_len; +#endif /* Memory Display * @@ -362,6 +367,142 @@ static int do_mem_cp(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +#ifdef CONFIG_MEM_SEARCH +static int do_mem_search(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr, length, bytes, offset; + u8 *ptr, *end, *buf; + bool quiet = false; + ulong last_pos; /* Offset of last match in 'size' units*/ + ulong last_addr; /* Address of last displayed line */ + int limit = 10; + int count; + int size; + int i; + + /* We use the last specified parameters, unless new ones are entered */ + addr = dp_last_addr; + size = dp_last_size; + length = dp_last_length; + + if (argc < 3) + return CMD_RET_USAGE; + + if ((!flag & CMD_FLAG_REPEAT)) { + /* + * Check for a size specification. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + if (size < 0 && size != -2 /* string */) + return 1; + + argc--; argv++; + while (argc && *argv[0] == '-') { + int ch = argv[0][1]; + + if (ch == 'q') + quiet = true; + else if (ch == 'l' && isxdigit(argv[0][2])) + limit = simple_strtoul(argv[0] + 2, NULL, 16); + else + return CMD_RET_USAGE; + argc--; argv++; + } + + /* Address is specified since argc > 1 */ + addr = simple_strtoul(argv[0], NULL, 16); + addr += base_address; + + /* Length is the number of objects, not number of bytes */ + length = simple_strtoul(argv[1], NULL, 16); + + /* Read the bytes to search for */ + end = search_buf + sizeof(search_buf); + for (i = 2, ptr = search_buf; i < argc && ptr < end; i++) { + if (SUPPORT_64BIT_DATA && size == 8) { + u64 val = simple_strtoull(argv[i], NULL, 16); + + *(u64 *)ptr = val; + } else if (size == -2) { /* string */ + int len = min(strlen(argv[i]), + (size_t)(end - ptr)); + + memcpy(ptr, argv[i], len); + ptr += len; + continue; + } else { + u32 val = simple_strtoul(argv[i], NULL, 16); + + switch (size) { + case 1: + *ptr = val; + break; + case 2: + *(u16 *)ptr = val; + break; + case 4: + *(u32 *)ptr = val; + break; + } + } + ptr += size; + } + search_len = ptr - search_buf; + } + + /* Do the search */ + if (size == -2) + size = 1; + bytes = size * length; + buf = map_sysmem(addr, bytes); + last_pos = 0; + last_addr = 0; + count = 0; + for (offset = 0; offset <= bytes - search_len && count < limit; + offset += size) { + void *ptr = buf + offset; + + if (!memcmp(ptr, search_buf, search_len)) { + uint align = (addr + offset) & 0xf; + ulong match = addr + offset; + + if (!count || (last_addr & ~0xf) != (match & ~0xf)) { + if (!quiet) { + if (count) + printf("--\n"); + print_buffer(match - align, ptr - align, + size, + ALIGN(search_len + align, + 16) / size, 0); + } + last_addr = match; + last_pos = offset / size; + } + count++; + } + } + if (!quiet) { + printf("%d match%s", count, count == 1 ? "" : "es"); + if (count == limit) + printf(" (repeat command to check for more)"); + printf("\n"); + } + env_set_hex("memmatches", count); + env_set_hex("memaddr", last_addr); + env_set_hex("mempos", last_pos); + + unmap_sysmem(buf); + + dp_last_addr = addr + offset / size; + dp_last_size = size; + dp_last_length = length - offset / size; + + return count ? 0 : CMD_RET_FAILURE; +} +#endif + static int do_mem_base(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -1196,6 +1337,16 @@ U_BOOT_CMD( "[.b, .w, .l" HELP_Q "] addr1 addr2 count" ); +#ifdef CONFIG_MEM_SEARCH +/**************************************************/ +U_BOOT_CMD( + ms, 255, 1, do_mem_search, + "memory search", + "[.b, .w, .l" HELP_Q ", .s] [-q | -<n>] address #-of-objects <value>..." + " -q = quiet, -l<val> = match limit" : +); +#endif + #ifdef CONFIG_CMD_CRC32 #ifndef CONFIG_CRC32_VERIFY |