当前位置:网站首页 > 更多 > 玩电脑 > 正文

[外设篇] Linux 看门狗工作原理

作者:CC下载站 日期:2023-10-11 22:05:21 浏览:54 分类:玩电脑

[外设篇] Linux 看门狗工作原理

一、什么是看门狗?

简单来说,看门狗就是一个定时器 Watchdog Timer(WDT),是一个在软件出错时可以让 Linux 系统复位的硬件电路。以下简述一下其工作原理: 

在用户空间通过看门狗程序以“喂狗”的形式不断地给 watchdog 写入数据(即通过 /dev/watchdog 特殊设备文件来通知内核的 watchdog 驱动)。当在一定时间内如果不喂狗(即没有往 watchdog 写入数据),它就执行一次系统复位,也就跳到中断向量表执行复位向量。

二、看门狗内核源码分析 

在内核中提供了一套完整的驱动接口,具体如下:

wdt_open  : 打开设备,程序调用 open 时进入该函数
wdt_close : 关闭设备,程序调用 close 时进入该函数
wdt_write  : 写设备,若传入数据大小不为 0 则喂狗; 程序调用 write 时进入该函数
wdt_ioctl   : 这个函数是最主要的,原型如下(driver/watchdog)

wdt_ioctl 驱动源码实现如下(以 w83697hf 为例): 

static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
	int new_timeout;
	static const struct watchdog_info ident = {
		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
							| WDIOF_MAGICCLOSE,
		.firmware_version = 1,
		.identity = "W83697HF WDT",
	};

	switch (cmd) {
	case WDIOC_GETSUPPORT:
		if (copy_to_user(argp, &ident, sizeof(ident)))
			return -EFAULT;
		break;

	case WDIOC_GETSTATUS:
	case WDIOC_GETBOOTSTATUS:
		return put_user(0, p);

	case WDIOC_SETOPTIONS:
	{
		int options, retval = -EINVAL;

		if (get_user(options, p))
			return -EFAULT;

		if (options & WDIOS_DISABLECARD) {
			wdt_disable();
			retval = 0;
		}

		if (options & WDIOS_ENABLECARD) {
			wdt_enable();
			retval = 0;
		}

		return retval;
	}

	case WDIOC_KEEPALIVE:
		wdt_ping();
		break;

	case WDIOC_SETTIMEOUT:
		if (get_user(new_timeout, p))
			return -EFAULT;
		if (wdt_set_heartbeat(new_timeout))
			return -EINVAL;
		wdt_ping();
		/* Fall */

	case WDIOC_GETTIMEOUT:
		return put_user(timeout, p);

	default:
		return -ENOTTY;
	}
	return 0;
}

简述其中重要的参数:
WDIOC_KEEPALIVE    : 喂狗,类似于 write 函数功能
WDIOC_SETTIMEOUT : 设置超时值
WDIOC_GETTIMEOUT : 获取超时值
WDIOC_SETOPTIONS : 设置看门狗状态,开启(WDIOS_ENABLECARD) 或 关闭(WDIOS_DISABLECARD

三、编写看门狗程序

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/watchdog.h>

static int open_watchdog(void)
{
	int wtd_fd = 0;
 
	wtd_fd = open("/dev/watchdog", O_RDWR);
	if (wtd_fd < 0) 
		return -1;

	int timeout = 60; //60s
	ioctl(wtd_fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
	ioctl(wtd_fd, WDIOC_SETTIMEOUT, &timeout);
	
	return wtd_fd;
}

static void feed_watchdog(int wtd_fd)
{
	while (1) {
		ioctl(wtd_fd, WDIOC_KEEPALIVE, NULL);
		sleep(10);
	}
}

static int close_watchdog(int wtd_fd)
{
	ioctl(wtd_fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
	close(wtd_fd);
}

int main(void)
{
	int wtd_fd = 0;
 
	/* 打开设备 */
	wtd_fd = open_watchdog(void);
	if (wtd_fd < 0) {  
		printf("wtd open failed\n");  
		return -1;
	}
 
	/* 喂狗 */
	feed_watchdog(wtd_fd);

	/* 关闭设备 */
	close_watchdog(wtd_fd);
	
	return 0;
}

四、关于看门狗作用的特别说明 

1. 在实际应用中,一般都是不需要主动去关闭看门狗close 或 WDIOS_DISABLECARD的,因为关闭看门狗后它就不能工作了,也就无法实现系统复位。只有当你明确不需要看门狗功能生效时,才可主动关闭看门狗;

2. 当程序奔溃或者软重启失败后,看门狗是让系统复位的最后保障了(假如连看门狗也失效了,那就只能乖乖地拔插电源让系统重启了)。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