看流星社区

 找回密码
 注册账号
查看: 1723|回复: 0

linux内核demo

[复制链接]

该用户从未签到

发表于 2017-6-1 12:52:05 | 显示全部楼层 |阅读模式
1,hello:
最基本的hello world内核模块
make
sudo insmod hello.ko
dmesg |tail
sudo rmmod hello
  1. /*************** hello.c ***************/
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. MODULE_LICENSE("Dual BSD/GPL");
  6. MODULE_AUTHOR("djwow");
  7. static int hello_init(void)
  8. {
  9.   printk(KERN_ALERT "Hello, world!\n");
  10.   return 0;
  11. }
  12. static void hello_exit(void)
  13. {
  14.   printk(KERN_ALERT "Goodbye, My Dear World!\n");
  15. }
  16. module_init(hello_init);
  17. module_exit(hello_exit);
复制代码





makefile:
  1. obj-m = hello.o
  2. KVERSION = $(shell uname -r)
  3. all:
  4.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
  5. clean:
  6.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
复制代码




2,hello-1,hello-2:
hello-2导出了一个hello_data的全局变量,供hello-1中的模块使用。
先编译hello-2。并将目录下的Module.symvers拷贝到hello-1中。然后再编译hello-1。
然后先安装hello-2中的模块,再运行hello-1中的模块。
或者将hello-1中的KBUILD_EXTRA_SYMBOLS = /mnt/hgfs/MallocFreeIBM/Linux/10ten-hellokernel/demo/hello-2/Module.symvers中的/mnt/hgfs/MallocFreeIBM/Linux/10ten-hellokernel/demo/hello-2修改为你自己对应的hello-2的路径。


hello-1.c
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. MODULE_LICENSE("GPL");
  5. extern int hello_data;
  6. static int hello_init(void)
  7. {
  8.         printk(KERN_ERR "hello,kernel!,this is hello module\n");
  9.         printk(KERN_ERR "hello_data:%d\n",++hello_data);
  10.         return 0;
  11. }
  12. static void hello_exit(void)
  13. {
  14.         printk(KERN_ERR "hello_data:%d\n",--hello_data);
  15.         printk(KERN_ERR "Leave hello module!\n");
  16. }
  17. module_init(hello_init);
  18. module_exit(hello_exit);
  19. MODULE_AUTHOR("djwow");
  20. MODULE_DESCRIPTION("This is hello module");
  21. MODULE_ALIAS("A simple example");
复制代码


hello_2.c
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. MODULE_LICENSE("GPL");
  5. unsigned int hello_data=100;
  6. EXPORT_SYMBOL(hello_data);
  7. static int hello_h_init(void)
  8. {
  9.         hello_data+=5;
  10.         printk(KERN_ERR "hello_data:%d\nhello kernel,this is hello_h module\n",hello_data);
  11.         return 0;
  12. }
  13. static void hello_h_exit(void)
  14. {
  15.         hello_data-=5;
  16.         printk(KERN_ERR "hello_data:%d\nleave hello_h module\n",hello_data);
  17. }
  18. module_init(hello_h_init);
  19. module_exit(hello_h_exit);
  20. MODULE_AUTHOR("djwow.com");
复制代码

makefile
  1. obj-m=hello_2.o
  2. KVERSION = $(shell uname -r)
  3. all:
  4.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
  5. clean:
  6.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
复制代码

3,hello-param用于向模块动态传递参数
编译之后运行方法:
insmod hello who="world" times=5

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/moduleparam.h>  
  4.       
  5. MODULE_LICENSE("Dual BSD/GPL");     
  6. static char *who= "world";            
  7. static int times = 1;
  8.       
  9. module_param(times,int,S_IRUSR);     
  10. module_param(who,charp,S_IRUSR);   
  11. static int hello_init(void)      
  12. {
  13.     int i;
  14.     for(i=0;i<times;i++)
  15.        printk(KERN_ALERT "(%d) hello, %s!\n",i,who);
  16.      return 0;
  17. }
  18. static void hello_exit(void)
  19. {
  20.     printk(KERN_ALERT"Goodbye, %s!\n",who);
  21. }
  22. module_init(hello_init);
  23. module_exit(hello_exit);
复制代码
makefile:
  1. obj-m = hello.o
  2. KVERSION = $(shell uname -r)
  3. all:
  4.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
  5. clean:
  6.         make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
复制代码

4,kernel-client 通信demop 顺便演示了timer使用
先分别运行make编译好client和kernel程序。
然后,加载驱动:sudo insmod timer-kernel.ko
然后,
cat /proc/devices,查看second对应的主功能号,如251
sudo mknod /dev/second c 251 0
然后运行client:
./timer-client


client:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. int main(void)
  5. {
  6.     int fd, i;
  7.     int data;
  8.     fd = open("/dev/second",O_RDONLY);
  9.     if (fd < 0)
  10.     {
  11.         printf("open /dev/second error\n");
  12.     }
  13.     for(i = 0; ; i++)
  14.     {
  15.       read(fd, &data, sizeof(data));
  16.       printf("read /dev/second is %d\n",data);
  17.       sleep(1);
  18.        }
  19.     close(fd);
  20. }
复制代码

makefile:
  1. timer-client:timer-client.o
  2.         gcc -o timer-client timer-client.o
  3. timer-client.o:timer-client.c
  4.         gcc -c timer-client.c -o timer-client.o
  5. clean:
  6.         rm -f *.o timer-client
复制代码
kernel:
  1. #include <linux/module.h>
  2. #include <linux/types.h>
  3. #include <linux/fs.h>
  4. #include <linux/errno.h>
  5. #include <linux/mm.h>
  6. #include <linux/sched.h>
  7. #include <linux/init.h>
  8. #include <linux/cdev.h>
  9. #include <asm/io.h>
  10. #include <asm/system.h>
  11. #include <asm/uaccess.h>
  12. #include <linux/timer.h>
  13. #include <asm/atomic.h>
  14. #define SECOND_MAJOR 0
  15. static int second_major = SECOND_MAJOR;
  16. struct second_dev
  17. {
  18.     struct cdev cdev;
  19.     atomic_t counter;
  20.     struct timer_list s_timer;
  21. };
  22. struct second_dev *second_devp;
  23. static void second_timer_handle(unsigned long arg)
  24. {
  25.     mod_timer(&second_devp->s_timer, jiffies + HZ);
  26.     atomic_inc(&second_devp->counter);
  27.    
  28.     printk(KERN_INFO "current jiffies is %ld\n",jiffies);
  29. }
  30. int second_open(struct inode *inode, struct file *filp)
  31. {
  32.   init_timer(&second_devp->s_timer);
  33.   second_devp->s_timer.function = &second_timer_handle;
  34.   second_devp->s_timer.expires = jiffies + HZ;
  35.   
  36.   add_timer(&second_devp->s_timer);
  37.   atomic_set(&second_devp->counter, 0);
  38.   return 0;   
  39. }
  40. int second_release(struct inode *inode, struct file *filp)
  41. {
  42.     del_timer(&second_devp->s_timer);
  43.    
  44.     return 0;
  45. }
  46. static ssize_t second_read(struct file *filp, char __user *buf, size_t count,
  47.   loff_t *ppos)
  48. {
  49.     int counter;
  50.    
  51.     counter = atomic_read(&second_devp->counter);
  52.     if (put_user(counter, (int *)buf))
  53.     {
  54.         return -EFAULT;
  55.     }else
  56.     {
  57.         return sizeof(unsigned int);
  58.     }
  59.    
  60. }
  61. static const struct file_operations second_fops =
  62. {
  63.     .owner = THIS_MODULE,
  64.     .open = second_open,
  65.     .release = second_release,
  66.     .read = second_read,
  67. };
  68. static void second_setup_cdev(struct second_dev *dev, int index)
  69. {
  70.     int err, devno = MKDEV(second_major, index);
  71.     cdev_init(&dev->cdev, &second_fops);
  72.     dev->cdev.owner = THIS_MODULE;
  73.     dev->cdev.ops = &second_fops;
  74.     err = cdev_add(&dev->cdev, devno, 1);
  75.     if (err)
  76.     {
  77.         printk(KERN_NOTICE "Error %d add second%d", err, index);
  78.     }
  79. }
  80. int second_init(void)
  81. {
  82.     int ret;
  83.     dev_t devno = MKDEV(second_major, 0);
  84.    
  85.     if (second_major)
  86.     {
  87.         ret = register_chrdev_region(devno, 1, "second");
  88.     }else
  89.     {
  90.         ret = alloc_chrdev_region(&devno, 0, 1, "second");
  91.         second_major = MAJOR(devno);
  92.     }
  93.     if (ret < 0)
  94.     {
  95.         return ret;
  96.     }
  97.    
  98.     second_devp = kmalloc(sizeof(struct second_dev), GFP_KERNEL);
  99.     if (!second_devp)
  100.     {
  101.         ret = -ENOMEM;
  102.         goto fail_malloc;
  103.     }
  104.    
  105.     memset(second_devp, 0, sizeof(struct second_dev));
  106.    
  107.     second_setup_cdev(second_devp, 0);
  108.    
  109.     return 0;
  110.   fail_malloc:
  111.       unregister_chrdev_region(devno, 1);
  112.       return ret;
  113. }
  114. void second_exit(void)
  115. {
  116.     cdev_del(&second_devp->cdev);
  117.     kfree(second_devp);
  118.     unregister_chrdev_region(MKDEV(second_major, 0), 1);
  119. }
  120. MODULE_AUTHOR("djwow");
  121. MODULE_LICENSE("Dual BSD/GPL");
  122. module_param(second_major, int, S_IRUGO);
  123. module_init(second_init);
  124. module_exit(second_exit);
