(相关资料图)
linux操作系统把虚拟地址分为用户空间和内核空间,内核空间可以通过procfs把内核的数据呈现给用户空间,用户空间也可以把数据写入到内核从而更改内核的行为,这在驱动中很常见,最终目的就是app就能通过读写procfs的文件和内核交互。
procfs是基于内存的文件系统,意味着掉电就会丢失,因此只能更改运行的行为和查看运行时的状态,一般都是用来查看动态的数据,大多数是只读的,当然这个可以设置。
procfs存在于系统中/proc目录中,可以通过mount 查看
mount...proc on /proc type proc (rw,relatime)...
/proc/devices
已经注册了的字符设备和块设备的住设备号/proc/iomem
系统能感知到的物理地址和总线设备地址,会包含外设的地址/proc/ioports
I/O空间的地址,ARM中没有IO空间,因此是X86架构使用/proc/interrupts
已经注册了的中断的信息/proc/softirqs
已经注册了的softirq/proc/swaps
当前有效的swaps/proc/kallsyms
运行时的内核的符号,包括已经加载驱动的符号/proc/partitions
当前已经连接的块设备和它们的分区/proc/partitions
当前内核可以识别的文件系统/proc/cpuinfo
cpu信息使用这个API来创建一个proc目录:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
name :在创建目录的名字parent:在哪个目录下创建目录,如果传入NULL,则在/proc下创建返回一个表示你要创建的目录的对象proc_dir_entry ,一个proc_dir_entry 表示一个proc目录或者一个proc文件。
使用这个API来创建一个文件:
static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops)
name 要创建文件的名字mode :此文件的默认权限parent : 要在哪个目录下创建文件,如果为NULL ,则在/proc下创建proc_ops :此文件的操作集合struct proc_ops类似于设备驱动中的文件操作集合,也就是open /read那些,在这里面实现读取,控制逻辑。
#include < linux/kernel.h >#include < linux/init.h >#include < linux/module.h >#include< linux/proc_fs.h >static struct proc_dir_entry *parent;static char etx_array[100] = "justice hello\\n";static int len =1;static int open_proc(struct inode *inode, struct file *file){ pr_info("proc file opend.....\\t"); return 0;}static int release_proc(struct inode *inode, struct file *file){ pr_info("proc file released.....\\n"); return 0;}static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset){ pr_info("proc file read.....\\n"); printk("offset (%d),length (%d)\\n",*offset,length ); if(*offset >= 100) { pr_info("file end!\\n"); return 0; } if(length > 100 - *offset) length = 100 - *offset; *offset += length; if(copy_to_user(buffer,etx_array,100) ) { pr_err("Data Send : Err!\\n"); } pr_info("read end\\n"); return length;}static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off){ pr_info("proc file wrote.....\\n"); memset(etx_array, 0, 100); if( copy_from_user(etx_array,buff,len) ) { pr_err("Data Write : Err!\\n"); } return len;}const struct proc_ops proc_ops = { .proc_open = open_proc, .proc_read = read_proc, .proc_write = write_proc, .proc_release = release_proc,}; static int __init procfs_init(void){ parent = proc_mkdir("procfs-test", NULL); if( parent == NULL ) { pr_info("Error creating proc entry"); return -EINVAL; } proc_create("lzy", 0666, parent, &proc_ops); return 0;}static void __exit procfs_exit(void){ proc_remove(parent);}module_init(procfs_init);module_exit(procfs_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("lzy");MODULE_DESCRIPTION("Simple Linux device driver (procfs)");MODULE_VERSION("1.6");
在这个例子中,通过读写/proc/procfs-test/lzy文件来读写字符串数字etx_array的内容,要注意的是,proc_ops .proc_read 需要小心处理传入的length和offset。
上层的app,比如cat工具都这个文件的话,length就是传入了4096字节,远远大于我们的数组内容,需要处理何时返回0,意味着本文件已经读完了,cat 的设计就是把文件读完,如果返回的值一直不为0的话,cat程序就会一直读一直读没有停止的时候。
Copyright © 2015-2022 南极快报网版权所有 备案号:粤ICP备2022077823号-13 联系邮箱: 317 493 128@qq.com