From 1536da3497050878d358234ff2a52f6d89ca80b1 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Fri, 4 Oct 2019 09:58:29 +0200
Subject: [PATCH] feat(epicardium): Add a panic() function

In unrecoverable situations we should provide a common way to output the
cause of the error and then reset the CPU.  The panic() function is
mean to be exactly that.  It outputs the error-cause, stack-trace, and
firmware revision, accompanied by a link to the issue-tracker to
encourage people to report the error.  After a timeout of ~1.5s it
resets the CPU and reboots.

Future Work:

 - Right now, the stack-trace only has a depth of one which is the
   return address from where panic() was called.  In the future it might
   make sense to provide a deeper stack-trace if a robust implementation
   is possible.
 - Integration of @msgctl's faultscreen (!79) so users who don't have
   the serial console open at all times can also see what happened.

Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/modules/meson.build |  1 +
 epicardium/modules/modules.h   |  4 +++
 epicardium/modules/panic.c     | 63 ++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+)
 create mode 100644 epicardium/modules/panic.c

diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 21a04ba5..022397ca 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -14,6 +14,7 @@ module_sources = files(
   'light_sensor.c',
   'log.c',
   'max30001.c',
+  'panic.c',
   'personal_state.c',
   'pmic.c',
   'rtc.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index 465c78a4..bf59566b 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -8,6 +8,10 @@
 #include <stdint.h>
 #include <stdbool.h>
 
+/* ---------- Panic -------------------------------------------------------- */
+void panic(const char *format, ...)
+	__attribute__((noreturn, format(printf, 1, 2)));
+
 /* ---------- Dispatcher --------------------------------------------------- */
 void vApiDispatcher(void *pvParameters);
 void dispatcher_mutex_init(void);
diff --git a/epicardium/modules/panic.c b/epicardium/modules/panic.c
new file mode 100644
index 00000000..e37f3d7a
--- /dev/null
+++ b/epicardium/modules/panic.c
@@ -0,0 +1,63 @@
+/*
+ * Panic
+ * =====
+ *
+ * Under some conditions the firmware should crash and reboot automatically.
+ * This module provides the necessary facilities to do so.
+ *
+ * Note that a panic should indicate **only** logic-errors in the firmware or
+ * unrecoverable hardware conditions.
+ */
+
+#include "modules/log.h"
+#include "modules/modules.h"
+
+#include "card10.h"
+#include "card10-version.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+void __attribute__((noreturn)) panic(const char *format, ...)
+{
+	/* Turn off interrupts.  We won't get back from here anyway. */
+	__asm volatile("cpsid	i" ::: "memory");
+
+	/*
+	 * Turn off asynchronous printing because that won't ever work from
+	 * here ...
+	 */
+	serial_return_to_synchronous();
+
+	printf("\x1b[31;1m           --- SYSTEM PANIC ---\n"
+	       "\x1b[0;31m         ---                  ---\n"
+	       "       ---                      ---\n"
+	       "\x1b[0m A fatal error occured:\n     \x1b[1m");
+
+	va_list ap;
+	va_start(ap, format);
+	vprintf(format, ap);
+	va_end(ap);
+
+	printf("\n"
+	       "\x1b[0m\n"
+	       " Firmware Version:\n"
+	       "\x1b[35m     %s\n",
+	       CARD10_VERSION);
+
+	printf("\x1b[0m\n"
+	       " Stack Trace:\n"
+	       "\x1b[36m     %p\n",
+	       __builtin_return_address(0));
+
+	printf("\x1b[33m\n"
+	       " Please report this error to the card10 firmware team!\n"
+	       "\x1b[0m -> https://git.card10.badge.events.ccc.de/card10/firmware/issues/new?issue <-\n"
+	       "\x1b[31m           --- ====== ===== ---\x1b[0m\n");
+
+	for (int i = 0; i < 96000000; i++) {
+		__asm volatile("nop");
+	}
+
+	card10_reset();
+}
-- 
GitLab