朝阳无限好 - Morning Sun Community

 找回密码
 注册
查看: 154|回复: 0

[分享] 一个ioctrl的简单使用示例,说明了内核态多进程共用同一个全局变量空间

[复制链接]
发表于 2020-7-19 15:48:25 | 显示全部楼层 |阅读模式
本帖最后由 yzhms 于 2020-7-19 15:50 编辑

内核态helloio.c
  1. #include <linux/init.h> //必须
  2. #include <linux/module.h> //必须
  3. #include <linux/fs.h> //file_operations 需要
  4. #include <linux/cdev.h> //file_operations 需要
  5. #include <linux/uaccess.h> //不同平台路径不同,copy_from_user需要


  6. #define DEV_SIZE 100
  7. #define TEST_CLEAR                0
  8. #define TEST_SET                1
  9. #define TEST_GET            3 //ioctrl 参数不能传2,内核保留使用

  10. int g_flagio = 0;

  11. struct _test_t{
  12.         char kbuf[DEV_SIZE];
  13.         unsigned int major;
  14.         unsigned int minor;
  15.         unsigned int cur_size;
  16.         dev_t devno;
  17.         struct cdev test_cdev;
  18. };

  19. int test_open(struct inode *node, struct file *filp)
  20. {
  21.         struct _test_t *dev;
  22.         dev = container_of(node->i_cdev, struct _test_t, test_cdev);
  23.         filp->private_data = dev;
  24.         return 0;
  25. }

  26. int test_close(struct inode *node, struct file *filp)
  27. {
  28.         return 0;
  29. }

  30. typedef struct my_msg {
  31.     int a;
  32.     short b;
  33.     int c;
  34.     short d;
  35. } MY_MSG;

  36. long test_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
  37. {
  38.         int ret = 0;
  39.         struct _test_t *dev = filp->private_data;
  40.     MY_MSG msg = {0};
  41.     ret = copy_from_user(&msg, (MY_MSG *)arg, sizeof(MY_MSG));
  42.     if (ret != 0) {
  43.         printk(KERN_ALERT "copy_from_user fail! ret=%d\n", ret);
  44.         return -1;
  45.     }
  46.     printk(KERN_ALERT "g_flagio1=%d\n", g_flagio);
  47.         switch(cmd) {
  48.                 case TEST_CLEAR:
  49.                         memset(dev->kbuf, 0, DEV_SIZE);
  50.                         dev->cur_size = 0;
  51.                         filp->f_pos = 0;
  52.                         ret = 0;
  53.             printk(KERN_ALERT "TEST_CLEAR! arg=0x%lx,a=%d,b=%d,c=%d,d=%d\n", arg, msg.a, msg.b, msg.c, msg.d);
  54.             g_flagio = 0;
  55.                         break;
  56.         case TEST_SET:
  57.             printk(KERN_ALERT "TEST_SET! arg=0x%lx,a=%d,b=%d,c=%d,d=%d\n", arg, msg.a, msg.b, msg.c, msg.d);
  58.             g_flagio = msg.a;
  59.             break;
  60.         case TEST_GET:
  61.             printk(KERN_ALERT "g_flagio=%d\n", g_flagio);
  62.             break;
  63.                 default:        /*命令错误时的处理*/
  64.                         printk(KERN_ALERT "error cmd=%d, arg=0x%lx,a=%d,b=%d,c=%d,d=%d!\n", cmd, arg, msg.a, msg.b, msg.c, msg.d);
  65.                         ret = - EINVAL;
  66.                         break;
  67.         }
  68.     printk(KERN_ALERT "g_flagio2=%d\n", g_flagio);

  69.         return ret;
  70. }

  71. struct file_operations test_fops = {
  72.         .open = test_open,
  73.         .release = test_close,
  74.         //.write = test_write,
  75.         //.read = test_read,
  76.         //.llseek = test_llseek,
  77.         .unlocked_ioctl = test_ioctl,
  78. };

  79. struct _test_t my_dev;

  80. static int hello_io_init(void)
  81. {
  82.     int result = 0;
  83.         my_dev.cur_size = 0;
  84.         my_dev.major = 0;
  85.         my_dev.minor = 0;

  86.         /*1.申请设备号*/
  87.         if(my_dev.major){                                               
  88.                 my_dev.devno = MKDEV(my_dev.major, my_dev.minor);
  89.                 result = register_chrdev_region(my_dev.devno, 1, "test new driver");
  90.         }else{
  91.                 result = alloc_chrdev_region(&my_dev.devno, my_dev.minor, 1, "test alloc diver");
  92.                 my_dev.major = MAJOR(my_dev.devno);
  93.                 my_dev.minor = MINOR(my_dev.devno);
  94.         }

  95.         if(result < 0){
  96.                 printk(KERN_ALERT "register devno errno!\n");
  97.                 goto err0;
  98.         }

  99.         printk("major[%d] minor[%d]\n", my_dev.major, my_dev.minor);

  100.         /*2.注册设备*/
  101.         cdev_init(&my_dev.test_cdev, &test_fops);
  102.         my_dev.test_cdev.owner = THIS_MODULE;
  103.         result = cdev_add(&my_dev.test_cdev, my_dev.devno, 1);
  104.         if(result < 0){
  105.                 printk(KERN_ALERT "cdev_add errno!\n");
  106.                 goto err1;
  107.         }

  108.         printk(KERN_ALERT "Hello World io enter\n");
  109.         return 0;

  110. err1:
  111.         unregister_chrdev_region(my_dev.devno, 1);
  112. err0:
  113.         return result;
  114. }
  115. static void hello_io_exit(void)
  116. {
  117.             /*1.从内核中删除cdev*/
  118.         cdev_del(&my_dev.test_cdev);
  119.         /*2.注销设备号*/
  120.         unregister_chrdev_region(my_dev.devno, 1);

  121.     printk(KERN_ALERT "Hello World io exit\n");
  122. }


  123. module_init(hello_io_init);
  124. module_exit(hello_io_exit);[code]#


  125. MODULE_LICENSE("Dual BSD/GPL");
  126. MODULE_AUTHOR("Yang Zhao");
  127. MODULE_DESCRIPTION("A Sample Hello World Ioctrl Test Module");
  128. MODULE_ALIAS("A Sample ioctrl module");
