现在的位置: 首页 > 综合 > 正文

WatchDog

2018年02月07日 ⁄ 综合 ⁄ 共 4983字 ⁄ 字号 评论关闭
让WatchDog也不闲着 2010-10-25
00:57:58

分类: LINUX

下面的代码让WatchDog也工作起来。


1.先执行命令"insmod wdt.ko",


2.再让WatchDog工作在reset模式“./app wdt_node”。此时一切正常.

    其中文件wdt_node由命令“sudo mknode wdt_node c 52 0”创建。

3.插入一个故障模块,使上一步中的进程得不到调度。很快,系统重启。


wdt.c代码如下:


#include <linux/module.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>

#include <asm/io.h>


MODULE_LICENSE("GPL");

MODULE_AUTHOR("zl");

#define WDT_MAGIC    'Y'
#define WDT_ON        _IOW(WDT_MAGIC, 0x00, int)
#define WDT_OFF        _IOW(WDT_MAGIC, 0x01, int)
#define WDT_MODE        _IOW(WDT_MAGIC, 0x02, int)
#define WDT_FEED        _IOW(WDT_MAGIC, 0x03, int)

struct watch_dog {

    unsigned long virt,phys;

    unsigned long wdtcon;

    unsigned long wdtdat;

    unsigned long wdtcnt;


    char name[1024];


    int reset_mode;

    int irq;


    void (*on)(struct watch_dog *);    

    void (*off)(struct watch_dog *);

    void (*mode)(struct watch_dog *, int);


    void (*feed)(struct watch_dog *);

    //----------------


    dev_t no;

    struct cdev dev;
};

void mywdt_on(struct watch_dog* mywdt)
{

    iowrite32(ioread32(mywdt->wdtcon) | (<< 5), mywdt->wdtcon);
}

void mywdt_off(struct watch_dog* mywdt)
{

    iowrite32(ioread32(mywdt->wdtcon) & ~(<< 5), mywdt->wdtcon);
}

void mywdt_mode(struct watch_dog* mywdt, int mymode)
{

    unsigned long tmp;

    mywdt->reset_mode = mymode;


    tmp = ioread32(mywdt->wdtcon);

    if(mywdt->wdtcon)

    {

        iowrite32((tmp & ~(<< 2)) | 1, mywdt->wdtcon);            

    }

    else

    {

        iowrite32((tmp & ~1) | (<< 2), mywdt->wdtcon);

    }

}
void mywdt_feed(struct watch_dog* mywdt)
{

    iowrite32(0x8000, mywdt->wdtcnt);
}


irqreturn_t mywdt_handle(int irq, struct watch_dog *mywdt)
{

    printk("wdt timer....\n");    

    return IRQ_HANDLED;
}

int init_watch_dog(struct watch_dog *mywdt, const char *name )
{

    int ret = 0;

    strcpy(mywdt->name, name);    

    mywdt->phys = 0x53000000;

    mywdt->irq = IRQ_S3C2440_WDT;

    mywdt->reset_mode = 0;


    ret = request_mem_region(mywdt->phys, SZ_4K, mywdt->name );

    if ((void *)ret == NULL) {

        ret = -EBUSY;

        goto err0;    

    }    

    

    ret = 0;

    mywdt->virt = ioremap(mywdt->phys, SZ_4K);

    if (mywdt->virt == NULL) {

        ret = -EBUSY;    

        goto err1;

    }


    mywdt->wdtcon = mywdt->virt + 0x00;

    mywdt->wdtdat = mywdt->virt + 0x04;

    mywdt->wdtcnt = mywdt->virt + 0x08;


    if (ret) {

        goto err2;    

    }


    mywdt->on = mywdt_on;

    mywdt->off = mywdt_off;

    mywdt->feed = mywdt_feed;

    mywdt->mode = mywdt_mode;


    iowrite32( 0x8004, mywdt->wdtcon);


    return ret;

err2:

    iounmap(mywdt->virt);

err1:

    release_mem_region(mywdt->phys, SZ_4K);    

err0:

    return ret;
}

void destroy_watch_dog(struct watch_dog *mywdt)
{

    iowrite32( 0x0, mywdt->wdtcon);

    iounmap(mywdt->virt);

    release_mem_region(mywdt->phys, SZ_4K);

    free_irq(mywdt->irq, mywdt);
}

//----------------------------------------

int mywdt_ioctl(struct inode *no, struct file *fp, unsigned long cmd, unsigned long arg)
{

    int ret = 0;

    struct watch_dog *mywdt = container_of(no->i_cdev, struct watch_dog, dev);


    switch(cmd) {

        case WDT_ON:

        mywdt->on(mywdt);

        break;


        case WDT_OFF:

        mywdt->off(mywdt);

        break;


        case WDT_MODE:

        mywdt->mode(mywdt, arg);

        break;


        case WDT_FEED:

        mywdt->feed(mywdt);

        break;


        default:

        ret = -EINVAL;

        break;

    }


    return ret;
}

struct watch_dog s3c2440_wdt;
struct file_operations s3c2440_wdt_ops = {

    .ioctl = mywdt_ioctl,
};
int test_init(void)
{

    int ret = 0;

    

    ret = init_watch_dog(&s3c2440_wdt, "s3c2440
watch dog"
);

    if (ret) {

        goto err0;

    }

    

    s3c2440_wdt.no = MKDEV(52, 0);

    ret = register_chrdev_region(s3c2440_wdt.no, 1, s3c2440_wdt.name);

    if (ret) {

        goto err1;    

    }


    cdev_init(&s3c2440_wdt.dev, &s3c2440_wdt_ops);

    cdev_add(&s3c2440_wdt.dev, s3c2440_wdt.no, 1);        


    return ret;

err1:

    destroy_watch_dog(&s3c2440_wdt);


err0:

    return ret;
}

void test_exit(void)
{

    destroy_watch_dog(&s3c2440_wdt);    

    cdev_del(&s3c2440_wdt.dev);

    unregister_chrdev_region(s3c2440_wdt.no, 1);
}


module_init(test_init);

module_exit(test_exit);



app.c文件代码创建一个守护进程,使WatchDog工作在reset模式。每0.1秒执行一次喂狗,内容如下:



#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "wdt.h"

int main(int argc, char **argv)
{

    int fd;

    unsigned cmd;

    if (argc < 2) {

        printf("Usage: %s <file> \n", argv[0]);

        return 0;

    }


    fd = open(argv[1], O_RDWR);


    chdir("/");

    close(0);close(1);close(2);    


    if (fork()) {

        return 0;    

    }


    ioctl(fd, WDT_MODE, 1);

    ioctl(fd, WDT_ON);


    while(1) {

        ioctl(fd, WDT_FEED);    

        usleep(100 * 1000);

    }


    close(fd);

    return 0;
}



故障模块文件代码bad_module.c禁止内核抢占,然后一个死循环把系统卡死,这样上面的"./app wdt_node"命令启动的守护进程就得不到调度。代码如下:



#include <linux/module.h>


MODULE_LICENSE("GPL");

MODULE_AUTHOR("zl");


int test_init(void)

{

    preempt_disable();

    while(1);


    return 0;

}


void test_exit(void)

{

}


module_init(test_init);

module_exit(test_exit);


抱歉!评论已关闭.