复制代码

5,char_drv 通信demo
另外一个例子可以看我了另一篇文件
51456791


先运行make编译好kernel程序。
然后,加载驱动:sudo insmod char_drv.ko
然后,
cat /proc/devices,查看mem_dev对应的主功能号,如251
sudo mknod /dev/memdev0 c 251 0
然后运行client:
gcc -o test_char_drv test_char_drv.c
./test_char_drv


R3:
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main()
  4. {
  5.     FILE *fp0 = NULL;
  6.     char Buf[4096];
  7.    
  8.     /*初始化Buf*/
  9.     strcpy(Buf,"Mem is char dev!");
  10.     printf("BUF: %s\n",Buf);
  11.    
  12.     /*打开设备文件*/
  13.     fp0 = fopen("/dev/memdev0","r+");
  14.     if (fp0 == NULL)
  15.     {
  16.         printf("Open Memdev0 Error!\n");
  17.         return -1;
  18.     }
  19.    
  20.     /*写入设备*/
  21.     fwrite(Buf, sizeof(Buf), 1, fp0);
  22.    
  23.     /*重新定位文件位置(思考没有该指令,会有何后果)*/
  24.     fseek(fp0,0,SEEK_SET);
  25.    
  26.     /*清除Buf*/
  27.     strcpy(Buf,"Buf is NULL!");
  28.     printf("BUF: %s\n",Buf);
  29.    
  30.    
  31.     /*读出设备*/
  32.     fread(Buf, sizeof(Buf), 1, fp0);
  33.    
  34.     /*检测结果*/
  35.     printf("BUF: %s\n",Buf);
  36.    
  37.     return 0;   
  38. }
复制代码

R0:
  1. char_drv.h
  2. #ifndef _MEMDEV_H_
  3. #define _MEMDEV_H_
  4. #ifndef MEMDEV_MAJOR
  5. #define MEMDEV_MAJOR 251   /*预设的mem的主设备号*/
  6. #endif
  7. #ifndef MEMDEV_NR_DEVS
  8. #define MEMDEV_NR_DEVS 2    /*设备数*/
  9. #endif
  10. #ifndef MEMDEV_SIZE
  11. #define MEMDEV_SIZE 4096
  12. #endif
  13. /*mem设备描述结构体*/
  14. struct mem_dev                                    
  15. {                                                        
  16.   char *data;                     
  17.   unsigned long size;      
  18. };
  19. #endif /* _MEMDEV_H_ */
