]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
sandbox: add SIGALRM-based watchdog device
authorRasmus Villemoes <rasmus.villemoes@prevas.dk>
Tue, 27 Sep 2022 09:54:04 +0000 (11:54 +0200)
committerStefan Roese <sr@denx.de>
Mon, 24 Oct 2022 09:10:21 +0000 (11:10 +0200)
In order to test that U-Boot actually maintains the watchdog device(s)
during long-running busy-loops, such as those where we wait for the
user to stop autoboot, we need a watchdog device that actually does
something during those loops; we cannot test that behaviour via the DM
test framework.

So introduce a relatively simple watchdog device which is simply based
on calling the host OS' alarm() function; that has the nice property
that a new call to alarm() simply sets a new deadline, and alarm(0)
cancels any existing alarm. These properties are precisely what we
need to implement start/reset/stop. We install our own handler so that
we get a known message printed if and when the watchdog fires, and by
just invoking that handler directly, we get expire_now for free.

The actual calls to the various OS functions (alarm, signal, raise)
need to be done in os.c, and since the driver code cannot get access
to the values of SIGALRM or SIG_DFL (that would require including a
host header, and that's only os.c which can do that), we cannot simply
do trivial wrappers for signal() and raise(), but instead create
specialized functions just for use by this driver.

Apart from enabling this driver for sandbox{,64}_defconfig, also
enable the wdt command which was useful for hand-testing this new
driver (especially with running u-boot under strace).

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
arch/sandbox/cpu/os.c
configs/sandbox64_defconfig
configs/sandbox_defconfig
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/sandbox_alarm-wdt.c [new file with mode: 0644]
include/os.h

index d6170adaf5e8e92a0975ca364a9cad1300cec144..5e66304e2b9dfdd544d99563b0a56b186d83e051 100644 (file)
@@ -130,6 +130,23 @@ void os_exit(int exit_code)
        exit(exit_code);
 }
 
