[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)

摘要:
目的:1.为我们自己的看门狗编写驱动程序步骤:通过前面的介绍,我们可以很容易地猜测,编写基于PCI的看门狗驱动程序可以分为两个步骤。通过这部分代码,我们可以找到制造商ID为0x1af4、设备ID为0x0101的设备。该设备是在QEMU#definePI_VENDOR_ID_REDHAT0x1af4#definePC_device_ID_CWD0x0101中定义的看门狗中指定的。我们需要一个探测功能来检测PCI设备。staticstructpci_driver.cwd_driver={.name=ESB_MODULE_name,.id_table=cwd_pci_tbl,.probe=cwd_probe,.remove=cwd_remove,.shutdown=cwd_shutdown,};我们可以直接引用其他PCI设备驱动程序代码来实现这部分代码,例如:driver/watchd/i6300esb。c代码如下。

目的:

1. 为我们自己的watchdog写一个驱动

步骤:

通过之前的介绍,我们很容易猜想到写我们基于PCI的watchdog驱动,可以分2个步骤。

1. 探测加载PCI设备

这部分代码跟我们的设备本身没有任何关系。

我们通过这部分代码,找到 厂商ID为 0x1af4, 设备ID为0x0101的设备。这个设备是我们用qemu中定义我们的watchdog中指定的。

#define PCI_VENDOR_ID_REDHAT 0x1af4
#define PCI_DEVICE_ID_CWD 0x0101

很自然的可以先到我们需要一个probe的函数来探测PCI设备。 事实确实如此。

我们通过一个pci_driver定义这部分。

static struct pci_driver cwd_driver = {
        .name           = ESB_MODULE_NAME,
        .id_table       = cwd_pci_tbl,
        .probe          = cwd_probe,
        .remove         = cwd_remove,
        .shutdown       = cwd_shutdown,
};

我们可以直接参考一下其他的PCI设备驱代码来实现这部分代码,比如: drivers/watchdog/i6300esb.c

代码如下。

cwd_demo.c

