Linux内核设备驱动之字符设备驱动笔记整理

2019-01-16 20:44:33王振洲

(8)和用户空间交换数据

read和write中的__user *buff 是用户空间的指针,内核不能直接引用其中的内容(也就是不能直接对buff进行取值操作),需要通过内核提供的函数进行数据拷贝。其原因是:

a.在不同架构下,在内核模式中运行时,用户空间的指针可能是无效的。 b.用户空间的内存是分页的,系统调用执行时,buff指向的内存可能根本不在RAM中(被交换到磁盘中了) c.这可能是个无效或者恶意指针(比如指向内核空间)

内核和用户空间交换数据的函数见<asm/uaccess.h>

如:

1. unsigned long copy_to_user(
      void __user *to, 
      const void *from, 
      unsigned long count);
//向用户空间拷贝数据

2. unsigned long copy_from_user(
      void *to, 
      const void __user *from, 
      unsigned long count);
//从用户空间获得数据

3. int put_user(datum, ptr)
//向用户空间拷贝数据。字节数由sizeof(*ptr)决定
//返回值为0成功,为负错误。

4. int get_user(local, ptr);
//从用户空间获得数据。字节数由sizeof(*ptr)决定
//返回值和local都是从用户空间获得的数据

任何访问用户空间的函数都必须是可睡眠的,这些函数需要可重入。

copy_to_user等函数如果返回值不等于0,则read或write应向用户空间返回-EFAULT

主设备号用来表示设备驱动, 次设备号表示使用该驱动的设备

在内核dev_t 表示设备号, 设备号由主设备号和次设备号组成

#include <linux/kdev_t.h> #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) //根据设备号获取主设备号 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) //获取次设备号 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) //根据指定的主设备和次设备号生成设备号 #include <linux/fs.h> //静态:申请指定的设备号, from指设备号, count指使用该驱动有多少个设备(次设备号), 设备名 int register_chrdev_region(dev_t from, unsigned count, const char *name); //name的长度不能超过64字节 //动态申请设备号, 由内核分配没有使用的主设备号, 分配好的设备存在dev, baseminor指次设备号从多少开始, count指设备数, name设备名 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) //释放设备号, from指设备号, count指设备数 void unregister_chrdev_region(dev_t from, unsigned count) //cat /proc/devices 可查看设备使用情况 在内核源码的documentations/devices.txt可查看设备号的静态分配情况 ///内核里使用struct cdev来描述一个字符设备驱动 #include <linux/cdev.h> struct cdev { struct kobject kobj; //内核用于管理字符设备驱动 struct module *owner; //通常设为THIS_MODULE, 用于防止驱动在使用中时卸载驱动模块 const struct file_operations *ops; //怎样操作(vfs) struct list_head list; //因多个设备可以使用同一个驱动, 用链表来记录 dev_t dev; //设备号 unsigned int count; //设备数 };