Merge branch '2020-07-08-misc-features-and-fixes'

- mem cmd improvements
- TPM fixes
- SPL/NAND/FIT fixes
- RSA improvements
diff --git a/Kconfig b/Kconfig
index 99bc5fa..566ca72 100644
--- a/Kconfig
+++ b/Kconfig
@@ -509,6 +509,8 @@
 	bool "Enable signature verification of FIT firmware within SPL"
 	depends on SPL_DM
 	select SPL_FIT
+	select SPL_CRYPTO_SUPPORT
+	select SPL_HASH_SUPPORT
 	select SPL_RSA
 	select SPL_RSA_VERIFY
 	select SPL_IMAGE_SIGN_INFO
diff --git a/README b/README
index 020918a..2384966 100644
--- a/README
+++ b/README
@@ -3237,6 +3237,7 @@
 mm	- memory modify (auto-incrementing)
 nm	- memory modify (constant address)
 mw	- memory write (fill)
+ms	- memory search
 cp	- memory copy
 cmp	- memory compare
 crc32	- checksum calculation
@@ -3482,6 +3483,15 @@
 		  CONFIG_NET_RETRY_COUNT, if defined. This value has
 		  precedence over the valu based on CONFIG_NET_RETRY_COUNT.
 
+  memmatches	- Number of matches found by the last 'ms' command, in hex
+
+  memaddr	- Address of the last match found by the 'ms' command, in hex,
+		  or 0 if none
+
+  mempos	- Index position of the last match found by the 'ms' command,
+		  in units of the size (.b, .w, .l) of the search
+
+
 The following image location variables contain the location of images
 used in booting. The "Image" column gives the role of the image and is
 not an environment variable name. The other columns are environment
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0ead88e..2b823dd 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -718,6 +718,20 @@
 	    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
diff --git a/cmd/Makefile b/cmd/Makefile
index 006075a..7008dd4 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -8,6 +8,7 @@
 obj-y += boot.o
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 obj-y += help.o
+obj-y += panic.o
 obj-y += version.o
 
 # command
diff --git a/cmd/mem.c b/cmd/mem.c
index 9b97f7b..575893c 100644
--- a/cmd/mem.c
+++ b/cmd/mem.c
@@ -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;
@@ -33,6 +34,15 @@
 #define CONFIG_SYS_MEMTEST_SCRATCH 0
 #endif
 
+/* Create a compile-time value */
+#ifdef MEM_SUPPORT_64BIT_DATA
+#define SUPPORT_64BIT_DATA 1
+#define HELP_Q ", .q"
+#else
+#define SUPPORT_64BIT_DATA 0
+#define HELP_Q ""
+#endif
+
 static int mod_mem(struct cmd_tbl *, int, int, int, char * const []);
 
 /* Display values from last command.
@@ -43,6 +53,10 @@
 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
  *
@@ -116,11 +130,7 @@
 static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc,
 		     char *const argv[])
 {
-#ifdef MEM_SUPPORT_64BIT_DATA
-	u64 writeval;
-#else
-	ulong writeval;
-#endif
+	ulong writeval;  /* 64-bit if SUPPORT_64BIT_DATA */
 	ulong	addr, count;
 	int	size;
 	void *buf, *start;
@@ -141,11 +151,10 @@
 
 	/* Get the value to write.
 	*/
