]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
sandbox: add handler for exceptions
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Wed, 11 Nov 2020 23:29:56 +0000 (00:29 +0100)
committerSimon Glass <sjg@chromium.org>
Sun, 13 Dec 2020 14:58:17 +0000 (07:58 -0700)
Add a handler for SIGILL, SIGBUS, SIGSEGV.

When an exception occurs print the program counter and the loaded
UEFI binaries and reset the system if CONFIG_SANDBOX_CRASH_RESET=y
or exit to the OS otherwise.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/sandbox/Kconfig
arch/sandbox/cpu/os.c
arch/sandbox/cpu/start.c
arch/sandbox/lib/interrupts.c
include/os.h

index 65f988e7369acf23efdfd35a59f5d85332ded3ba..f83282d9d56ac15165a893f24e88466babacf348 100644 (file)
@@ -51,6 +51,15 @@ config HOST_64BIT
 
 endchoice
 
+config SANDBOX_CRASH_RESET
+       bool "Reset on crash"
+       help
+         If an illegal instruction or an illegal memory access occurs, the
+         sandbox by default writes a crash dump and exits. If you set this
+         flag, the sandbox is reset instead. This may be useful when running
+         test suites like the UEFI self certification test which continue
+         with the next test after a crash.
+
 config SANDBOX_BITS_PER_LONG
        int
        default 32 if HOST_32BIT
index 0d8efd83f6239dbb625beb6739b39e319684265d..b56fa04a34b5cd497a04c79ffd4200e11767ad1c 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (c) 2011 The Chromium OS Authors.
  */
 
+#define _GNU_SOURCE
+
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
 #include <termios.h>
 #include <time.h>
+#include <ucontext.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <linux/compiler_attributes.h>
 #include <linux/types.h>
 
 #include <asm/getopt.h>
@@ -191,6 +195,42 @@ static void os_sigint_handler(int sig)
        raise(SIGINT);
 }
 
+static void os_signal_handler(int sig, siginfo_t *info, void *con)
+{
+       ucontext_t __maybe_unused *context = con;
+       unsigned long pc;
+
+#if defined(__x86_64__)
+       pc = context->uc_mcontext.gregs[REG_RIP];
+#elif defined(__aarch64__)
+       pc = context->uc_mcontext.pc;
+#elif defined(__riscv)
+       pc = context->uc_mcontext.__gregs[REG_PC];
+#else
+       const char msg[] =
+               "\nUnsupported architecture, cannot read program counter\n";
+
+       os_write(1, msg, sizeof(msg));
+       pc = 0;
+#endif
+
+       os_signal_action(sig, pc);
+}
+
+int os_setup_signal_handlers(void)
+{
+       struct sigaction act;
+
+       act.sa_sigaction = os_signal_handler;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = SA_SIGINFO | SA_NODEFER;
+       if (sigaction(SIGILL, &act, NULL) ||
+           sigaction(SIGBUS, &act, NULL) ||
+           sigaction(SIGSEGV, &act, NULL))
+               return -1;
+       return 0;
+}
+
 /* Put tty into raw mode so <tab> and <ctrl+c> work */
 void os_tty_raw(int fd, bool allow_sigs)
 {
index a03e5aa0b3038c5a421c65561cfb3c33235067b2..f6c98545e0d59d83deaff84008db802ddbafb093 100644 (file)
@@ -451,6 +451,10 @@ int main(int argc, char *argv[])
        if (ret)
                goto err;
 
+       ret = os_setup_signal_handlers();
+       if (ret)
+               goto err;
+
 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
        gd->malloc_base = CONFIG_MALLOC_F_ADDR;
 #endif
index 21f761ac3b0f96833f066c598134c637bca6e563..9c2c60b8c6854ec790cb6d089a685e6ee7780334 100644 (file)
@@ -6,7 +6,13 @@
  */
 
 #include <common.h>
+#include <efi_loader.h>
 #include <irq_func.h>
+#include <os.h>
+#include <asm-generic/signal.h>
+#include <asm/u-boot-sandbox.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 int interrupt_init(void)
 {
@@ -21,3 +27,32 @@ int disable_interrupts(void)
 {
        return 0;
 }
+
+void os_signal_action(int sig, unsigned long pc)
+{
+       efi_restore_gd();
+
+       switch (sig) {
+       case SIGILL:
+               printf("\nIllegal instruction\n");
+               break;
+       case SIGBUS:
+               printf("\nBus error\n");
+               break;
+       case SIGSEGV:
+               printf("\nSegmentation violation\n");
+               break;
+       default:
+               break;
+       }
+       printf("pc = 0x%lx, ", pc);
+       printf("pc_reloc = 0x%lx\n\n", pc - gd->reloc_off);
+       efi_print_image_infos((void *)pc);
+
+       if (IS_ENABLED(CONFIG_SANDBOX_CRASH_RESET)) {
+               printf("resetting ...\n\n");
+               sandbox_reset();
+       } else {
+               sandbox_exit();
+       }
+}
index 1fe44f351053d699d6cc87ca6aa9681ca022754c..0913b47b3a853127dbc1e3294362346edbd615cd 100644 (file)
@@ -407,4 +407,21 @@ void *os_find_text_base(void);
  */
 void os_relaunch(char *argv[]);
 
+/**
+ * os_setup_signal_handlers() - setup signal handlers
+ *
+ * Install signal handlers for SIGBUS and SIGSEGV.
+ *
+ * Return:     0 for success
+ */
+int os_setup_signal_handlers(void);
+
+/**
+ * os_signal_action() - handle a signal
+ *
+ * @sig:       signal
+ * @pc:                program counter
+ */
+void os_signal_action(int sig, unsigned long pc);
+
 #endif