Blog:
看门狗在嵌入式 Linux 中的应用
在嵌入式领域中 Watchdog 看门狗通常被作为用于应对系统或者应用意外崩溃的有效手段。其可以在程序执行出错并无法恢复的情况下,自动重启应用甚至复位整个系统,从而使系统脱离宕机状态,恢复正常业务执行。这对于涉及到人身、财产安全的应用,显得极为重要。本文将就 Toradex 嵌入式 Colibri iMX6 计算机模块如何使用看门狗进行介绍,应对 Linux 系统或者应用程序意外崩溃。
Colibri iMX6 计算机模块采用了 NXP iMX6 SoC , 该芯片自带看门狗功能,其硬件和早期的 iMX2 一致,所以看门狗驱动仍然沿用 imx2-wdt。看门狗只支持单用户操作,即只能有一个实例来使用看门狗。因此在 Linux 系统中,用户可以选择由自己的应用直接使用看门狗,但只限于一个进程。看门狗只监控该应用,对于Linux 本身或者其他应用则无法在意外崩溃的情况下触发看门狗复位。或者使用 systemd (183以后的版本)来操作硬件看门狗,同时为用 systemd 所管理的单元提供软件逻辑看门狗。硬件看门狗主要应对 Linux 内核以及 systemd 自身的崩溃,软件逻辑看门狗则可以用于用户自己的应用,且不受数量限制。
用户应用操作
首先在 U-Boot 中设置看门狗超时时间,这里设置为 60 秒。
setenv defargs $defargs imx2-wdt.timeout=60
saveenv
编译完成后运行测试程序。
root@colibri-imx6:~# ./wdt-sample-app &
[1] 627
终结该测试程序进程。当进程被终结后,看门狗仍旧保持运行,但是无法定时喂狗。因此,在60s 超时后,看门狗会复位系统。
root@colibri-imx6:~# kill 627
root@colibri-imx6:~# [ 45.964155] watchdog: watchdog0: watchdog did not stop!
[1]+ Terminated ./wdt-sample-app
当模块由于看门狗复位时,可以从U-Boot 启动的串口日志发现复位的原因。
U-Boot 2016.11-2.8.5+g02735f4004 (Dec 28 2018 - 01:54:12 +0000)
CPU: Freescale i.MX6DL rev1.1 at 792 MHz
Reset cause: WDOG
I2C: ready
DRAM: 512 MiB
Apalis/Colibri iMX8 的看门狗来自 SoC 的 SCU,在配置超时时间需要修改 device tree 中 watchdog 节点的 timeout-sec 属性。
arch/arm64/boot/dts/freescale/imx8qm.dtsiwatchdog {
compatible = "fsl,imx8qm-sc-wdt", "fsl,imx-sc-wdt";
timeout-sec = <60>;
};
arch/arm64/boot/dts/freescale/imx8qxp.dtsiwatchdog {
compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
timeout-sec = <60>;
};
Verdin iMX8M Mini/Plus 采用了和 Colibri iMX6 一样的 imx2-wdt,因此可以通过 imx2-wdt.timeout 参数配置。
setenv defargs $defargs imx2-wdt.timeout=60
saveenv
Systemd 操作
对于需要使用看门狗监控多个应用,可以使用 systemd 来操作。Systemd 提供硬件看门狗和软件看门狗支持。硬件看门狗用于监控 Linux 内核以及 systemd 自身的运行,一旦出现内核崩溃的情况,看门狗超时将触发系统复位。在 systemd 中使用硬件看门狗非常简单,只需要配置 /etc/systemd/system.conf
中的RuntimeWatchdogSec=
参数,将其设置超时时间即可。在规定时间如果没有喂狗,将触发复位。systemd 通常会在所设置时间的一半为间隔进行喂狗。ShutdownWatchdogSec=
则可以设置关机超时时间,如果系统在该时间内没有完成关机,也将系统复位。
为了触发内核崩溃的情况,我们需要开启内核调试的 MAGIC_SYSRQ 功能,该选项在 Toradex 默认的 Linux BSP 中是关闭的。打开后重新编译内核。
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_DEBUG_KERNEL=y
设置超时时间为60秒,RuntimeWatchdogSec=60。
启动查看系统日志,显示硬件看门狗超时时间被设置为1分钟。
root@colibri-imx6:/etc/systemd# dmesg|grep watchdog
[ 3.137012] systemd[1]: Hardware watchdog 'imx2+ watchdog', version 0
[ 3.147564] systemd[1]: Set hardware watchdog to 1min.
然后我们用下面命令触发内核崩溃。echo c > /proc/sysrq-trigger
一分钟以后,由于 systemd 没有对进行喂狗操作,系统将复位后重新启动。
除了硬件看门狗外,sytemd 还提供软件看门狗,每个 systemd service 都可以使用。service 需要读取 WATCHDOG_USEC=
参数,确定看门狗超时时间,并在该时间范围内使用 sd_notify("WATCHDOG=1")
喂狗,同样喂狗的时间间隔为 WatchdogSec
所设置的一半。
用户只要在对应的 systemd service 文件中设置 WatchdogSec=
参数即可,而 WATCHDOG_USEC=
将根据前面的参数自动被设置。在应用程序中以 WatchdogSec/2 的间隔调用 sd_notify
函数发送 "WATCHDOG=1"
进行喂狗操作。例如
Systemd servier 文件,用于启动用户应用
/etc/systemd/system/test.service
[Unit]
Description=Watchdog Test service
[Service]
ExecStart=/home/root/wdt-sw-test
WatchdogSec=30s
Restart=on-failure
StartLimitInterval=5min
StartLimitBurst=4
StartLimitAction=reboot
[Install]
WantedBy=multi-user.target
用户应用 wdt-sw-test.c,并定期执行喂狗操作(编译的时候需要使用 -lsystemd 链接 systemd 库文件)。
在应用初始化后需要通知 systemd 管理器本应用正常启动,sd_notify (0, "READY=1");
。然后根据 WATCHDOG_USEC
变量设置喂狗间隔。在应用中我们将模拟一次超时喂狗,从而引起应用重启。
下面是运行日志。起初应用程序 wdt-sw-test 由 systemd 加载启动,PID=396,并以15s间隔喂狗(该时间源自WatchdogSec=30s)。当喂狗超时后,systemd 会发送信号 SIGABRT 终止该进程,并重启该应用,新 PID=647。
在 service 文件中,我们还配置了 StartLimitBurst
和 StartLimitInterval
以及 StartLimitAction
参数。这使得在 StartLimitInterval
时间内应用启动次数超过 StartLimitBurst
后,将不被允许再次启动,并触发 StartLimitAction
的操作。具体描述请参考 systemd.unit。
总结
看门狗对于关键应用,以及大多数的一般应用来讲是一个很重要的功能,其能够应对 Linux系统或者应用崩溃的情况,避免用户设备处于失控的状态。当整个系统只有一个嵌入式设备作为决策控制单元时,对于关键的安全应用,根据单一故障准则,我们还建议引入辅助控制单元,例如额外的 MCU 等做同步监测,或者使用保险丝、热电偶等,当出现超限情况,能够执行紧急操作,从而进一步提高设备的安全性。