简介
操作系统将虚拟内存分为内核空间和用户空间。内核空间严格保留用于运行内核,内核扩展和大多数设备驱动程序。相反,用户空间是所有用户模式应用程序都在其中工作的存储区,并且可以在必要时将该存储区换出。
在用户空间和内核空间之间进行通信的方法有很多
Procfs in Linux
/proc 文件是procfs(进程文件系统)的挂载点,该文件是内存中的文件系统。许多进程在此虚拟文件系统上存储有关自身的信息。ProcFS还存储其他系统信息。用户空间程序可以使用proc文件来读取内核导出的信息。proc文件系统中的每个条目都提供了一些来自内核的信息。
cat /proc/meminfo
cat /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 = 4
PATCHLEVEL = 19
SUBLEVEL = 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条目,上述功能将定义如下,
```c
proc_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 ```