复制代码

内核态makefile:
  1. #
  2. #Makefile for the helloworld.c
  3. #
  4. obj-m := helloio.o
  5. CURRENT_PATH := $(shell pwd)
  6. LINUX_KERNEL := $(shell uname -r)
  7. LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
  8. #KBUILD_EXTRA_SYMBOLS+=~/Desktop/work/helloworld/Module.symvers
  9. all:
  10.         $(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
  11. clean:
  12.         rm *.ko
  13.         rm *.o
复制代码


用户态helloapp.c
  1. #include <stdio.h>
  2. #include <stdlib.h> //strtoul需要
  3. #include <sys/types.h> //open需要
  4. #include <sys/stat.h> //open需要
  5. #include <fcntl.h> //open需要
  6. #include <sys/ioctl.h> //ioctrl需要
  7. #include <unistd.h> //close需要
  8. #include <errno.h>  //errno需要

  9. #define TEST_CLEAR                0
  10. #define TEST_SET                1
  11. #define TEST_GET            3 //ioctrl 参数不能传2,内核保留使用
  12. typedef struct my_msg {
  13.     int a;
  14.     short b;
  15.     int c;
  16.     short d;
  17. } MY_MSG;

  18. int main(int argc, void* argv[])
  19. {
  20.         char buf[20];
  21.         int fd;
  22.         int ret;
  23.         MY_MSG msg = {12345678, 7890, 23456789, 3456};
  24.         unsigned char arg1 = 0xab;
  25.         unsigned long arg2 = 0x12345678;
  26.         unsigned char arg3 = 0xcd;
  27.         int cmd = TEST_CLEAR;

  28.         if (argc > 1) {
  29.                 cmd = (int)strtoul(argv[1], NULL, 10);
  30.                 printf("argc is %d, argv[0]=%s, argv[1]=%s, cmd=%d\n", argc, argv[0], argv[1], cmd);
  31.         }

  32.         fd = open("/dev/test", O_RDWR);
  33.         if(fd < 0)
  34.         {
  35.                 printf("open error, ret=%d\n", fd);
  36.                 printf("Error %d: Failed to open file\n", errno);
  37.                 if (errno == EEXIST ) {
  38.                         printf("EEXIST 参数pathname 所指的文件已存在, 却使用了O_CREAT 和O_EXCL 旗标. \r\n");
  39.                 } else if(errno == EACCES) {
  40.                         printf("EACCESS 参数pathname 所指的文件不符合所要求测试的权限.\r\n");
  41.                 } else if(errno == EROFS) {
  42.                         printf("EROFS 欲测试写入权限的文件存在于只读文件系统内.\r\n");
  43.                 }
  44.                 return -1;
  45.         }
  46.        
  47.         ret = ioctl(fd, cmd, &msg);
  48.         if(ret != 0)
  49.         {
  50.                 printf("ioctl error, ret=%d\n", ret);
  51.         }

  52.         close(fd);
  53.         return 0;
  54. }
复制代码


使用日志:
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ make
make -C /usr/src/linux-headers-5.3.0-3-amd64 M=/home/morningsun/Desktop/work/helloioctrl modules
make[1]: 进入目录“/usr/src/linux-headers-5.3.0-3-amd64”
  CC [M]  /home/morningsun/Desktop/work/helloioctrl/helloio.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/morningsun/Desktop/work/helloioctrl/helloio.mod.o
  LD [M]  /home/morningsun/Desktop/work/helloioctrl/helloio.ko
make[1]: 离开目录“/usr/src/linux-headers-5.3.0-3-amd64”
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo insmod  ./helloio.ko
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7028.327006] Hello World io exit
[ 7036.728781] major[242] minor[0]
[ 7036.728783] Hello World io enter
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo mknod /dev/test c 242 0
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ gcc helloapp.c
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out 3
argc is 2, argv[0]=./a.out, argv[1]=3, cmd=3
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c