+unsigned int os_alarm(unsigned int seconds)
+{
+       return alarm(seconds);
+}
+
+void os_set_alarm_handler(void (*handler)(int))
+{
+       if (!handler)
+               handler = SIG_DFL;
+       signal(SIGALRM, handler);
+}
+
+void os_raise_sigalrm(void)
+{
+       raise(SIGALRM);
+}
+
 int os_write_file(const char *fname, const void *buf, int size)
 {
        int fd;
index 48a7fd2bc220b4257f87ff36cd5659e87c99ba6f..0475672968242f2c99006ca45b32e513420a9023 100644 (file)
@@ -56,6 +56,7 @@ CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_CAT=y
+CONFIG_CMD_WDT=y
 CONFIG_BOOTP_DNS2=y
 CONFIG_CMD_TFTPPUT=y
 CONFIG_CMD_TFTPSRV=y
@@ -238,6 +239,7 @@ CONFIG_SPLASH_SCREEN_ALIGN=y
 CONFIG_WDT=y
 CONFIG_WDT_GPIO=y
 CONFIG_WDT_SANDBOX=y
+CONFIG_WDT_ALARM_SANDBOX=y
 CONFIG_FS_CBFS=y
 CONFIG_FS_CRAMFS=y
 CONFIG_CMD_DHRYSTONE=y
index e18e666f126de66f1b81d79a5f94cbe48618d088..34e90674eeca770e1bb3e5904ace8bb37ddd8d14 100644 (file)
@@ -80,6 +80,7 @@ CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_TEMPERATURE=y
 CONFIG_CMD_USB=y
+CONFIG_CMD_WDT=y
 CONFIG_CMD_AXI=y
 CONFIG_CMD_CAT=y
 CONFIG_CMD_SETEXPR_FMT=y
@@ -314,6 +315,7 @@ CONFIG_W1_EEPROM_SANDBOX=y
 CONFIG_WDT=y
 CONFIG_WDT_GPIO=y
 CONFIG_WDT_SANDBOX=y
+CONFIG_WDT_ALARM_SANDBOX=y
 CONFIG_FS_CBFS=y
 CONFIG_FS_CRAMFS=y
 CONFIG_ADDR_MAP=y
index e55deaf906b56613ec25452a869eddbb73863584..29e375e11785f6bca47096758bfbf6d15c4f8a69 100644 (file)
@@ -281,6 +281,14 @@ config WDT_SANDBOX
          can be probed and supports all of the methods of WDT, but does not
          really do anything.
 
+config WDT_ALARM_SANDBOX
+       bool "Enable SIGALRM-based Watchdog Timer support for Sandbox"
+       depends on SANDBOX && WDT
+       help
+         Enable support for a SIGALRM-based watchdog timer in Sandbox. This is
+         a watchdog device based on the host OS' alarm() function, which will
+         kill the sandbox with SIGALRM unless properly maintained.
+
 config WDT_SBSA
        bool "SBSA watchdog timer support"
        depends on WDT
index 0e2f582a5f99d5612b04755ae8d9002f7ddfe067..446d961d7d2e4ef8aebbff763335df7bb027ac6e 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
 obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
 obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
 obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
+obj-$(CONFIG_WDT_ALARM_SANDBOX) += sandbox_alarm-wdt.o
 obj-$(CONFIG_WDT_APPLE) += apple_wdt.o
 obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
diff --git a/drivers/watchdog/sandbox_alarm-wdt.c b/drivers/watchdog/sandbox_alarm-wdt.c
new file mode 100644 (file)
index 0000000..71bb5d9
--- /dev/null
@@ -0,0 +1,79 @@
+#include <common.h>
+#include <dm.h>
+#include <os.h>
+#include <wdt.h>
+
+struct alarm_wdt_priv {
+       unsigned int timeout_sec;
+};
+
+static void alarm_handler(int sig)
+{
+       const char *msg = "!!! ALARM !!!\n";
+
+       os_write(2, msg, strlen(msg));
+       os_fd_restore();
+       os_set_alarm_handler(NULL);
+       os_raise_sigalrm();
+}
+
+static int alarm_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+       struct alarm_wdt_priv *priv = dev_get_priv(dev);
+       unsigned int sec;
+
+       timeout = DIV_ROUND_UP(timeout, 1000);
+       sec = min_t(u64, UINT_MAX, timeout);
+       priv->timeout_sec = sec;
+
+       os_alarm(0);
+       os_set_alarm_handler(alarm_handler);
+       os_alarm(sec);
+
+       return 0;
+}
+
+static int alarm_wdt_stop(struct udevice *dev)
+{
+       os_alarm(0);
+       os_set_alarm_handler(NULL);
+
+       return 0;
+}
+
+static int alarm_wdt_reset(struct udevice *dev)
+{
+       struct alarm_wdt_priv *priv = dev_get_priv(dev);
+
+       os_alarm(priv->timeout_sec);
+
+       return 0;
+}
+
+static int alarm_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+       alarm_handler(0);
+
+       return 0;
+}
+
+
+static const struct wdt_ops alarm_wdt_ops = {
+       .start = alarm_wdt_start,
+       .reset = alarm_wdt_reset,
+       .stop = alarm_wdt_stop,
+       .expire_now = alarm_wdt_expire_now,
+};
+
+static const struct udevice_id alarm_wdt_ids[] = {
+       { .compatible = "sandbox,alarm-wdt" },
+       {}
+};
+
+U_BOOT_DRIVER(alarm_wdt_sandbox) = {
+       .name = "alarm_wdt_sandbox",
+       .id = UCLASS_WDT,
+       .of_match = alarm_wdt_ids,
+       .ops = &alarm_wdt_ops,
+       .priv_auto = sizeof(struct alarm_wdt_priv),
+};
index 5b353ae9d94b023483fbd88ca81cba5b78168aa3..54874f5e0e88c6dbb10a6e7d0e07cf39efaea5b6 100644 (file)
@@ -108,6 +108,23 @@ int os_unlink(const char *pathname);
  */
 void os_exit(int exit_code) __attribute__((noreturn));
 
+/**
+ * os_alarm() - access to the OS alarm() system call
+ */
+unsigned int os_alarm(unsigned int seconds);
+
+/**
+ * os_set_alarm_handler() - set handler for SIGALRM
+ *
+ * @handler:   The handler function. Pass NULL for SIG_DFL.
+ */
+void os_set_alarm_handler(void (*handler)(int));
+
+/**
+ * os_raise_sigalrm() - do raise(SIGALRM)
+ */
+void os_raise_sigalrm(void);
+
 /**
  * os_tty_raw() - put tty into raw mode to mimic serial console better
  *