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.g...@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.g...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to