diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index d6170adaf5..5e66304e2b 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -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; diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 48a7fd2bc2..0475672968 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -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 diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index e18e666f12..34e90674ee 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -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 diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e55deaf906..29e375e117 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -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 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 0e2f582a5f..446d961d7d 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -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 index 0000000000..71bb5d924e --- /dev/null +++ b/drivers/watchdog/sandbox_alarm-wdt.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include + +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), +}; diff --git a/include/os.h b/include/os.h index 5b353ae9d9..54874f5e0e 100644 --- a/include/os.h +++ b/include/os.h @@ -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 *