[ 7052.782395] g_flagio1=0
[ 7052.782397] g_flagio=0
[ 7052.782398] g_flagio2=0
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out 1
argc is 2, argv[0]=./a.out, argv[1]=1, cmd=1
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7067.437513] g_flagio1=0
[ 7067.437515] TEST_SET! arg=0x7ffd25634030,a=12345678,b=7890,c=23456789,d=3456
[ 7067.437516] g_flagio2=12345678
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out 3
argc is 2, argv[0]=./a.out, argv[1]=3, cmd=3
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7075.198575] g_flagio1=12345678
[ 7075.198577] g_flagio=12345678
[ 7075.198578] g_flagio2=12345678
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out 3
argc is 2, argv[0]=./a.out, argv[1]=3, cmd=3
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7083.429585] g_flagio1=12345678
[ 7083.429588] g_flagio=12345678
[ 7083.429588] g_flagio2=12345678
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7088.662049] g_flagio1=12345678
[ 7088.662052] TEST_CLEAR! arg=0x7fff2032a270,a=12345678,b=7890,c=23456789,d=3456
[ 7088.662052] g_flagio2=0
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo ./a.out 3
argc is 2, argv[0]=./a.out, argv[1]=3, cmd=3
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$ sudo dmesg -c
[ 7094.374037] g_flagio1=0
[ 7094.374039] g_flagio=0
[ 7094.374039] g_flagio2=0
morningsun@MorningSun-Deepin:~/Desktop/work/helloioctrl$
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|手机版|Archiver|朝阳无限好 ( 琼ICP备19005269号-1 )

GMT+8, 2020-10-25 10:31 , Processed in 0.064373 second(s), 24 queries .

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