复制代码
char_drv.c
  1. #include "char_drv.h"
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/mm.h>
  7. #include <linux/sched.h>
  8. #include <linux/init.h>
  9. #include <linux/cdev.h>
  10. #include <asm/io.h>
  11. #include <asm/system.h>
  12. #include <asm/uaccess.h>
  13. static int mem_major = MEMDEV_MAJOR;
  14. module_param(mem_major, int, S_IRUGO);
  15. struct mem_dev *mem_devp; /*设备结构体指针*/
  16. struct cdev cdev;
  17. /*文件打开函数*/
  18. int mem_open(struct inode *inode, struct file *filp)
  19. {
  20.     struct mem_dev *dev;
  21.    
  22.     /*获取次设备号*/
  23.     int num = MINOR(inode->i_rdev);
  24.     if (num >= MEMDEV_NR_DEVS)
  25.             return -ENODEV;
  26.     dev = &mem_devp[num];
  27.    
  28.     /*将设备描述结构指针赋值给文件私有数据指针*/
  29.     filp->private_data = dev;
  30.    
  31.     return 0;
  32. }
  33. /*文件释放函数*/
  34. int mem_release(struct inode *inode, struct file *filp)
  35. {
  36.   return 0;
  37. }
  38. /*读函数*/
  39. static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  40. {
  41.   unsigned long p =  *ppos;        /*记录文件指针偏移位置*/  
  42.   unsigned int count = size;    /*记录需要读取的字节数*/
  43.   int ret = 0;    /*返回值*/  
  44.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  45.   /*判断读位置是否有效*/
  46.   if (p >= MEMDEV_SIZE)    /*要读取的偏移大于设备的内存空间*/  
  47.     return 0;
  48.   if (count > MEMDEV_SIZE - p)     /*要读取的字节大于设备的内存空间*/
  49.     count = MEMDEV_SIZE - p;
  50.   /*读数据到用户空间:内核空间->用户空间交换数据*/  
  51.   if (copy_to_user(buf, (void*)(dev->data + p), count))
  52.   {
  53.     ret =  - EFAULT;
  54.   }
  55.   else
  56.   {
  57.     *ppos += count;
  58.     ret = count;
  59.    
  60.     printk(KERN_INFO "read %d bytes(s) from %ld\n", count, p);
  61.   }
  62.   return ret;
  63. }
  64. /*写函数*/
  65. static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
  66. {
  67.   unsigned long p =  *ppos;
  68.   unsigned int count = size;
  69.   int ret = 0;
  70.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  71.   
  72.   /*分析和获取有效的写长度*/
  73.   if (p >= MEMDEV_SIZE)
  74.     return 0;
  75.   if (count > MEMDEV_SIZE - p)    /*要写入的字节大于设备的内存空间*/
  76.     count = MEMDEV_SIZE - p;
  77.    
  78.   /*从用户空间写入数据*/
  79.   if (copy_from_user(dev->data + p, buf, count))
  80.     ret =  - EFAULT;
  81.   else
  82.   {
  83.     *ppos += count;      /*增加偏移位置*/  
  84.     ret = count;      /*返回实际的写入字节数*/
  85.    
  86.     printk(KERN_INFO "written %d bytes(s) from %ld\n", count, p);
  87.   }
  88.   return ret;
  89. }
  90. /* seek文件定位函数 */
  91. static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
  92. {
  93.     loff_t newpos;      
  94.     switch(whence) {
  95.       case 0: /* SEEK_SET */       /*相对文件开始位置偏移*/
  96.         newpos = offset;           /*更新文件指针位置*/
  97.         break;
  98.       case 1: /* SEEK_CUR */
  99.         newpos = filp->f_pos + offset;   
  100.         break;
  101.       case 2: /* SEEK_END */
  102.         newpos = MEMDEV_SIZE -1 + offset;
  103.         break;
  104.       default: /* can't happen */
  105.         return -EINVAL;
  106.     }
  107.     if ((newpos<0) || (newpos>MEMDEV_SIZE))
  108.         return -EINVAL;
  109.         
  110.     filp->f_pos = newpos;
  111.     return newpos;
  112. }
  113. /*文件操作结构体*/
  114. static const struct file_operations mem_fops =
  115. {
  116.   .owner = THIS_MODULE,
  117.   .llseek = mem_llseek,
  118.   .read = mem_read,
  119.   .write = mem_write,
  120.   .open = mem_open,
  121.   .release = mem_release,
  122. };
  123. /*设备驱动模块加载函数*/
  124. static int memdev_init(void)
  125. {
  126.   int result;
  127.   int i;
  128.   dev_t devno = MKDEV(mem_major, 0);
  129.    /* 申请设备号,当xxx_major不为0时,表示静态指定;当为0时,表示动态申请*/
  130.   /* 静态申请设备号*/
  131.   if (mem_major)
  132.     result = register_chrdev_region(devno, 2, "mem_dev");
  133.   else  /* 动态分配设备号 */
  134.   {
  135.     result = alloc_chrdev_region(&devno, 0, 2, "mem_dev");
  136.     mem_major = MAJOR(devno);    /*获得申请的主设备号*/
  137.   }  
  138.   
  139.   if (result < 0)
  140.     return result;
  141. /*初始化cdev结构,并传递file_operations结构指针*/
  142.   cdev_init(&cdev, &mem_fops);   
  143.   cdev.owner = THIS_MODULE;    /*指定所属模块*/
  144.   cdev.ops = &mem_fops;
  145.   
  146.   /* 注册字符设备 */
  147.   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
  148.    
  149.   /* 为设备描述结构分配内存*/
  150.   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
  151.   if (!mem_devp)    /*申请失败*/
  152.   {
  153.     result =  - ENOMEM;
  154.     goto fail_malloc;
  155.   }
  156.   memset(mem_devp, 0, sizeof(struct mem_dev));
  157.   
  158.   /*为设备分配内存*/
  159.   for (i=0; i < MEMDEV_NR_DEVS; i++)
  160.   {
  161.         mem_devp[i].size = MEMDEV_SIZE;
  162.         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
  163.         memset(mem_devp[i].data, 0, MEMDEV_SIZE);
  164.   }
  165.    
  166.   return 0;
  167.   fail_malloc:
  168.   unregister_chrdev_region(devno, 1);
  169.   
  170.   return result;
  171. }
  172. /*模块卸载函数*/
  173. static void memdev_exit(void)
  174. {
  175.   cdev_del(&cdev);   /*注销设备*/
  176.   kfree(mem_devp);     /*释放设备结构体内存*/
  177.   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
  178. }
  179. MODULE_AUTHOR("djwow");
  180. MODULE_LICENSE("GPL");
  181. module_init(memdev_init);
  182. module_exit(memdev_exit);
复制代码
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 16:57

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表