瑞昱rtl819x-SDK-v3.4.14b的watchdog分析

news2025/4/7 2:59:28

watchdog

看门狗,又叫watchdog timer,是一个定时器电路,一般有一个输入,叫喂狗或踢狗;一个输出到MCU 的 RST 端,MCU 正常工作的时候,每隔一段时间输出一个信号到喂狗端,给 WDT 清零,如果超过规定的时间不喂狗(一般在程序跑飞时),WDT 定时超过,就会给出一个复位信号到 MCU,使 MCU 复位。防止 MCU 死机。

整体思路

  1. 内核模块初始化watchdog控制寄存器并使能watchdog
  2. 用户看门狗进程定时踢狗

一、用户空间代码分析

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <stdarg.h>

static void
die(const char *msg, ...)
{
    va_list ap;

    va_start(ap, msg);
    fprintf(stderr, "%s: ERROR: ", "watchdog");
    vfprintf(stderr, msg, ap);
    va_end(ap);

    exit(1);
}


static void
watchdog_write_pidfile(void)
{
    char pidfile[80];
    char pidbuf[16];
    int fd;
    int ret;

    snprintf(pidfile, sizeof(pidfile), "/var/run/%s.pid", "watchdog");
    fd = open(pidfile, O_RDONLY);
    if (fd < 0) {
        if (errno != ENOENT) {
            die("watchdog_write_pidfile: opening pidfile %s for read: %s
",
                    pidfile, strerror(errno));
        }
        /* ENOENT is good: the pidfile doesn't exist */
    } else {
        /* the pidfile exists: read it and check whether the named pid
           is still around */
        int pid;
        char *end;

        ret = read(fd, pidbuf, sizeof(pidbuf));
        if (ret < 0) {
            die("watchdog_write_pidfile: read of pre-existing %s failed: %s
",
                pidfile, strerror(errno));
        }

        pid = strtol(pidbuf, &end, 10);
        if (*end != '' && *end != '
') {
            die("watchdog_write_pidfile: couldn't parse "%s" as a pid (from file %s); "
                "aborting
", pidbuf, pidfile);
        }
        ret = kill(pid, 0); /* try sending signal 0 to the pid to check it exists */
        if (ret == 0) {
            die("watchdog_write_pidfile: %s contains pid %d which is still running; aborting
",
                pidfile, pid);
        }
        /* pid doesn't exist, looks like we can proceed */
        close(fd);
    }

    /* re-open pidfile for write, possibly creating it */
    fd = open(pidfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if (fd < 0)
    die("watchdog_write_pidfile: open %s for write/create: %s
", pidfile, strerror(errno));
    snprintf(pidbuf, sizeof(pidbuf), "%d
", getpid());
    ret = write(fd, pidbuf, strlen(pidbuf));
    if (ret < 0) {
        die("watchdog_write_pidfile: writing my PID to lockfile %s: %s
",
            pidfile, strerror(errno));
    }
    close(fd);
}


void watchdog_func()
{
    FILE *file;
    file = fopen("/proc/watchdog_kick","w+"); 
    if(file)
    {
        fputs("111", file);
        fclose(file);
    }    
}

int
main(int argc, char **argv)
{ 
    pid_t    pid; 
    char tmpBuff[30] = {0};
    int res = 0;  
    int fd;
    int interval;
    int sec,micro_sec;
    sigset_t sigset;

    if(argc >= 2)
        interval = atoi(argv[1]);
    else
        interval = 500;

    if(interval >= 10000){
        printf("watchdog interval too long,should not more than 10s
");
        interval = 1000;
    }

    sec = interval/1000;
    micro_sec = (interval % 1000) * 1000;

    watchdog_write_pidfile();

    /* unblock sigalarm and sigterm signal */
    sigaddset(&sigset,SIGALRM);
    if(sigprocmask(SIG_UNBLOCK,&sigset,NULL) < 0)
        printf("sigprocmask error
");
  
      // Register watchdog_func to SIGALRM  
    signal(SIGALRM, watchdog_func);
    
    struct itimerval tick;  
    memset(&tick, 0, sizeof(tick));  
    //printf("interval:%d.
",interval);

    // Timeout to run function first time  
    tick.it_value.tv_sec = sec;  // sec  
    tick.it_value.tv_usec = micro_sec; // micro sec.  

    // Interval time to run function  
    tick.it_interval.tv_sec = sec;  
    tick.it_interval.tv_usec = micro_sec;  

    pid = getpid(); 
    snprintf(tmpBuff,30,"renice -19 %d",pid);
    system(tmpBuff);
    //stop watchdog first
    system("echo 1 > /proc/watchdog_kick");    
    system("echo enable 0 interval 0 > /proc/watchdog_cmd");    
    
    // resume watchdog
#ifdef CONFIG_RTL_8197F
    system("echo enable 1 interval 32 > /proc/watchdog_cmd");
#else
    system("echo enable 1 interval 10 > /proc/watchdog_cmd");
#endif
    system("echo 1 > /proc/watchdog_kick");
    res = setitimer(ITIMER_REAL, &tick, NULL);  
    if (res) {  
        printf("Set watchdog timer failed!!/n"); 
        return -1;  
    }  
 
    while(1) {  
        pause();  
    }  
    return 0;    
}

用户进程主要做了两件事:

1. 用户进程设置watchdog intervel
echo enable 1 interval 32 > /proc/watchdog_cmd
2. 定时器定时踢狗
void watchdog_func()
{
    FILE *file;
    file = fopen("/proc/watchdog_kick","w+"); 
    if(file)
    {
        fputs("111", file);
        fclose(file);
    }    
}

二、内核部分

1. 看门狗定时器控制寄存器初始化

void bsp_enable_watchdog( void )
{
    bBspWatchdog = 1;
    *(volatile unsigned long *)(0xb800311C)=0x00240000; // 2^24
}

void __init plat_time_init(void) // mips-ori
{
    printk(COLOR_RED"[%s:%d] [watchdog] platform timer init
"COLOR_CLEAR, __FUNCTION__, __LINE__);
    {/* 省略部分代码 */}
    
#ifdef CONFIG_RTL_WTDOG
    /* 配置时钟分频寄存器 */
    REG32(BSP_CDBR)=(BSP_DIVISOR) << BSP_DIVF_OFFSET;
    printk(COLOR_RED"[%s:%d] [watchdog] BSP enable watchdog, BSP_CDBR=0x%x
"COLOR_CLEAR, 
                    __FUNCTION__, __LINE__, ((BSP_DIVISOR) << BSP_DIVF_OFFSET));
    /* 使能watchdog */
    bsp_enable_watchdog();

    wtdog_cdbr = (REG32(BSP_CDBR) >> 16) & 0xffff;
    printk(COLOR_RED"[%s:%d] [watchdog] watchdog cdbr=%u
"COLOR_CLEAR, __FUNCTION__, __LINE__, wtdog_cdbr);
    
#endif /* CONFIG_RTL_WTDOG */

    {/* 省略部分代码 */}
}

看门狗控制寄存器初始化为:0x00240000,表示 OVSEL 的高两位是 10, OVSEL 的低两位是 01, OVSEL=1001

2. 创建proc节点(watchdog_cmd 和 watchdog_kick)

为应用层配置watchdog提供两个接口,watchdog_cmd用来设置interval,watchdog_kick用来踢狗

int __init bsp_watchdog_proc_init(void)
{
    proc_create_data("watchdog_reboot", 0, &proc_root,
            &watchdog_reboot_proc_fops, NULL);
#ifdef  CONFIG_RTL_USERSPACE_WTDOG
    proc_create_data("watchdog_cmd", 0, &proc_root,
            &watchdog_cmd_proc_fops, NULL);
            
    proc_create_data("watchdog_kick", 0, &proc_root,
            &watchdog_kick_proc_fops, NULL);
#endif

    return 0;
}

2.1 watchdog_cmd的write接口

应用层向该节点写入watchdog interval的配置,该接口去配置watchdog寄存器的OVSEL位

如:echo enable 1 interval 32 > /proc/watchdog_cmd

static ssize_t watchdog_cmd_single_write(struct file * file, const char __user * userbuf,
             size_t count, loff_t * off)
{
    char flag[64];
    int enable,interval;

    extern void bsp_enable_watchdog(void);
    extern void bsp_disable_watchdog(void);
    
    if (count < 2)
        return -EFAULT;
    if (userbuf && !copy_from_user(&flag, userbuf, 63)) {
        int i;
        unsigned int wtdog_intervel,wtdog_intervel0 = 0,wtdog_cdbr,wtdog_maxtime;
        sscanf(flag,"enable %d interval %d",&enable,&interval);

        if (enable == 0) {
            /* disable watchdog */
            bsp_disable_watchdog();
        } else if (enable == 1) {
            if (watchdog_default_flag == 0) {
                watchdog_default_flag = 1;
                watchdog_default_val = interval;
            } else {
                if(interval < watchdog_default_val){
                    printk("	
watchdog timeout time should not less than default val,default=%d
",watchdog_default_val);
                    return -1;
                }
            }

            wtdog_cdbr = (REG32(BSP_CDBR) >> 16) & 0xffff;
            i = sizeof(wtdog_tbl)/sizeof(WTDOG_REGTBL_T) - 1;

            /* interval计算方法 */
            wtdog_maxtime = wtdog_tbl[i].wtdog_val/(LXBUS_CLOCK/wtdog_cdbr);

            if (interval > wtdog_maxtime) {
                printk("	
 watchdog max intervale time is %d,please check the set value
",  wtdog_maxtime);
                return -1;
            }

            for(i = 0; i < sizeof(wtdog_tbl)/sizeof(WTDOG_REGTBL_T); i++) {
                wtdog_intervel = wtdog_tbl[i].wtdog_val/(LXBUS_CLOCK/wtdog_cdbr);
                printk(COLOR_GREEN"[%s:%d] [watchdog] Supported interval=%ds
"COLOR_CLEAR, 
                                    __FUNCTION__, __LINE__, wtdog_intervel);
                if (interval >= wtdog_intervel0
                    && interval <= wtdog_intervel) {
                    goto END;
                }
                wtdog_intervel0 = wtdog_intervel;
            }
            
END:
            printk(COLOR_GREEN"[%s:%d] [watchdog] Do watchdog control register set (index=%d).
"COLOR_CLEAR, 
                                __FUNCTION__, __LINE__, i);
            printk(COLOR_GREEN"[%s:%d] [watchdog] oversel_l = 0x%x, oversel_h = 0x%x.
"COLOR_CLEAR, 
                                __FUNCTION__, __LINE__, wtdog_tbl[i].oversel_l, wtdog_tbl[i].oversel_h);

            /* 设置wathdog寄存器 */
            REG32(BSP_WDTCNR) = ( wtdog_tbl[i].oversel_l << 21) | ( wtdog_tbl[i].oversel_h << 17);
        }
        return count;
    }
    
    return -EFAULT;    
}

2.2 watchdog_kick的write接口

static ssize_t watchdog_kick_single_write(struct file * file, const char __user * userbuf,
             size_t count, loff_t * off)
{
    char flag[20];

    if (count < 2)
        return -EFAULT;
#ifdef CONFIG_RTL_WTDOG
    { 
        /*If kernel fault. reboot whole system so softwatch dog can not kick even*/
        extern int is_fault;
        if(is_fault)
            return count;
    }
#endif
    if (userbuf && !copy_from_user(&flag, userbuf, 1)) {
        if(flag[0] == '1'){
            watchdog_kick_state = RTL_WATCHDOG_KICK;
            /* kick watchdog here */
            *(volatile unsigned long *)(0xB800311c) |=  1 << 23;
        }else {
            watchdog_kick_state = 0;
        }
        return count;
    }
    
    return -EFAULT;    
}

原文:

瑞昱rtl819x-SDK-v3.4.14b的watchdog分析 - 走看看 (zoukankan.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/111499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL注入渗透与攻防(八)之延时注入

目录 基于时间的SQL盲注 - 延时注入 案列演示 基于时间的SQL盲注 - 延时注入 关于延时注入的使用场景一般在我们测试的注入点没有报错信息又没有回显点的情况下进行的。通过对于时间的延时判断来猜解数据。在实战过程中并不推荐大家通过延时注入去判断数据库&#xff0c;因为…

转行做程序员,难吗

在互联网急速发展的这几年里&#xff0c;程序员这个职业&#xff0c;成为了很多人的心之所向。虽然高薪背后往往伴随着高强度的工作节奏和压力&#xff0c;但是也不妨碍大量的人在编程培训或者自学编程的道路上前仆后继。 那么转行程序员真的容易吗&#xff1f;下面就跟大家分享…

无需编程即可将chatgpt接入自己的微信公众号

ChatGpt是openai推出的GPT3文本生成机器人。该机器人主要完成文本生成相关任务。机器人可以自主进行写作、翻译、修改语法、角色扮演的&#xff0c;甚至编写程序。网上有很多接入方法&#xff0c;大部份需要编程&#xff0c;并且需要注册openai账号获取appkey。本文所介绍的方法…

datagridview如何根据不同的按钮显示不同的表

以我设计的为例&#xff1a; 双击按钮&#xff0c;会自动创建三个事件 以第一个按钮为例&#xff1a;在其中添加如下代码 SqlConnection sqlcon new SqlConnection(); sqlcon.ConnectionString "";//双引号内填入你的数据库连接字符 sqlcon.Open(); string sql &…

UG NX二次开发(C#)-获取模型文件的预览图片

文章目录 1.前言2. 模型文件预览图介绍3.采用二次开发的方法获取模型的预览图4.验证1.前言 UG NX保持的prt文件中保存了模型的预览位图,但是采用UG NX二次开发时不能直接提取出来,本文讲解一下将prt文件的预览位图提取出来并单独保存。 2. 模型文件预览图介绍 如果我们在UG…

【字体】写代码编程字体展示推荐

写代码编程字体展示推荐 零、适合写代码编程的字体 什么样的字体适合写代码用&#xff1f;一般来讲&#xff0c;写代码的字体要求字母的宽度一致、轮廓清晰美观、l1i&#xff0c;0oO易于分辨、清晰易分辨的标点等&#xff0c;甚至有强迫症的还要中文与英文严格2:1对齐。下面收…

机器学习 | 决策树

一.基本原理 决策树是一种树状结构模型&#xff0c;每一个根节点都是一个特征判断&#xff0c;它的叶子节点就是它的特征分类结果 决策树是一种分类和回归的基本模型&#xff0c;是一棵树的形式&#xff0c;其实就是将平时所说的 if-else 语句构建成了树的形式。决策树主要包…

使用 SQL 别名简化查询并自定义结果

别名能够在不影响基础表或视图的情况下临时重命名表或列。作为大多数甚至所有关系数据库管理系统都支持的 SQL 功能&#xff0c;别名是简化查询和/或自定义结果集中列标题的好方法。在这篇文章中&#xff0c;我们将使用 Navicat Premium 16 来完成这两项工作。 重命名列 许多…

带宽消耗以及Swap(上)

今天我们来看一个真实的案例。事情是这样的,之前有人在微信上问我一个问题,这个问题的现象很典型:典型的 TPS 上不去,响应时间增加,资源用不上。 大概的情况是这样的:有两台 4C8G 的服务器,一台服务器上有 2 个 Tomcat,一台服务器上是 DB。压测的混合场景有 4 个功能模…

【验证码逆向专栏】某验三代滑块验证码逆向分析

声明 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 本文章未经许可禁止转载…

k8s教程(20)-pod之定时任务

文章目录01 引言02 基本语法03 案例04 文末01 引言 声明&#xff1a;本文为《Kubernetes权威指南&#xff1a;从Docker到Kubernetes实践全接触&#xff08;第5版&#xff09;》的读书笔记 Kubernetes从1.5版本开始增加了一种新类型的Job&#xff0c;即类似Linux Cron的定时任务…

SpringMVC、SSM整合

SpringMVC的工作原理&#xff08;底层Servlet的工作流程&#xff09; DispatcherServletHandlerMapping &#xff0c;返回值 HandlerExecutionChainHandlerAdapterViewResolverView ~~老版本&#xff08;过去式&#xff09; 一、搭建springmvc 第一步&#xff1a;配置打包…

互联网行业逐步回暖!就业显示有74%学员跨专业学编程!

三年以来&#xff0c;居家办公、隔离等影响已深入每个人的生活。就业形势承受着巨大的压力&#xff0c;同时就业环境也发生巨大变化&#xff0c;越来越多的人都面临转行&#xff01; 达妹被问到最多的问题是&#xff1a; 跨专业学编程的疑虑 非科班出身零基础能学会编程吗? 数…

程序人生:起薪13k,兜兜转转还得是软件测试

很多人一聊到IT教育培训第一反应就是&#xff1a;为什么要报班呢&#xff0c;网上大把资源它不香吗&#xff1f;自己学一学不就出来找工作了吗&#xff1f;还花这种冤枉钱&#xff1f; 小编作为从业人员认真地说&#xff0c;进入IT行业虽然不是特别难&#xff0c;但也没有这么…

English Learning - L1-6 从此口语变得简约(下)2022.12.22 周四

English Learning - L1-6 从此口语变得简约&#xff08;下&#xff09;2022.12.22 周四引言6.2.2 分词非谓语动词作后置定语的三种被动结构1. to be done 将来的动作2. being done 正在进行的3. done 已经完成的6.2.3 分词形容词挑错其它1. 形容词 名词 ed2. 数词 名词 ed答…

RiscV汇编基础学习

文章目录一、基础概念指令集---指示计算机执行某种操作的命令&#xff0c;是计算机运行的最小功能单位。复杂指令集CISC&#xff08;如x86&#xff09;和精简指令集RISC&#xff08;如arm、riscV&#xff09;---两种指令集的优化设计方向RiscV---一个基于精简指令集RISC原则的开…

SQL注入渗透与攻防(七)之查询方式及报错注入

目录 SQL注入之查询方式 select 查询数据 delete 删除数据 insert 插入数据 update 更新数据 SQL注入 报错盲注 1.基于布尔的SQL盲注 - 逻辑判断 2.基于时间的SQL盲注 - 延时判断 3.基于报错的SQL盲注 - 报错回显&#xff08;强制性报错 &#xff09; 案列演示 SQL注入…

移动设备的自动化测试工具,如何选型?

一、问题的提出 最近二两年来&#xff0c;一直在从事移动设备的自动化测试工作&#xff0c;可以说小有心得。但最近由于种种原因&#xff0c;面临着对移动设备的自动化测试工具的更换工作。所以&#xff0c;一个问题呈现在面前。我们需要为我们的项目选出一款新的自动化测试工…

最长上升子序列

基于最长上升子序列 LIS 求最长上升子序列有两种做法求最长上升子序列有两种做法求最长上升子序列有两种做法 一种是n2复杂度的线性dp一种是n^2复杂度的线性dp一种是n2复杂度的线性dp 另一种是O(nlogn)复杂度的贪心二分另一种是O(nlogn)复杂度的贪心二分另一种是O(nlogn)复杂度…

看BP英文文献生词记录

看BP英文文献生词记录 总的来说&#xff0c;该论文是在讲CAT和SAR的后向后向投影之间的联系与区别 acoustic imaging 原声成像 polychromatic 美 [pɒlɪkroʊ’mtɪk] 英 [pɒlɪkrəʊ’mtɪk] adj.多色的 illumination 美 [ɪˌlumɪˈneɪʃ(ə)n] 英 [ɪˌluːmɪˈne…