简介
操作系统将虚拟内存分为内核空间和用户空间。内核空间严格保留用于运行内核,内核扩展和大多数设备驱动程序。相反,用户空间是所有用户模式应用程序都在其中工作的存储区,并且可以在必要时将该存储区换出。
在用户空间和内核空间之间进行通信的方法有很多
Procfs in Linux
/proc 文件是procfs(进程文件系统)的挂载点,该文件是内存中的文件系统。许多进程在此虚拟文件系统上存储有关自身的信息。ProcFS还存储其他系统信息。用户空间程序可以使用proc文件来读取内核导出的信息。proc文件系统中的每个条目都提供了一些来自内核的信息。
cat /proc/meminfocat /proc/modules/proc/devices -注册字符和主号码/proc/iomem —系统上的物理RAM和总线设备地址/proc/ioports —系统上的I / O端口地址(尤其是x86系统)/proc/interrupts —已注册的中断请求号/proc/softirqs —已注册的软IRQ/proc/swaps -当前有效的掉期/proc/kallsyms —运行内核符号,包括从加载的模块中/proc/partitions —当前连接的块设备及其分区/proc/filesystems —当前活动的文件系统驱动程序/proc/cpuinfo —有关系统上CPU的信息
当我们要调试内核模块时,proc文件系统也非常有用。在调试时,我们可能想知道模块中各种变量的值,或者也许是模块正在处理的数据。在这种情况下,我们可以为自己创建一个proc条目,并转储我们要在条目中查找的所有数据。
proc条目可以用于通过写入内核将数据传递到内核,因此可以有两种proc条目。
- 仅从内核空间读取数据的条目。
- 一个在内核空间中读取和写入数据的条目。
创建过程条目
proc条目的创建在3.10及更高版本的内核中经历了相当大的变化。在本文中,我们将看到可以在Linux内核3.10及更高版本中使用的一种方法,让我们看看如何在3.10及更高版本中创建proc条目。我使用的linux版本为
```cVERSION = 4PATCHLEVEL = 19SUBLEVEL = 19
include
static inline struct proc_dir_entry proc_create(const char name, umode_t mode,struct proc_dir_entry *parent,const struct file_operations *proc_fops)
例如,要在/ proc下创建一个名称为“ etx_proc”的proc条目,上述功能将定义如下,```cproc_create("etx_proc",0666,NULL,&proc_fops);
Procfs文件系统
现在,我们需要创建file_operations结构proc_fops,在其中可以映射proc条目的读写功能。
static struct file_operations proc_fops = {.open = open_proc,.read = read_proc,.write = write_proc,.release = release_proc};
打开和释放功能
这些功能可选
static int open_proc(struct inode *inode, struct file *file){printk(KERN_INFO "proc file opend.....\t");return 0;}static int release_proc(struct inode *inode, struct file *file){printk(KERN_INFO "proc file released.....\n");return 0;}
写功能
写函数将使用函数copy_from_user从用户空间接收数据到数组“ etx_array”中。
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off){printk(KERN_INFO "proc file write.....\t");copy_from_user(etx_array,buff,len);return len;}
读取功能
一旦将数据写入proc条目,我们就可以使用读取功能从proc条目读取数据,即使用copy_to_user函数将数据传输到用户空间。
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset){printk(KERN_INFO "proc file read.....\n");if(len)len=0;else{len=1;return 0;}copy_to_user(buffer,etx_array,20);return length;;}
删除过程条目
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
代码
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/kdev_t.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/slab.h> //kmalloc()#include <linux/uaccess.h> //copy_to/from_user()#include <linux/ioctl.h>#include <linux/proc_fs.h>#define WR_VALUE _IOW('a', 'a', int32_t *)#define RD_VALUE _IOR('a', 'b', int32_t *)int32_t value = 0;char etx_array[20] = "try_proc_array\n";static int len = 1;dev_t dev = 0;static struct class *dev_class;static struct cdev etx_cdev;static int __init etx_driver_init(void);static void __exit etx_driver_exit(void);/*************** Driver Functions **********************/static int etx_open(struct inode *inode, struct file *file);static int etx_release(struct inode *inode, struct file *file);static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);/***************** Procfs Functions *******************/static int open_proc(struct inode *inode, struct file *file);static int release_proc(struct inode *inode, struct file *file);static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length, loff_t *offset);static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t *off);static struct file_operations fops ={.owner = THIS_MODULE,.read = etx_read,.write = etx_write,.open = etx_open,.unlocked_ioctl = etx_ioctl,.release = etx_release,};static struct file_operations proc_fops = {.open = open_proc,.read = read_proc,.write = write_proc,.release = release_proc};static int open_proc(struct inode *inode, struct file *file){printk(KERN_INFO "proc file opend.....\t");return 0;}static int release_proc(struct inode *inode, struct file *file){printk(KERN_INFO "proc file released.....\n");return 0;}static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length, loff_t *offset){int ret = 0x00;printk(KERN_INFO "proc file read.....\n");if (len)len = 0;else{len = 1;return 0;}ret = copy_to_user(buffer, etx_array, 20);(void)ret;return length;;}static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t *off){int ret = 0x00;int maxlen = sizeof(etx_array) / sizeof(etx_array[0]);int length = len;if (length > maxlen)length = maxlen;ret = copy_from_user(etx_array, buff, length);etx_array[length] = '\0';// printk(KERN_INFO "proc file write....., %s,%d byte\n", etx_array, length);printk(KERN_INFO "proc file write...\n");(void)ret;return len;}static int etx_open(struct inode *inode, struct file *file){printk(KERN_INFO "Device File Opened...!!!\n");return 0;}static int etx_release(struct inode *inode, struct file *file){printk(KERN_INFO "Device File Closed...!!!\n");return 0;}static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off){int ret = 0x00;printk(KERN_INFO "Readfunction\n");ret = copy_to_user(buf, etx_array, sizeof(etx_array) / sizeof(etx_array[0]));return len;}static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off){printk(KERN_INFO "Write Function\n");return 0x0;}static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg){int ret = 0x00;switch (cmd){case WR_VALUE:ret = copy_from_user(&value, (int32_t *)arg, sizeof(value));printk(KERN_INFO "Value = %d\n", value);break;case RD_VALUE:ret = copy_to_user((int32_t *)arg, &value, sizeof(value));break;}(void)ret;return 0;}static int __init etx_driver_init(void){/*Allocating Major number*/if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0){printk(KERN_INFO "Cannot allocate major number\n");return -1;}printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));/*Creating cdev structure*/cdev_init(&etx_cdev, &fops);/*Adding character device to the system*/if ((cdev_add(&etx_cdev, dev, 1)) < 0){printk(KERN_INFO "Cannot add the device to the system\n");goto r_class;}/*Creating struct class*/if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL){printk(KERN_INFO "Cannot create the struct class\n");goto r_class;}/*Creating device*/if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL){printk(KERN_INFO "Cannot create the Device 1\n");goto r_device;}/*Creating Proc entry*/proc_create("etx_proc", 0666, NULL, &proc_fops);printk(KERN_INFO "Device Driver Insert...Done!!!\n");return 0;r_device:class_destroy(dev_class);r_class:unregister_chrdev_region(dev, 1);return -1;}void __exit etx_driver_exit(void){remove_proc_entry("etx_proc", NULL);device_destroy(dev_class, dev);class_destroy(dev_class);cdev_del(&etx_cdev);unregister_chrdev_region(dev, 1);printk(KERN_INFO "Device Driver Remove...Done!!!\n");}module_init(etx_driver_init);module_exit(etx_driver_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");MODULE_DESCRIPTION("A Sample Profs Demo");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 ```
