#include <asm/io.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
+#include <linux/ctype.h>
#include <linux/delay.h>
DECLARE_GLOBAL_DATA_PTR;
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
*
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[])
{
"[.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
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for memory commands
+ *
+ * Copyright 2020 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <console.h>
+#include <mapmem.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+#define BUF_SIZE 0x100
+
+/* Test 'ms' command with bytes */
+static int dm_test_ms_b(struct unit_test_state *uts)
+{
+ u8 *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 1);
+ memset(buf, '\0', BUF_SIZE);
+ buf[0x0] = 0x12;
+ buf[0x31] = 0x12;
+ buf[0xff] = 0x12;
+ buf[0x100] = 0x12;
+ console_record_reset();
+ run_command("ms.b 1 ff 12", 0);
+ ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................");
+ ut_assert_nextline("--");
+ ut_assert_nextline("000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 ................");
+ ut_assert_nextline("2 matches");
+ ut_assert_console_end();
+
+ ut_asserteq(2, env_get_hex("memmatches", 0));
+ ut_asserteq(0xff, env_get_hex("memaddr", 0));
+ ut_asserteq(0xfe, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_b, 0);
+
+/* Test 'ms' command with 16-bit values */
+static int dm_test_ms_w(struct unit_test_state *uts)
+{
+ u16 *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 2);
+ memset(buf, '\0', BUF_SIZE);
+ buf[0x34 / 2] = 0x1234;
+ buf[BUF_SIZE / 2] = 0x1234;
+ console_record_reset();
+ run_command("ms.w 0 80 1234", 0);
+ ut_assert_nextline("00000030: 0000 0000 1234 0000 0000 0000 0000 0000 ....4...........");
+ ut_assert_nextline("1 match");
+ ut_assert_console_end();
+
+ ut_asserteq(1, env_get_hex("memmatches", 0));
+ ut_asserteq(0x34, env_get_hex("memaddr", 0));
+ ut_asserteq(0x34 / 2, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_w, 0);
+
+/* Test 'ms' command with 32-bit values */
+static int dm_test_ms_l(struct unit_test_state *uts)
+{
+ u32 *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 4);
+ memset(buf, '\0', BUF_SIZE);
+ buf[0x38 / 4] = 0x12345678;
+ buf[BUF_SIZE / 4] = 0x12345678;
+ console_record_reset();
+ run_command("ms 0 40 12345678", 0);
+ ut_assert_nextline("00000030: 00000000 00000000 12345678 00000000 ........xV4.....");
+ ut_assert_nextline("1 match");
+ ut_assert_console_end();
+
+ ut_asserteq(1, env_get_hex("memmatches", 0));
+ ut_asserteq(0x38, env_get_hex("memaddr", 0));
+ ut_asserteq(0x38 / 4, env_get_hex("mempos", 0));
+
+ console_record_reset();
+ run_command("ms 0 80 12345679", 0);
+ ut_assert_nextline("0 matches");
+ ut_assert_console_end();
+
+ ut_asserteq(0, env_get_hex("memmatches", 0));
+ ut_asserteq(0, env_get_hex("memaddr", 0));
+ ut_asserteq(0 / 4, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_l, 0);
+
+/* Test 'ms' command with continuation */
+static int dm_test_ms_cont(struct unit_test_state *uts)
+{
+ char *const args[] = {"ms.b", "0", "100", "34"};
+ int repeatable;
+ u8 *buf;
+ int i;
+
+ buf = map_sysmem(0, BUF_SIZE);
+ memset(buf, '\0', BUF_SIZE);
+ for (i = 5; i < 0x33; i += 3)
+ buf[i] = 0x34;
+ console_record_reset();
+ run_command("ms.b 0 100 34", 0);
+ ut_assert_nextlinen("00000000: 00 00 00 00 00 34 00 00 34 00 00 34 00 00 34 00");
+ ut_assert_nextline("--");
+ ut_assert_nextlinen("00000010: 00 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00");
+ ut_assert_nextline("--");
+ ut_assert_nextlinen("00000020: 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00 34");
+ ut_assert_nextlinen("10 matches (repeat command to check for more)");
+ ut_assert_console_end();
+
+ ut_asserteq(10, env_get_hex("memmatches", 0));
+ ut_asserteq(0x20, env_get_hex("memaddr", 0));
+ ut_asserteq(0x20, env_get_hex("mempos", 0));
+
+ /*
+ * run_command() ignoes the repeatable flag when using hush, so call
+ * cmd_process() directly
+ */
+ console_record_reset();
+ cmd_process(CMD_FLAG_REPEAT, 4, args, &repeatable, NULL);
+ ut_assert_nextlinen("00000020: 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00 34");
+ ut_assert_nextline("--");
+ ut_assert_nextlinen("00000030: 00 00 34 00 00 00 00 00");
+ ut_assert_nextlinen("6 matches");
+ ut_assert_console_end();
+
+ ut_asserteq(6, env_get_hex("memmatches", 0));
+ ut_asserteq(0x32, env_get_hex("memaddr", 0));
+
+ /* 0x32 less 0x21, where the second search started */
+ ut_asserteq(0x11, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_cont, 0);
+
+/* Test 'ms' command with multiple values */
+static int dm_test_ms_mult(struct unit_test_state *uts)
+{
+ static const char str[] = "hello";
+ char *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 5);
+ memset(buf, '\0', BUF_SIZE);
+ strcpy(buf + 0x1e, str);
+ strcpy(buf + 0x63, str);
+ strcpy(buf + BUF_SIZE - strlen(str) + 1, str);
+ console_record_reset();
+ run_command("ms.b 0 100 68 65 6c 6c 6f", 0);
+ ut_assert_nextline("00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 65 ..............he");
+ ut_assert_nextline("00000020: 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 llo.............");
+ ut_assert_nextline("--");
+ ut_assert_nextline("00000060: 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 ...hello........");
+ ut_assert_nextline("2 matches");
+ ut_assert_console_end();
+ unmap_sysmem(buf);
+
+ ut_asserteq(2, env_get_hex("memmatches", 0));
+ ut_asserteq(0x63, env_get_hex("memaddr", 0));
+ ut_asserteq(0x63, env_get_hex("mempos", 0));
+
+ return 0;
+}
+DM_TEST(dm_test_ms_mult, 0);
+
+/* Test 'ms' command with string */
+static int dm_test_ms_s(struct unit_test_state *uts)
+{
+ static const char str[] = "hello";
+ static const char str2[] = "hellothere";
+ char *buf;
+
+ buf = map_sysmem(0, BUF_SIZE);
+ memset(buf, '\0', BUF_SIZE);
+ strcpy(buf + 0x1e, str);
+ strcpy(buf + 0x63, str);
+ strcpy(buf + 0xa1, str2);
+ console_record_reset();
+ run_command("ms.s 0 100 hello", 0);
+ ut_assert_nextline("00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 65 ..............he");
+ ut_assert_nextline("00000020: 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 llo.............");
+ ut_assert_nextline("--");
+ ut_assert_nextline("00000060: 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 ...hello........");
+ ut_assert_nextline("--");
+ ut_assert_nextline("000000a0: 00 68 65 6c 6c 6f 74 68 65 72 65 00 00 00 00 00 .hellothere.....");
+ ut_assert_nextline("3 matches");
+ ut_assert_console_end();
+
+ ut_asserteq(3, env_get_hex("memmatches", 0));
+ ut_asserteq(0xa1, env_get_hex("memaddr", 0));
+ ut_asserteq(0xa1, env_get_hex("mempos", 0));
+
+ console_record_reset();
+ run_command("ms.s 0 100 hello there", 0);
+ ut_assert_nextline("000000a0: 00 68 65 6c 6c 6f 74 68 65 72 65 00 00 00 00 00 .hellothere.....");
+ ut_assert_nextline("1 match");
+ ut_assert_console_end();
+
+ ut_asserteq(1, env_get_hex("memmatches", 0));
+ ut_asserteq(0xa1, env_get_hex("memaddr", 0));
+ ut_asserteq(0xa1, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_s, 0);
+
+/* Test 'ms' command with limit */
+static int dm_test_ms_limit(struct unit_test_state *uts)
+{
+ u8 *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 1);
+ memset(buf, '\0', BUF_SIZE);
+ buf[0x0] = 0x12;
+ buf[0x31] = 0x12;
+ buf[0x62] = 0x12;
+ buf[0x76] = 0x12;
+ console_record_reset();
+ run_command("ms.b -l2 1 ff 12", 0);
+ ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................");
+ ut_assert_nextline("--");
+ ut_assert_nextlinen("00000060: 00 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ ut_assert_nextline("2 matches (repeat command to check for more)");
+ ut_assert_console_end();
+
+ ut_asserteq(2, env_get_hex("memmatches", 0));
+ ut_asserteq(0x62, env_get_hex("memaddr", 0));
+ ut_asserteq(0x61, env_get_hex("mempos", 0));
+
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_limit, 0);
+
+/* Test 'ms' command in quiet mode */
+static int dm_test_ms_quiet(struct unit_test_state *uts)
+{
+ u8 *buf;
+
+ buf = map_sysmem(0, BUF_SIZE + 1);
+ memset(buf, '\0', BUF_SIZE);
+ buf[0x0] = 0x12;
+ buf[0x31] = 0x12;
+ buf[0x62] = 0x12;
+ buf[0x76] = 0x12;
+ console_record_reset();
+ run_command("ms.b -l2 1 ff 12", 0);
+ ut_assert_console_end();
+ unmap_sysmem(buf);
+
+ return 0;
+}
+DM_TEST(dm_test_ms_quiet, 0);
+