[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)第1张[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)第2张
  1 #include <linux/init.h>  //初始换函数 
  2 #include <linux/kernel.h>  //内核头文件 
  3 #include <linux/module.h>  //模块的头文件 
  4 #include <linux/pci.h> 
  5 #include <linux/miscdevice.h> 
  6 #include <linux/types.h> 
  7 #include <linux/fs.h> 
  8 #include <linux/mm.h> 
  9 #include <linux/watchdog.h> 
 10 #include <linux/ioport.h> 
 11 #include <linux/uaccess.h> 
 12 #include <linux/io.h> 
 13  
 14  
 15  
 16 #define ESB_MODULE_NAME "cstl watchdog" 
 17  
 18 /* We only use 1 card for cwd_demo */ 
 19 static int cards_found; 
 20 static struct pci_dev *cwd_pci; 
 21  
 22 MODULE_LICENSE("GPL"); 
 23  
 24 #define CWD_VERSION "0.1" 
 25 #define PCI_VENDOR_ID_REDHAT 0x1af4 
 26 #define PCI_DEVICE_ID_CWD 0x0101 
 27 /* internal variables */ 
 28 static void __iomem *BASEADDR; 
 29  
 30  
 31 /*  
 32  * Data for PCI driver interface  
 33  */  
 34 static DEFINE_PCI_DEVICE_TABLE(cwd_pci_tbl) = {  
 35         { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_CWD), },
 36         { 0, },                 /* End of list */
 37 };
 38 MODULE_DEVICE_TABLE(pci, cwd_pci_tbl);
 39 
 40 
 41 static unsigned char cwd_getdevice(struct pci_dev *pdev)
 42 {
 43         if (pci_enable_device(pdev)) {
 44                 printk(KERN_ERR "failed to enable device
");
 45                 goto err_devput;
 46         }
 47 
 48         if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
 49                 printk(KERN_ERR "failed to request region
");
 50                 goto err_disable;
 51         }
 52 
 53         BASEADDR = pci_ioremap_bar(pdev, 0);
 54         if (BASEADDR == NULL) {
 55                 /* Something's wrong here, BASEADDR has to be set */
 56                 printk(KERN_ERR "failed to get BASEADDR
");
 57                 goto err_release;
 58         }
 59 
 60         /* Done */
 61         cwd_pci = pdev;
 62         return 1;
 63 
 64 err_release:
 65         pci_release_region(pdev, 0);
 66 err_disable:
 67         pci_disable_device(pdev);
 68 err_devput:
 69         return 0;
 70 }
 71 
 72 
 73 static int cwd_probe(struct pci_dev *pdev,
 74                 const struct pci_device_id *ent)
 75 {
 76         int ret;
 77 
 78         cards_found++;
 79         if (cards_found == 1)
 80                 printk(KERN_INFO "Cstl WatchDog Timer Driver v%s
",
 81                         CWD_VERSION);
 82 
 83         if (cards_found > 1) {
 84                 printk(KERN_ERR "Cstl driver only supports 1 device
");
 85                 return -ENODEV;
 86         }
 87 
 88         /* Check whether or not the hardware watchdog is there */
 89         if (!cwd_getdevice(pdev) || cwd_pci == NULL)
 90                 return -ENODEV;
 91         return 0;
 92 }
 93 
 94 static int cwd_timer_stop(void)
 95 {
 96         /* Returns 0 if the timer was disabled, non-zero otherwise */
 97         return 0;
 98 }
 99 static void cwd_remove(struct pci_dev *pdev)
100 {
101         /* Stop the timer before we leave */
102         cwd_timer_stop();
103 
104         /* Deregister */
105         // misc_deregister(&cwd_miscdev);
106         iounmap(BASEADDR);
107         pci_release_region(cwd_pci, 0);
108         pci_disable_device(cwd_pci);
109         cwd_pci = NULL;
110 }
111 
112 static void cwd_shutdown(struct pci_dev *pdev)
113 {
114         cwd_timer_stop();
115 }
116 
117 
118 static struct pci_driver cwd_driver = {
119         .name           = ESB_MODULE_NAME,
120         .id_table       = cwd_pci_tbl,
121         .probe          = cwd_probe,
122         .remove         = cwd_remove,
123         .shutdown       = cwd_shutdown,
124 };
125 
126 static int __init cwd_demo_start(void)
127 {
128     printk(KERN_ALERT "Loading cwd_demo module...
");
129     printk(KERN_ALERT "Hello, I'm cwd_demo
");
130     return pci_register_driver(&cwd_driver);
131 }
132 
133 static void __exit cwd_demo_end(void)
134 {
135     pci_unregister_driver(&cwd_driver);
136     printk(KERN_ALERT "cwd demo Module Unloaded, Goodbye!
");
137 
138 }
139 
140 module_init(cwd_demo_start);
141 module_exit(cwd_demo_end);
View Code

Makefile

[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)第3张[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)第4张
 1 ifeq ($(KERNELRELEASE),)
 2         KVERSION = $(shell uname -r)
 3 all:
 4         make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) modules
 5         echo $(shell pwd)
 6 clean:
 7         make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) clean
 8 else
 9         obj-m :=cwd_demo.o
10 endif
View Code

编译加载:

$ make

$ sudo insmod cwd_demo.ko

查看加载结果:

发现加载失败

$ tail -n 40 -f /var/log/syslog

Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759632] Hello, I'm cwd_demo
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759666] Cstl WatchDog Timer Driver v0.1
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759740] ------------[ cut here ]------------
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759749] WARNING: CPU: 0 PID: 15113 at /build/buil
dd/linux-lts-saucy-3.11.0/drivers/pci/pci.c:130 pci_ioremap_bar+0x71/0x80()
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759750] Modules linked in: cwd_demo(OF+) btrfs ra
id6_pq zlib_deflate xor ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs reiserfs ext2 usblp hello(POF)
rfcomm bnep bluetooth cirrus ttm drm_kms_helper drm sysimgblt sysfillrect syscopyarea ppdev mac_hid p
arport_pc i2c_piix4 psmouse serio_raw lp parport floppy [last unloaded: cwd_demo]
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759775] CPU: 0 PID: 15113 Comm: insmod Tainted: P
F       W  O 3.11.0-15-generic #25~precise1-Ubuntu
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759777] Hardware name: QEMU Standard PC (i440FX +
 PIIX, 1996), BIOS Bochs 01/01/2011
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759778]  0000000000000082 ffff8800367b5b38 ffffff
ff8173bc5e 0000000000000007
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759781]  0000000000000000 ffff8800367b5b78 ffffff
ff810653ac ffff88003dba1098
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759783]  ffff88003dba1000 ffff8800367b5c20 ffffff
ffa01e0000 ffff88003dba1098
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759785] Call Trace:
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759792]  [<ffffffff8173bc5e>] dump_stack+0x46/0x58
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759797]  [<ffffffff810653ac>] warn_slowpath_common+0x8c/0xc0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759799]  [<ffffffff810653fa>] warn_slowpath_null+0x1a/0x20
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759801]  [<ffffffff813aaf91>] pci_ioremap_bar+0x71/0x80
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759805]  [<ffffffffa01de12f>] cwd_probe+0x6f/0x1d0 [cwd_demo]
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759808]  [<ffffffff813acd2b>] local_pci_probe+0x4b/0x80
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759810]  [<ffffffff813ae5a9>] __pci_device_probe+0xd9/0xe0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759813]  [<ffffffff813ae5ea>] pci_device_probe+0x3a/0x60
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759817]  [<ffffffff814948bc>] really_probe+0x6c/0x330
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759819]  [<ffffffff81494d07>] driver_probe_device+0x47/0xa0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759821]  [<ffffffff81494e0b>] __driver_attach+0xab/0xb0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759823]  [<ffffffff81494d60>] ? driver_probe_device+0xa0/0xa0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759825]  [<ffffffff81492aee>] bus_for_each_dev+0x5e/0x90
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759827]  [<ffffffff8149447e>] driver_attach+0x1e/0x20
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759829]  [<ffffffff81493f0c>] bus_add_driver+0x10c/0x290
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759831]  [<ffffffff8149538d>] driver_register+0x7d/0x160
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759834]  [<ffffffffa0032000>] ? 0xffffffffa0031fff
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759836]  [<ffffffff813ad56c>] __pci_register_driver+0x4c/0x50
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759838]  [<ffffffffa003203a>] cwd_demo_start+0x3a/0x1000 [cwd_demo]
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759842]  [<ffffffff8100212a>] do_one_initcall+0xfa/0x1b0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759846]  [<ffffffff810578e3>] ? set_memory_nx+0x43/0x50
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759852]  [<ffffffff81730257>] do_init_module+0x80/0x1d1
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759857]  [<ffffffff810d1af9>] load_module+0x4c9/0x5f0
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759859]  [<ffffffff810cf270>] ? show_initstate+0x50/0x50
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759862]  [<ffffffff810d1cd4>] SyS_init_module+0xb4/0x100
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759866]  [<ffffffff8175099d>] system_call_fastpath+0x1a/0x1f
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759868] ---[ end trace 4d45fe543fa54a73 ]---
Jun 30 15:14:30 fsh-virtual-machine kernel: [612625.759869] failed to get BASEADDR

