[U-Boot] [PATCH 1/1] cmd: add exception command

Heinrich Schuchardt xypron.glpk at gmx.de
Sat Nov 17 14:28:46 UTC 2018


The 'exception' command allows to test exception handling.

This implementation supports ARM, x86, RISC-V and the following exceptions:
* 'breakpoint' - prefetch abort exception (ARM 32bit only)
* 'unaligned'  - data abort exception (ARM only)
* 'undefined'  - undefined instruction exception

Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
---
Currently RISC-V 64bit gets into an endless loop when hitting the
undefined instruction.

So it makes sense to have a testing capability.
---
 cmd/Kconfig     |   6 ++
 cmd/Makefile    |   1 +
 cmd/exception.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 cmd/exception.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index e2973b3c51..9d2b8199b8 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1388,6 +1388,12 @@ config CMD_DISPLAY
 	  displayed on a simple board-specific display. Implement
 	  display_putc() to use it.
 
+config CMD_EXCEPTION
+	bool "exception - raise exception"
+	depends on ARM || RISCV || X86
+	help
+	  Enable the 'exception' command which allows to raise an exception.
+
 config CMD_LED
 	bool "led"
 	default y if LED
diff --git a/cmd/Makefile b/cmd/Makefile
index 0534ddc679..cd67a79170 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -46,6 +46,7 @@ endif
 obj-$(CONFIG_CMD_DISPLAY) += display.o
 obj-$(CONFIG_CMD_DTIMG) += dtimg.o
 obj-$(CONFIG_CMD_ECHO) += echo.o
+obj-$(CONFIG_CMD_EXCEPTION) += exception.o
 obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
 obj-$(CONFIG_CMD_EEPROM) += eeprom.o
 obj-$(CONFIG_EFI_STUB) += efi.o
diff --git a/cmd/exception.c b/cmd/exception.c
new file mode 100644
index 0000000000..fb6a15573e
--- /dev/null
+++ b/cmd/exception.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * The 'exception' command can be used for testing exception handling.
+ *
+ * Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk at gmx.de>
+ */
+#include <common.h>
+#include <command.h>
+
+enum exception {
+	UNDEFINED_INSTRUCTION = 1,
+	DATA_ABORT,
+	BREAKPOINT,
+};
+
+struct exception_str {
+	enum exception id;
+	char *text;
+	void (*func)(void);
+};
+
+#if defined(CONFIG_ARM)
+static void data_abort(void)
+{
+#if defined(CONFIG_ARM64)
+	/*
+	 * The LDR instruction requires the data source to be eight byte
+	 * aligned.
+	 */
+	asm volatile (
+		"MOV x1, sp\n"
+		"ADD x1, x1, 1\n"
+		"LDR x3, [x1]\n");
+#else
+	/*
+	 * The LDRD instruction requires the data source to be four byte aligned
+	 * even if strict alignment fault checking is disabled in the system
+	 * control register.
+	 */
+	asm volatile (
+		"MOV r5, sp\n"
+		"ADD r5, #1\n"
+		"LDRD r6, r7, [r5]\n");
+#endif
+}
+
+#if !defined(CONFIG_ARM64)
+static void breakpoint(void)
+{
+	asm volatile ("BKPT #123\n");
+}
+#endif
+#endif
+
+static void undefined_instruction(void)
+{
+#if defined(CONFIG_ARM)
+	/*
+	 * 0xe7f...f.	is undefined in ARM mode
+	 * 0xde..	is undefined in Thumb mode
+	 */
+	asm volatile (".word 0xe7f7defb\n");
+#elif defined(CONFIG_RISCV)
+	asm volatile (".word 0xffffffff\n");
+#elif defined(CONFIG_X86)
+	asm volatile (".word 0xffff\n");
+#endif
+}
+
+struct exception_str exceptions[] = {
+#if defined(CONFIG_ARM)
+#if !defined(CONFIG_ARM64)
+	{ BREAKPOINT, "breakpoint", breakpoint },
+#endif
+	{ DATA_ABORT, "unaligned", data_abort },
+#endif
+	{ UNDEFINED_INSTRUCTION, "undefined", undefined_instruction },
+	{ 0, NULL, NULL },
+};
+
+static int do_exception(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	struct exception_str *ex;
+	enum exception id = 0;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	for (ex = exceptions; ex->func ; ++ex) {
+		if (!strcmp(argv[1], ex->text)) {
+			id = ex->id;
+			break;
+		}
+	}
+	switch (id) {
+#if defined(CONFIG_ARM)
+#if !defined(CONFIG_ARM64)
+	case BREAKPOINT:
+		breakpoint();
+		break;
+#endif
+	case DATA_ABORT:
+		data_abort();
+		break;
+#endif
+	case UNDEFINED_INSTRUCTION:
+		undefined_instruction();
+		break;
+	default:
+		return CMD_RET_USAGE;
+	}
+
+	return CMD_RET_FAILURE;
+}
+
+static int exception_complete(int argc, char * const argv[], char last_char,
+			      int maxv, char *cmdv[])
+{
+	int len = 0;
+	struct exception_str *ex;
+	int i = 0;
+
+	switch (argc) {
+	case 1:
+		break;
+	case 2:
+		len = strlen(argv[1]);
+		break;
+	default:
+		return 0;
+	}
+	for (ex = exceptions; ex->func ; ++ex) {
+		if (i >= maxv - 1)
+			return i;
+		if (!strncmp(argv[1], ex->text, len))
+			cmdv[i++] = ex->text;
+	}
+	cmdv[i] = NULL;
+	return i;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char exception_help_text[] =
+	"<ex>\n"
+	"  The following exceptions are available:\n"
+#if defined(CONFIG_ARM)
+#if !defined(CONFIG_ARM64)
+	"  breakpoint - prefetch abort\n"
+#endif
+	"  unaligned  - data abort\n"
+#endif
+#endif
+	"  undefined  - undefined instruction\n"
+	;
+
+U_BOOT_CMD_COMPLETE(
+	exception, 2, 0, do_exception,
+	"Forces an exception to occur",
+	exception_help_text, exception_complete
+);
-- 
2.19.1



More information about the U-Boot mailing list