简介

操作系统将虚拟内存分为内核空间和用户空间。内核空间严格保留用于运行内核,内核扩展和大多数设备驱动程序。相反,用户空间是所有用户模式应用程序都在其中工作的存储区,并且可以在必要时将该存储区换出。
在用户空间和内核空间之间进行通信的方法有很多

  1. IOCTL
  2. Procfs
  3. Sysfs
  4. Configfs
  5. Debugfs
  6. Sysctl
  7. UDP Sockets
  8. Netlink Sockets

在这里我们讨论Procfs

Procfs in Linux

/proc 文件是procfs(进程文件系统)的挂载点,该文件是内存中的文件系统。许多进程在此虚拟文件系统上存储有关自身的信息。ProcFS还存储其他系统信息。用户空间程序可以使用proc文件来读取内核导出的信息。proc文件系统中的每个条目都提供了一些来自内核的信息。

  1. cat /proc/meminfo
  2. cat /proc/modules
  3. /proc/devices -注册字符和主号码
  4. /proc/iomem —系统上的物理RAM和总线设备地址
  5. /proc/ioports —系统上的I / O端口地址(尤其是x86系统)
  6. /proc/interrupts —已注册的中断请求号
  7. /proc/softirqs —已注册的软IRQ
  8. /proc/swaps -当前有效的掉期
  9. /proc/kallsyms —运行内核符号,包括从加载的模块中
  10. /proc/partitions —当前连接的块设备及其分区
  11. /proc/filesystems —当前活动的文件系统驱动程序
  12. /proc/cpuinfo —有关系统上CPU的信息

当我们要调试内核模块时,proc文件系统也非常有用。在调试时,我们可能想知道模块中各种变量的值,或者也许是模块正在处理的数据。在这种情况下,我们可以为自己创建一个proc条目,并转储我们要在条目中查找的所有数据。
proc条目可以用于通过写入内核将数据传递到内核,因此可以有两种proc条目。

  1. 仅从内核空间读取数据的条目。
  2. 一个在内核空间中读取和写入数据的条目。

    创建过程条目

    proc条目的创建在3.10及更高版本的内核中经历了相当大的变化。在本文中,我们将看到可以在Linux内核3.10及更高版本中使用的一种方法,让我们看看如何在3.10及更高版本中创建proc条目。我使用的linux版本为
    1. VERSION = 4
    2. PATCHLEVEL = 19
    3. SUBLEVEL = 19
    ```c

    include

    static inline struct proc_dir_entry proc_create(const char name, umode_t mode,
    1. struct proc_dir_entry *parent,
    2. const struct file_operations *proc_fops)

: The name of the proc entry

: The access mode for proc entry

: The name of the parent directory under /proc. If NULL is passed as a parent, the /proc directory will be set as a parent.

: The structure in which the file operations for the proc entry will be created.

  1. 例如,要在/ proc下创建一个名称为“ etx_proc”的proc条目,上述功能将定义如下,
  2. ```c
  3. proc_create("etx_proc",0666,NULL,&proc_fops);

Procfs文件系统

现在,我们需要创建file_operations结构proc_fops,在其中可以映射proc条目的读写功能。

  1. static struct file_operations proc_fops = {
  2. .open = open_proc,
  3. .read = read_proc,
  4. .write = write_proc,
  5. .release = release_proc
  6. };

打开和释放功能

这些功能可选

  1. static int open_proc(struct inode *inode, struct file *file)
  2. {
  3. printk(KERN_INFO "proc file opend.....\t");
  4. return 0;
  5. }
  6. static int release_proc(struct inode *inode, struct file *file)
  7. {
  8. printk(KERN_INFO "proc file released.....\n");
  9. return 0;
  10. }

写功能

写函数将使用函数copy_from_user从用户空间接收数据到数组“ etx_array”中。

  1. static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off)
  2. {
  3. printk(KERN_INFO "proc file write.....\t");
  4. copy_from_user(etx_array,buff,len);
  5. return len;
  6. }

读取功能

一旦将数据写入proc条目,我们就可以使用读取功能从proc条目读取数据,即使用copy_to_user函数将数据传输到用户空间。

  1. static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset)
  2. {
  3. printk(KERN_INFO "proc file read.....\n");
  4. if(len)
  5. len=0;
  6. else{
  7. len=1;
  8. return 0;
  9. }
  10. copy_to_user(buffer,etx_array,20);
  11. return length;;
  12. }

删除过程条目

  1. void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