分析错误:

  通过内核栈信息,我们知道,代码在调用 pci_ioremap_bar 出现了问题。

  我们之前已经了解到,对PCI设备IO的操作,有两种方式,一种,是IO空间,一种是内存空间。我们这里抄袭了i6300esb的代码,esb采用的是内存空间。

很容易的想到,我们的外设是不支持内存空间的。

查看我们的qemu的代码,发现我们确实没有实现相关的代码。

这个可以通过我们的qemu monitor的 info qtree 来查看。

      dev: cstl-watchdog, id ""
        expiration-ticks = 10 (0xa)
        addr = 05.0
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        command_serr_enable = true
        class Class 0880, addr 00:05.0, pci id 1af4:0101 (sub 1af4:1100)
        bar 0: i/o at 0xc090 [0xc09f]

果真是不支持内存空间。

其实在PCI的spec文件中,有说明,如果从baro~bar5寄存器中读出来的地址是奇数,表示这是个IO空间,这是的地址要与~0x03UL做与运算,如果是偶数,则表示是内存空间。

        /* here we are testing it is a io space or mem space */
        unsigned int addr = 0;
        pci_read_config_dword(pdev, 0x10, &addr);
        printk(KERN_ERR "get BASEADDR: 0x%x ", addr);

在我们的log中将会输出以下的结果:

Jun 30 16:14:30 fsh-virtual-machine kernel: [612625.759872] failed to get get BASEADDR: 0xc91

免责声明:文章转载自《[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux环境安装jdk12-rpmjava-邮件发送下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

如何杀死linux-zombie僵尸进程

百科: ZOMBIE:僵尸状态,表示进程结束但尚未消亡的一种状态,此时进程已经结束运行并释放大部分资源,但尚未释放进程控制块。 与ZOMBIE对应的进程状态还有RUNNING(正在运行或等待运行状态),UNINTERRUPTABLE(不可中断阻塞状态),INTERRUPTABLE(可中断阻塞状态),STOPPED(挂起状态)。 服务器通常都会带来一些僵尸进...

Linux中最大进程数和最大文件数

前言 Linux系统中可以设置关于资源的使用限制,比如:进程数量,文件句柄数,连接数等等。在日常的工作中应该遇到过: -bash: fork: retry: Resource temporarily unavailable 或者 too many open files 这些类似的操作错误,前者是由于当前用户的进程数超出限制,后者由于当前用户的文件打开数超出...

Linux shadow文件中密码的加密方式

1)查看shadow文件的内容 cat/etc/shadow 可以得到shadow文件的内容,限于篇幅,我们举例说明: root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:14838:0:99999:7::: 其格式为: {用户名}:{加密后的口令密码}:{口令最后修改时间距原点(1970-1-1)的天数}:{口令最小修改间隔...

tail -f 实时查看日志文件 linux查看日志后100行

tail -f 实时查看日志文件 tail -f 日志文件logtail - 100f 实时查看日志文件 后一百行tail -f -n 100 catalina.out linux查看日志后100行搜寻字符串grep ‘搜寻字符串’ filename按ctrl+c 退出--------------------- 作者:wanghai76 来源:CSDN 原...

Linux普通用户执行提示权限不够,sudo提示找不到命令

问题源于使用哈工大老师操作系统课程的环境时,运行run这个shell文件出现这样的情况: song@ubuntu:~/workspace/oslab$ ./run -bash: ./run: 权限不够 song@ubuntu:~/workspace/oslab$ sudo ./run sudo: ./run:找不到命令 搜索网上有这样的解决过程 1.编辑文...

Linux下Redis的安装和部署

一、Redis介绍 Redis是当前比较热门的NOSQL系统之一,它是一个key-value存储系统。和Memcache类似,但很大程度补偿了Memcache的不足,它支持存储的value类型相对更多,包括string、list、set、zset和hash。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作。在此基础上...