-#ifdef MEM_SUPPORT_64BIT_DATA
-	writeval = simple_strtoull(argv[2], NULL, 16);
-#else
-	writeval = simple_strtoul(argv[2], NULL, 16);
-#endif
+	if (SUPPORT_64BIT_DATA)
+		writeval = simple_strtoull(argv[2], NULL, 16);
+	else
+		writeval = simple_strtoul(argv[2], NULL, 16);
 
 	/* Count ? */
 	if (argc == 4) {
@@ -160,10 +169,8 @@
 	while (count-- > 0) {
 		if (size == 4)
 			*((u32 *)buf) = (u32)writeval;
-#ifdef MEM_SUPPORT_64BIT_DATA
-		else if (size == 8)
-			*((u64 *)buf) = (u64)writeval;
-#endif
+		else if (SUPPORT_64BIT_DATA && size == 8)
+			*((ulong *)buf) = writeval;
 		else if (size == 2)
 			*((u16 *)buf) = (u16)writeval;
 		else
@@ -240,11 +247,7 @@
 	int     rcode = 0;
 	const char *type;
 	const void *buf1, *buf2, *base;
-#ifdef MEM_SUPPORT_64BIT_DATA
-	u64 word1, word2;
-#else
-	ulong word1, word2;
-#endif
+	ulong word1, word2;  /* 64-bit if SUPPORT_64BIT_DATA */
 
 	if (argc != 4)
 		return CMD_RET_USAGE;
@@ -272,11 +275,9 @@
 		if (size == 4) {
 			word1 = *(u32 *)buf1;
 			word2 = *(u32 *)buf2;
-#ifdef MEM_SUPPORT_64BIT_DATA
-		} else if (size == 8) {
-			word1 = *(u64 *)buf1;
-			word2 = *(u64 *)buf2;
-#endif
+		} else if (SUPPORT_64BIT_DATA && size == 8) {
+			word1 = *(ulong *)buf1;
+			word2 = *(ulong *)buf2;
 		} else if (size == 2) {
 			word1 = *(u16 *)buf1;
 			word2 = *(u16 *)buf2;
@@ -286,15 +287,9 @@
 		}
 		if (word1 != word2) {
 			ulong offset = buf1 - base;
-#ifdef MEM_SUPPORT_64BIT_DATA
-			printf("%s at 0x%p (%#0*llx) != %s at 0x%p (%#0*llx)\n",
-			       type, (void *)(addr1 + offset), size, word1,
-			       type, (void *)(addr2 + offset), size, word2);
-#else
 			printf("%s at 0x%08lx (%#0*lx) != %s at 0x%08lx (%#0*lx)\n",
 				type, (ulong)(addr1 + offset), size, word1,
 				type, (ulong)(addr2 + offset), size, word2);
-#endif
 			rcode = 1;
 			break;
 		}
@@ -371,6 +366,142 @@
 	unmap_sysmem(dst);
 	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[])
@@ -391,9 +522,7 @@
 {
 	ulong	addr, length, i, bytes;
 	int	size;
-#ifdef MEM_SUPPORT_64BIT_DATA
-	volatile u64 *llp;
-#endif
+	volatile ulong *llp;  /* 64-bit if SUPPORT_64BIT_DATA */
 	volatile u32 *longp;
 	volatile u16 *shortp;
 	volatile u8 *cp;
@@ -424,13 +553,11 @@
 	 * If we have only one object, just run infinite loops.
 	 */
 	if (length == 1) {
-#ifdef MEM_SUPPORT_64BIT_DATA
-		if (size == 8) {
-			llp = (u64 *)buf;
+		if (SUPPORT_64BIT_DATA && size == 8) {
+			llp = (ulong *)buf;
 			for (;;)
 				i = *llp;
 		}
-#endif
 		if (size == 4) {
 			longp = (u32 *)buf;
 			for (;;)
@@ -446,16 +573,14 @@
 			i = *cp;
 	}
 
-#ifdef MEM_SUPPORT_64BIT_DATA
-	if (size == 8) {
+	if (SUPPORT_64BIT_DATA && size == 8) {
 		for (;;) {
-			llp = (u64 *)buf;
+			llp = (ulong *)buf;
 			i = length;
 			while (i-- > 0)
 				*llp++;
 		}
 	}
-#endif
 	if (size == 4) {
 		for (;;) {
 			longp = (u32 *)buf;
@@ -489,12 +614,8 @@
 {
 	ulong	addr, length, i, bytes;
 	int	size;
-#ifdef MEM_SUPPORT_64BIT_DATA
-	volatile u64 *llp;
-	u64 data;
-#else
-	ulong	data;
-#endif
+	volatile ulong *llp;  /* 64-bit if SUPPORT_64BIT_DATA */
+	ulong	data;    /* 64-bit if SUPPORT_64BIT_DATA */
 	volatile u32 *longp;
 	volatile u16 *shortp;
 	volatile u8 *cp;
@@ -519,11 +640,10 @@
 	length = simple_strtoul(argv[2], NULL, 16);
 
 	/* data to write */
-#ifdef MEM_SUPPORT_64BIT_DATA
-	data = simple_strtoull(argv[3], NULL, 16);
-#else
-	data = simple_strtoul(argv[3], NULL, 16);
-#endif
+	if (SUPPORT_64BIT_DATA)
+		data = simple_strtoull(argv[3], NULL, 16);
+	else
+		data = simple_strtoul(argv[3], NULL, 16);
 
 	bytes = size * length;
 	buf = map_sysmem(addr, bytes);
@@ -532,13 +652,11 @@
 	 * If we have only one object, just run infinite loops.
 	 */
 	if (length == 1) {
-#ifdef MEM_SUPPORT_64BIT_DATA
-		if (size == 8) {
-			llp = (u64 *)buf;
+		if (SUPPORT_64BIT_DATA && size == 8) {
+			llp = (ulong *)buf;
 			for (;;)
 				*llp = data;
 		}
-#endif
 		if (size == 4) {
 			longp = (u32 *)buf;
 			for (;;)
@@ -554,16 +672,14 @@
 			*cp = data;
 	}
 
-#ifdef MEM_SUPPORT_64BIT_DATA
-	if (size == 8) {
+	if (SUPPORT_64BIT_DATA && size == 8) {
 		for (;;) {
-			llp = (u64 *)buf;
+			llp = (ulong *)buf;
 			i = length;
 			while (i-- > 0)
 				*llp++ = data;
 		}
 	}
-#endif
 	if (size == 4) {
 		for (;;) {
 			longp = (u32 *)buf;
@@ -1016,18 +1132,13 @@
  *
  * Syntax:
  *	mm{.b, .w, .l, .q} {addr}
- *	nm{.b, .w, .l, .q} {addr}
  */
 static int
 mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc,
 	char *const argv[])
 {
 	ulong	addr;
-#ifdef MEM_SUPPORT_64BIT_DATA
-	u64 i;
-#else
-	ulong i;
-#endif
+	ulong i;  /* 64-bit if SUPPORT_64BIT_DATA */
 	int	nbytes, size;
 	void *ptr = NULL;
 
@@ -1062,10 +1173,8 @@
 		printf("%08lx:", addr);
 		if (size == 4)
 			printf(" %08x", *((u32 *)ptr));
-#ifdef MEM_SUPPORT_64BIT_DATA
-		else if (size == 8)
-			printf(" %016llx", *((u64 *)ptr));
-#endif
+		else if (SUPPORT_64BIT_DATA && size == 8)
+			printf(" %0lx", *((ulong *)ptr));
 		else if (size == 2)
 			printf(" %04x", *((u16 *)ptr));
 		else
@@ -1089,11 +1198,10 @@
 #endif
 		else {
 			char *endp;
-#ifdef MEM_SUPPORT_64BIT_DATA
-			i = simple_strtoull(console_buffer, &endp, 16);
-#else
-			i = simple_strtoul(console_buffer, &endp, 16);
-#endif
+			if (SUPPORT_64BIT_DATA)
+				i = simple_strtoull(console_buffer, &endp, 16);
+			else
+				i = simple_strtoul(console_buffer, &endp, 16);
 			nbytes = endp - console_buffer;
 			if (nbytes) {
 				/* good enough to not time out
@@ -1101,10 +1209,8 @@
 				bootretry_reset_cmd_timeout();
 				if (size == 4)
 					*((u32 *)ptr) = i;
-#ifdef MEM_SUPPORT_64BIT_DATA
-				else if (size == 8)
-					*((u64 *)ptr) = i;
-#endif
+				else if (SUPPORT_64BIT_DATA && size == 8)
+					*((ulong *)ptr) = i;
 				else if (size == 2)
 					*((u16 *)ptr) = i;
 				else
@@ -1196,65 +1302,51 @@
 U_BOOT_CMD(
 	md,	3,	1,	do_mem_md,
 	"memory display",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address [# of objects]"
-#else
-	"[.b, .w, .l] address [# of objects]"
-#endif
+	"[.b, .w, .l" HELP_Q "] address [# of objects]"
 );
 
 
 U_BOOT_CMD(
 	mm,	2,	1,	do_mem_mm,
 	"memory modify (auto-incrementing address)",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address"
-#else
-	"[.b, .w, .l] address"
-#endif
+	"[.b, .w, .l" HELP_Q "] address"
 );
 
 
 U_BOOT_CMD(
 	nm,	2,	1,	do_mem_nm,
 	"memory modify (constant address)",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address"
-#else
-	"[.b, .w, .l] address"
-#endif
+	"[.b, .w, .l" HELP_Q "] address"
 );
 
 U_BOOT_CMD(
 	mw,	4,	1,	do_mem_mw,
 	"memory write (fill)",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address value [count]"
-#else
-	"[.b, .w, .l] address value [count]"
-#endif
+	"[.b, .w, .l" HELP_Q "] address value [count]"
 );
 
 U_BOOT_CMD(
 	cp,	4,	1,	do_mem_cp,
 	"memory copy",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] source target count"
-#else
-	"[.b, .w, .l] source target count"
-#endif
+	"[.b, .w, .l" HELP_Q "] source target count"
 );
 
 U_BOOT_CMD(
 	cmp,	4,	1,	do_mem_cmp,
 	"memory compare",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] addr1 addr2 count"
-#else
-	"[.b, .w, .l] addr1 addr2 count"
-#endif
+	"[.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
@@ -1299,22 +1391,14 @@
 U_BOOT_CMD(
 	loop,	3,	1,	do_mem_loop,
 	"infinite loop on address range",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address number_of_objects"
-#else
-	"[.b, .w, .l] address number_of_objects"
-#endif
+	"[.b, .w, .l" HELP_Q "] address number_of_objects"
 );
 
 #ifdef CONFIG_LOOPW
 U_BOOT_CMD(
 	loopw,	4,	1,	do_mem_loopw,
 	"infinite write loop on address range",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address number_of_objects data_to_write"
-#else
-	"[.b, .w, .l] address number_of_objects data_to_write"
-#endif
+	"[.b, .w, .l" HELP_Q "] address number_of_objects data_to_write"
 );
 #endif /* CONFIG_LOOPW */
 
@@ -1330,21 +1414,13 @@
 U_BOOT_CMD(
 	mdc,	4,	1,	do_mem_mdc,
 	"memory display cyclic",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address count delay(ms)"
-#else
-	"[.b, .w, .l] address count delay(ms)"
-#endif
+	"[.b, .w, .l" HELP_Q "] address count delay(ms)"
 );
 
 U_BOOT_CMD(
 	mwc,	4,	1,	do_mem_mwc,
 	"memory write cyclic",
-#ifdef MEM_SUPPORT_64BIT_DATA
-	"[.b, .w, .l, .q] address value delay(ms)"
-#else
-	"[.b, .w, .l] address value delay(ms)"
-#endif
+	"[.b, .w, .l" HELP_Q "] address value delay(ms)"
 );
 #endif /* CONFIG_CMD_MX_CYCLIC */
 
diff --git a/cmd/panic.c b/cmd/panic.c
new file mode 100644
index 0000000..f13b3f0
--- /dev/null
+++ b/cmd/panic.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <command.h>
+
+static int do_panic(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char * const argv[])
+{
+	char *text = (argc < 2) ? "" : argv[1];
+
+	panic(text);
+
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	panic,	2,	1,	do_panic,
+	"Panic with optional message",
+	"[message]"
+);
diff --git a/common/command.c b/common/command.c
index 4f49f15..2c491e2 100644
--- a/common/command.c
+++ b/common/command.c
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <compiler.h>
 #include <command.h>
 #include <console.h>
 #include <env.h>
@@ -473,12 +474,12 @@
 			return 2;
 		case 'l':
 			return 4;
-#ifdef MEM_SUPPORT_64BIT_DATA
-		case 'q':
-			return 8;
-#endif
 		case 's':
 			return -2;
+		case 'q':
+			if (MEM_SUPPORT_64BIT_DATA)
+				return 8;
+			/* no break */
 		default:
 			return -1;
 		}
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index f581a22..365104f 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -619,9 +619,12 @@
 	 * Booting a next-stage U-Boot may require us to append the FDT.
 	 * We allow this to fail, as the U-Boot image might embed its FDT.
 	 */
-	if (spl_image->os == IH_OS_U_BOOT)
-		spl_fit_append_fdt(spl_image, info, sector, fit,
-				   images, base_offset);
+	if (spl_image->os == IH_OS_U_BOOT) {
+		ret = spl_fit_append_fdt(spl_image, info, sector, fit,
+					 images, base_offset);
+		if (!IS_ENABLED(CONFIG_OF_EMBED) && ret < 0)
+			return ret;
+	}
 
 	firmware_node = node;
 	/* Now check if there are more images for us to load */
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c
index 48c9754..d13a524 100644
--- a/common/spl/spl_nand.c
+++ b/common/spl/spl_nand.c
@@ -42,13 +42,16 @@
 static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
 			       ulong size, void *dst)
 {
-	int ret;
+	ulong sector;
+	int err;
 
-	ret = nand_spl_load_image(offs, size, dst);
-	if (!ret)
-		return size;
-	else
+	sector = *(int *)load->priv;
+	offs = sector + nand_spl_adjust_offset(sector, offs - sector);
+	err = nand_spl_load_image(offs, size, dst);
+	if (err)
 		return 0;
+
+	return size;
 }
 
 static int spl_nand_load_element(struct spl_image_info *spl_image,
@@ -66,7 +69,7 @@
 
 		debug("Found FIT\n");
 		load.dev = NULL;
-		load.priv = NULL;
+		load.priv = &offset;
 		load.filename = NULL;
 		load.bl_len = 1;
 		load.read = spl_nand_fit_read;
diff --git a/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt
index b48a151..3a2ee4b 100644
--- a/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt
+++ b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt
@@ -2,7 +2,7 @@
 -------------------------------
 
 Required properties:
-- compatible		: Should be "tis,tpm2-spi"
+- compatible		: Should be "tcg,tpm_tis-spi"
 - reg			: SPI Chip select
 
 Optional properties:
@@ -12,7 +12,7 @@
 Example:
 
 	tpm@1 {
-		compatible = "tis,tpm2-spi";
+		compatible = "tcg,tpm_tis-spi";
 		reg = <1>;
 		spi-max-frequency = <10000000>;
 	};
diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c
index 177c12b..4befc75 100644
--- a/drivers/mtd/nand/raw/nand_spl_loaders.c
+++ b/drivers/mtd/nand/raw/nand_spl_loaders.c
@@ -41,6 +41,34 @@
 	return 0;
 }
 
+/**
+ * nand_spl_adjust_offset - Adjust offset from a starting sector
+ * @sector:	Address of the sector
+ * @offs:	Offset starting from @sector
+ *
+ * If one or more bad blocks are in the address space between @sector
+ * and @sector + @offs, @offs is increased by the NAND block size for
+ * each bad block found.
+ */
+u32 nand_spl_adjust_offset(u32 sector, u32 offs)
+{
+	unsigned int block, lastblock;
+
+	block = sector / CONFIG_SYS_NAND_BLOCK_SIZE;
+	lastblock = (sector + offs) / CONFIG_SYS_NAND_BLOCK_SIZE;
+
+	while (block <= lastblock) {
+		if (nand_is_bad_block(block)) {
+			offs += CONFIG_SYS_NAND_BLOCK_SIZE;
+			lastblock++;
+		}
+
+		block++;
+	}
+
+	return offs;
+}
+
 #ifdef CONFIG_SPL_UBI
 /*
  * Temporary storage for non NAND page aligned and non NAND page sized
diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c
index 36016de..9a8145e 100644
--- a/drivers/tpm/tpm2_tis_spi.c
+++ b/drivers/tpm/tpm2_tis_spi.c
@@ -676,7 +676,7 @@
 
 static const struct udevice_id tpm_tis_spi_ids[] = {
 	{
-		.compatible = "tis,tpm2-spi",
+		.compatible = "tcg,tpm_tis-spi",
 		.data = (ulong)&tpm_tis_std_chip_data,
 	},
 	{ }
diff --git a/drivers/tpm/tpm_tis.h b/drivers/tpm/tpm_tis.h
index 947585f..2a160fe 100644
--- a/drivers/tpm/tpm_tis.h
+++ b/drivers/tpm/tpm_tis.h
@@ -104,6 +104,7 @@
 /* Max number of iterations after i2c NAK */
 #define MAX_COUNT		3
 
+#ifndef __TPM_V2_H
 /*
  * Max number of iterations after i2c NAK for 'long' commands
  *
@@ -127,5 +128,6 @@
 	TPM_STS_DATA_AVAIL		= 0x10,
 	TPM_STS_DATA_EXPECT		= 0x08,
 };
+#endif
 
 #endif
diff --git a/include/compiler.h b/include/compiler.h
index ed74c27..90b7afa 100644
--- a/include/compiler.h
+++ b/include/compiler.h
@@ -145,7 +145,9 @@
 #define unlikely(x)	__builtin_expect(!!(x), 0)
 
 #ifdef __LP64__
-#define MEM_SUPPORT_64BIT_DATA
+#define MEM_SUPPORT_64BIT_DATA	1
+#else
+#define MEM_SUPPORT_64BIT_DATA	0
 #endif
 
 #endif
diff --git a/include/debug_uart.h b/include/debug_uart.h
index 4d1c580..714b369 100644
--- a/include/debug_uart.h
+++ b/include/debug_uart.h
@@ -112,7 +112,7 @@
 void printdec(unsigned int value);
 
 #ifdef CONFIG_DEBUG_UART_ANNOUNCE
-#define _DEBUG_UART_ANNOUNCE	printascii("<debug_uart> ");
+#define _DEBUG_UART_ANNOUNCE	printascii("\n<debug_uart>\n");
 #else
 #define _DEBUG_UART_ANNOUNCE
 #endif
diff --git a/include/nand.h b/include/nand.h
index 93cbe1e..80dd646 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -120,6 +120,7 @@
 		int allexcept);
 int nand_get_lock_status(struct mtd_info *mtd, loff_t offset);
 
+u32 nand_spl_adjust_offset(u32 sector, u32 offs);
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
 int nand_spl_read_block(int block, int offset, int len, void *dst);
 void nand_deselect(void);
diff --git a/include/spl.h b/include/spl.h
index b31c9bb..580e4e0 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -155,7 +155,7 @@
 #endif
 };
 
-/*
+/**
  * Information required to load data from a device
  *
  * @dev: Pointer to the device, e.g. struct mmc *
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index d53d2e4..f6c045d 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -70,6 +70,7 @@
  * @TPM2_CC_DAM_RESET: TPM2_DictionaryAttackLockReset().
  * @TPM2_CC_DAM_PARAMETERS: TPM2_DictionaryAttackParameters().
  * @TPM2_CC_GET_CAPABILITY: TPM2_GetCapibility().
+ * @TPM2_CC_GET_RANDOM: TPM2_GetRandom().
  * @TPM2_CC_PCR_READ: TPM2_PCR_Read().
  * @TPM2_CC_PCR_EXTEND: TPM2_PCR_Extend().
  * @TPM2_CC_PCR_SETAUTHVAL: TPM2_PCR_SetAuthValue().
@@ -85,6 +86,7 @@
 	TPM2_CC_DAM_PARAMETERS	= 0x013A,
 	TPM2_CC_NV_READ         = 0x014E,
 	TPM2_CC_GET_CAPABILITY	= 0x017A,
+	TPM2_CC_GET_RANDOM      = 0x017B,
 	TPM2_CC_PCR_READ	= 0x017E,
 	TPM2_CC_PCR_EXTEND	= 0x0182,
 	TPM2_CC_PCR_SETAUTHVAL	= 0x0183,
@@ -339,4 +341,15 @@
 			  const ssize_t pw_sz, u32 index, const char *key,
 			  const ssize_t key_sz);
 
+/**
+ * Issue a TPM2_GetRandom command.
+ *
+ * @dev		TPM device
+ * @param data		output buffer for the random bytes
+ * @param count		size of output buffer
+ *
+ * @return return code of the operation
+ */
+u32 tpm2_get_random(struct udevice *dev, void *data, u32 count);
+
 #endif /* __TPM_V2_H */
diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h
index 2d3024d..a0bae49 100644
--- a/include/u-boot/rsa.h
+++ b/include/u-boot/rsa.h
@@ -83,6 +83,20 @@
 
 #if IMAGE_ENABLE_VERIFY
 /**
+ * rsa_verify_hash() - Verify a signature against a hash
+ *
+ * Verify a RSA PKCS1.5 signature against an expected hash.
+ *
+ * @info:	Specifies key and FIT information
+ * @hash:	Hash according to algorithm specified in @info
+ * @sig:	Signature
+ * @sig_len:	Number of bytes in signature
+ * @return 0 if verified, -ve on error
+ */
+int rsa_verify_hash(struct image_sign_info *info,
+		    const uint8_t *hash, uint8_t *sig, uint sig_len);
+
+/**
  * rsa_verify() - Verify a signature against some data
  *
  * Verify a RSA PKCS1.5 signature against an expected hash.
@@ -108,6 +122,13 @@
 		       const uint8_t *hash, int hash_len);
 #endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
 #else
+static inline int rsa_verify_hash(struct image_sign_info *info,
+				  const uint8_t *hash,
+				  uint8_t *sig, uint sig_len)
+{
+	return -ENXIO;
+}
+
 static inline int rsa_verify(struct image_sign_info *info,
 		const struct image_region region[], int region_count,
 		uint8_t *sig, uint sig_len)
diff --git a/lib/display_options.c b/lib/display_options.c
index 1dd5b6a..ea9977c 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -138,19 +138,13 @@
 {
 	/* linebuf as a union causes proper alignment */
 	union linebuf {
-#ifdef MEM_SUPPORT_64BIT_DATA
 		uint64_t uq[MAX_LINE_LENGTH_BYTES/sizeof(uint64_t) + 1];
-#endif
 		uint32_t ui[MAX_LINE_LENGTH_BYTES/sizeof(uint32_t) + 1];
 		uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1];
 		uint8_t  uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1];
 	} lb;
 	int i;
-#ifdef MEM_SUPPORT_64BIT_DATA
-	uint64_t __maybe_unused x;
-#else
-	uint32_t __maybe_unused x;
-#endif
+	ulong x;
 
 	if (linelen*width > MAX_LINE_LENGTH_BYTES)
 		linelen = MAX_LINE_LENGTH_BYTES / width;
@@ -169,20 +163,16 @@
 		for (i = 0; i < thislinelen; i++) {
 			if (width == 4)
 				x = lb.ui[i] = *(volatile uint32_t *)data;
-#ifdef MEM_SUPPORT_64BIT_DATA
-			else if (width == 8)
-				x = lb.uq[i] = *(volatile uint64_t *)data;
-#endif
+			else if (MEM_SUPPORT_64BIT_DATA && width == 8)
+				x = lb.uq[i] = *(volatile ulong *)data;
 			else if (width == 2)
 				x = lb.us[i] = *(volatile uint16_t *)data;
 			else
 				x = lb.uc[i] = *(volatile uint8_t *)data;
 #if defined(CONFIG_SPL_BUILD)
 			printf(" %x", (uint)x);
-#elif defined(MEM_SUPPORT_64BIT_DATA)
-			printf(" %0*llx", width * 2, (long long)x);
 #else
-			printf(" %0*x", width * 2, x);
+			printf(" %0*lx", width * 2, x);
 #endif
 			data += width;
 		}
diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
index 14ed3cb..8b75d41 100644
--- a/lib/rsa/Makefile
+++ b/lib/rsa/Makefile
@@ -5,6 +5,6 @@
 # (C) Copyright 2000-2007
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
-obj-$(CONFIG_$(SPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o
-obj-$(CONFIG_RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o
+obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o
+obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o
 obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o
diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c
index 9464df0..1e83eed 100644
--- a/lib/rsa/rsa-keyprop.c
+++ b/lib/rsa/rsa-keyprop.c
@@ -654,21 +654,17 @@
 {
 	struct rsa_key rsa_key;
 	uint32_t *n = NULL, *rr = NULL, *rrtmp = NULL;
-	const int max_rsa_size = 4096;
-	int rlen, i, ret;
+	int rlen, i, ret = 0;
 
 	*prop = calloc(sizeof(**prop), 1);
-	n = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5));
-	rr = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5));
-	rrtmp = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5));
-	if (!(*prop) || !n || !rr || !rrtmp) {
+	if (!(*prop)) {
 		ret = -ENOMEM;
-		goto err;
+		goto out;
 	}
 
 	ret = rsa_parse_pub_key(&rsa_key, key, keylen);
 	if (ret)
-		goto err;
+		goto out;
 
 	/* modulus */
 	/* removing leading 0's */
@@ -678,20 +674,28 @@
 	(*prop)->modulus = malloc(rsa_key.n_sz - i);
 	if (!(*prop)->modulus) {
 		ret = -ENOMEM;
-		goto err;
+		goto out;
 	}
 	memcpy((void *)(*prop)->modulus, &rsa_key.n[i], rsa_key.n_sz - i);
 
+	n = calloc(sizeof(uint32_t), 1 + ((*prop)->num_bits >> 5));
+	rr = calloc(sizeof(uint32_t), 1 + (((*prop)->num_bits * 2) >> 5));
+	rrtmp = calloc(sizeof(uint32_t), 2 + (((*prop)->num_bits * 2) >> 5));
+	if (!n || !rr || !rrtmp) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
 	/* exponent */
 	(*prop)->public_exponent = calloc(1, sizeof(uint64_t));
 	if (!(*prop)->public_exponent) {
 		ret = -ENOMEM;
-		goto err;
+		goto out;
 	}
 	memcpy((void *)(*prop)->public_exponent + sizeof(uint64_t)
 						- rsa_key.e_sz,
 	       rsa_key.e, rsa_key.e_sz);
-	(*prop)->exp_len = rsa_key.e_sz;
+	(*prop)->exp_len = sizeof(uint64_t);
 
 	/* n0 inverse */
 	br_i32_decode(n, &rsa_key.n[i], rsa_key.n_sz - i);
@@ -710,16 +714,15 @@
 	(*prop)->rr = malloc(rlen);
 	if (!(*prop)->rr) {
 		ret = -ENOMEM;
-		goto err;
+		goto out;
 	}
 	br_i32_encode((void *)(*prop)->rr, rlen, rr);
 
-	return 0;
-
-err:
+out:
 	free(n);
 	free(rr);
 	free(rrtmp);
-	rsa_free_key_prop(*prop);
+	if (ret < 0)
+		rsa_free_key_prop(*prop);
 	return ret;
 }
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index 1d55b99..6c4bbc4 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -194,6 +194,19 @@
 	return ret;
 }
 
+/*
+ * padding_pss_verify() - verify the pss padding of a signature
+ *
+ * Only works with a rsa_pss_saltlen:-2 (default value) right now
+ * saltlen:-1 "set the salt length to the digest length" is currently
+ * not supported.
+ *
+ * @info:	Specifies key and FIT information
+ * @msg:	byte array of message, len equal to msg_len
+ * @msg_len:	Message length
+ * @hash:	Pointer to the expected hash
+ * @hash_len:	Length of the hash
+ */
 int padding_pss_verify(struct image_sign_info *info,
 		       uint8_t *msg, int msg_len,
 		       const uint8_t *hash, int hash_len)
@@ -285,7 +298,7 @@
 }
 #endif
 
-#if CONFIG_IS_ENABLED(FIT_SIGNATURE) || IS_ENABLED(CONFIG_RSA_VERIFY_WITH_PKEY)
+#if CONFIG_IS_ENABLED(FIT_SIGNATURE) || CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY)
 /**
  * rsa_verify_key() - Verify a signature against some data using RSA Key
  *
@@ -359,7 +372,7 @@
 }
 #endif
 
-#ifdef CONFIG_RSA_VERIFY_WITH_PKEY
+#if CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY)
 /**
  * rsa_verify_with_pkey() - Verify a signature against some data using
  * only modulus and exponent as RSA key properties.
@@ -465,34 +478,12 @@
 }
 #endif
 
-int rsa_verify(struct image_sign_info *info,
-	       const struct image_region region[], int region_count,
-	       uint8_t *sig, uint sig_len)
+int rsa_verify_hash(struct image_sign_info *info,
+		    const uint8_t *hash, uint8_t *sig, uint sig_len)
 {
-	/* Reserve memory for maximum checksum-length */
-	uint8_t hash[info->crypto->key_len];
 	int ret = -EACCES;
 
-	/*
-	 * Verify that the checksum-length does not exceed the
-	 * rsa-signature-length
-	 */
-	if (info->checksum->checksum_len >
-	    info->crypto->key_len) {
-		debug("%s: invlaid checksum-algorithm %s for %s\n",
-		      __func__, info->checksum->name, info->crypto->name);
-		return -EINVAL;
-	}
-
-	/* Calculate checksum with checksum-algorithm */
-	ret = info->checksum->calculate(info->checksum->name,
-					region, region_count, hash);
-	if (ret < 0) {
-		debug("%s: Error in checksum calculation\n", __func__);
-		return -EINVAL;
-	}
-
-	if (IS_ENABLED(CONFIG_RSA_VERIFY_WITH_PKEY) && !info->fdt_blob) {
+	if (CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) && !info->fdt_blob) {
 		/* don't rely on fdt properties */
 		ret = rsa_verify_with_pkey(info, hash, sig, sig_len);
 
@@ -542,3 +533,33 @@
 
 	return ret;
 }
+
+int rsa_verify(struct image_sign_info *info,
+	       const struct image_region region[], int region_count,
+	       uint8_t *sig, uint sig_len)
+{
+	/* Reserve memory for maximum checksum-length */
+	uint8_t hash[info->crypto->key_len];
+	int ret = -EACCES;
+
+	/*
+	 * Verify that the checksum-length does not exceed the
+	 * rsa-signature-length
+	 */
+	if (info->checksum->checksum_len >
+	    info->crypto->key_len) {
+		debug("%s: invlaid checksum-algorithm %s for %s\n",
+		      __func__, info->checksum->name, info->crypto->name);
+		return -EINVAL;
+	}
+
+	/* Calculate checksum with checksum-algorithm */
+	ret = info->checksum->calculate(info->checksum->name,
+					region, region_count, hash);
+	if (ret < 0) {
+		debug("%s: Error in checksum calculation\n", __func__);
+		return -EINVAL;
+	}
+
+	return rsa_verify_hash(info, hash, sig, sig_len);
+}
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 5a039f6..a4c352e 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -422,3 +422,47 @@
 
 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }
+
+u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
+{
+	const u8 command_v2[10] = {
+		tpm_u16(TPM2_ST_NO_SESSIONS),
+		tpm_u32(12),
+		tpm_u32(TPM2_CC_GET_RANDOM),
+	};
+	u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+
+	const size_t data_size_offset = 10;
+	const size_t data_offset = 12;
+	size_t response_length = sizeof(response);
+	u32 data_size;
+	u8 *out = data;
+
+	while (count > 0) {
+		u32 this_bytes = min((size_t)count,
+				     sizeof(response) - data_offset);
+		u32 err;
+
+		if (pack_byte_string(buf, sizeof(buf), "sw",
+				     0, command_v2, sizeof(command_v2),
+				     sizeof(command_v2), this_bytes))
+			return TPM_LIB_ERROR;
+		err = tpm_sendrecv_command(dev, buf, response,
+					   &response_length);
+		if (err)
+			return err;
+		if (unpack_byte_string(response, response_length, "w",
+				       data_size_offset, &data_size))
+			return TPM_LIB_ERROR;
+		if (data_size > this_bytes)
+			return TPM_LIB_ERROR;
+		if (unpack_byte_string(response, response_length, "s",
+				       data_offset, out, data_size))
+			return TPM_LIB_ERROR;
+
+		count -= data_size;
+		out += data_size;
+	}
+
+	return 0;
+}
diff --git a/test/Makefile b/test/Makefile
index bab8f1a..7c40399 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -3,6 +3,7 @@
 # (C) Copyright 2012 The Chromium Authors
 
 obj-$(CONFIG_SANDBOX) += bloblist.o
+obj-$(CONFIG_CMDLINE) += cmd/
 obj-$(CONFIG_UNIT_TEST) += cmd_ut.o
 obj-$(CONFIG_UNIT_TEST) += ut.o
 obj-$(CONFIG_SANDBOX) += command_ut.o
diff --git a/test/cmd/Makefile b/test/cmd/Makefile
new file mode 100644
index 0000000..85d38f0
--- /dev/null
+++ b/test/cmd/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2013 Google, Inc
+
+obj-$(CONFIG_MEM_SEARCH) += mem_search.o
diff --git a/test/cmd/mem_search.c b/test/cmd/mem_search.c
new file mode 100644
index 0000000..d57bfad
--- /dev/null
+++ b/test/cmd/mem_search.c
@@ -0,0 +1,275 @@
+// 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);
+