代码

  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kdev_t.h>
  5. #include <linux/fs.h>
  6. #include <linux/cdev.h>
  7. #include <linux/device.h>
  8. #include <linux/slab.h> //kmalloc()
  9. #include <linux/uaccess.h> //copy_to/from_user()
  10. #include <linux/ioctl.h>
  11. #include <linux/proc_fs.h>
  12. #define WR_VALUE _IOW('a', 'a', int32_t *)
  13. #define RD_VALUE _IOR('a', 'b', int32_t *)
  14. int32_t value = 0;
  15. char etx_array[20] = "try_proc_array\n";
  16. static int len = 1;
  17. dev_t dev = 0;
  18. static struct class *dev_class;
  19. static struct cdev etx_cdev;
  20. static int __init etx_driver_init(void);
  21. static void __exit etx_driver_exit(void);
  22. /*************** Driver Functions **********************/
  23. static int etx_open(struct inode *inode, struct file *file);
  24. static int etx_release(struct inode *inode, struct file *file);
  25. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
  26. static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
  27. static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
  28. /***************** Procfs Functions *******************/
  29. static int open_proc(struct inode *inode, struct file *file);
  30. static int release_proc(struct inode *inode, struct file *file);
  31. static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length, loff_t *offset);
  32. static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t *off);
  33. static struct file_operations fops =
  34. {
  35. .owner = THIS_MODULE,
  36. .read = etx_read,
  37. .write = etx_write,
  38. .open = etx_open,
  39. .unlocked_ioctl = etx_ioctl,
  40. .release = etx_release,
  41. };
  42. static struct file_operations proc_fops = {
  43. .open = open_proc,
  44. .read = read_proc,
  45. .write = write_proc,
  46. .release = release_proc};
  47. static int open_proc(struct inode *inode, struct file *file)
  48. {
  49. printk(KERN_INFO "proc file opend.....\t");
  50. return 0;
  51. }
  52. static int release_proc(struct inode *inode, struct file *file)
  53. {
  54. printk(KERN_INFO "proc file released.....\n");
  55. return 0;
  56. }
  57. static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
  58. {
  59. int ret = 0x00;
  60. printk(KERN_INFO "proc file read.....\n");
  61. if (len)
  62. len = 0;
  63. else
  64. {
  65. len = 1;
  66. return 0;
  67. }
  68. ret = copy_to_user(buffer, etx_array, 20);
  69. (void)ret;
  70. return length;
  71. ;
  72. }
  73. static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t *off)
  74. {
  75. int ret = 0x00;
  76. int maxlen = sizeof(etx_array) / sizeof(etx_array[0]);
  77. int length = len;
  78. if (length > maxlen)
  79. length = maxlen;
  80. ret = copy_from_user(etx_array, buff, length);
  81. etx_array[length] = '\0';
  82. // printk(KERN_INFO "proc file write....., %s,%d byte\n", etx_array, length);
  83. printk(KERN_INFO "proc file write...\n");
  84. (void)ret;
  85. return len;
  86. }
  87. static int etx_open(struct inode *inode, struct file *file)
  88. {
  89. printk(KERN_INFO "Device File Opened...!!!\n");
  90. return 0;
  91. }
  92. static int etx_release(struct inode *inode, struct file *file)
  93. {
  94. printk(KERN_INFO "Device File Closed...!!!\n");
  95. return 0;
  96. }
  97. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
  98. {
  99. int ret = 0x00;
  100. printk(KERN_INFO "Readfunction\n");
  101. ret = copy_to_user(buf, etx_array, sizeof(etx_array) / sizeof(etx_array[0]));
  102. return len;
  103. }
  104. static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
  105. {
  106. printk(KERN_INFO "Write Function\n");
  107. return 0x0;
  108. }
  109. static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  110. {
  111. int ret = 0x00;
  112. switch (cmd)
  113. {
  114. case WR_VALUE:
  115. ret = copy_from_user(&value, (int32_t *)arg, sizeof(value));
  116. printk(KERN_INFO "Value = %d\n", value);
  117. break;
  118. case RD_VALUE:
  119. ret = copy_to_user((int32_t *)arg, &value, sizeof(value));
  120. break;
  121. }
  122. (void)ret;
  123. return 0;
  124. }
  125. static int __init etx_driver_init(void)
  126. {
  127. /*Allocating Major number*/
  128. if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
  129. {
  130. printk(KERN_INFO "Cannot allocate major number\n");
  131. return -1;
  132. }
  133. printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
  134. /*Creating cdev structure*/
  135. cdev_init(&etx_cdev, &fops);
  136. /*Adding character device to the system*/
  137. if ((cdev_add(&etx_cdev, dev, 1)) < 0)
  138. {
  139. printk(KERN_INFO "Cannot add the device to the system\n");
  140. goto r_class;
  141. }
  142. /*Creating struct class*/
  143. if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
  144. {
  145. printk(KERN_INFO "Cannot create the struct class\n");
  146. goto r_class;
  147. }
  148. /*Creating device*/
  149. if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
  150. {
  151. printk(KERN_INFO "Cannot create the Device 1\n");
  152. goto r_device;
  153. }
  154. /*Creating Proc entry*/
  155. proc_create("etx_proc", 0666, NULL, &proc_fops);
  156. printk(KERN_INFO "Device Driver Insert...Done!!!\n");
  157. return 0;
  158. r_device:
  159. class_destroy(dev_class);
  160. r_class:
  161. unregister_chrdev_region(dev, 1);
  162. return -1;
  163. }
  164. void __exit etx_driver_exit(void)
  165. {
  166. remove_proc_entry("etx_proc", NULL);
  167. device_destroy(dev_class, dev);
  168. class_destroy(dev_class);
  169. cdev_del(&etx_cdev);
  170. unregister_chrdev_region(dev, 1);
  171. printk(KERN_INFO "Device Driver Remove...Done!!!\n");
  172. }
  173. module_init(etx_driver_init);
  174. module_exit(etx_driver_exit);
  175. MODULE_LICENSE("GPL");
  176. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  177. MODULE_DESCRIPTION("A Sample Profs Demo");
  178. MODULE_VERSION("2:1.0");
  • 测试 ```c /proc # ls | grep etx_proc etx_proc

write

echo “helloworld1234” >> /proc/etx_proc

读数据

/mnt # hexdump /proc/etx_proc -c proc file opend….. proc file read….. 0000000 h e l l o w o r l d 1 2 3 \n \0 \0 0000010 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 ```