读和写方法都进行类似的任务, 就是, 从和到应用程序代码拷贝数据. 因此, 它们的原型 相当相似, 可以同时介绍它们:
ssize_t read(struct file *filp, char user *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char user *buff, size_t count, loff_t *offp);
对于 2 个方法, filp 是文件指针, count 是请求的传输数据大小. buff 参数指向持有被 写入数据的缓存, 或者放入新数据的空缓存. 最后, offp 是一个指针指向一个 "long offset type" 对象, 它指出用户正在存取的文件位置. 返回值是一个 "signed size type"; 它的使用在后面讨论.
让我们重复一下, read 和 write 方法的 buff 参数是用户空间指针. 因此, 它不能被内 核代码直接解引用. 这个限制有几个理由:
. 依赖于你的驱动运行的体系, 以及内核被如何配置的, 用户空间指针当运行于内核 模式可能根本是无效的. 可能没有那个地址的映射, 或者它可能指向一些其他的随 机数据.
就算这个指针在内核空间是同样的东西, 用户空间内存是分页的, 在做系统调用时 这个内存可能没有在 RAM 中. 试图直接引用用户空间内存可能产生一个页面错, 这 是内核代码不允许做的事情. 结果可能是一个 "oops", 导致进行系统调用的进程死 亡.
. 置疑中的指针由一个用户程序提供, 它可能是错误的或者恶意的. 如果你的驱动盲 目地解引用一个用户提供的指针, 它提供了一个打开的门路使用户空间程序存取或 覆盖系统任何地方的内存. 如果你不想负责你的用户的系统的安全危险, 你就不能 直接解引用用户空间指针.
显然, 你的驱动必须能够存取用户空间缓存以完成它的工作. 但是, 为安全起见这个存取 必须使用特殊的, 内核提供的函数. 我们介绍几个这样的函数 (定义于 <asm/uaccess.h>), 剩下的在第一章 "使用 ioctl 参数" 一节中. 它们使用一些特殊的, 依赖体系的技巧来确保 内核和用户空间的数据传输安全和正确.
scull 中的读写代码需要拷贝一整段数据到或者从用户地址空间. 这个能力由下列内核函 数提供, 它们拷贝一个任意的字节数组, 并且位于大部分读写实现的核心中.
unsigned long copy_to_user(void user *to,const void *from,unsigned long count); unsigned long copy_from_user(void *to,const void user *from,unsigned long count);
来源: http://www.bubuko.com/infodetail-3114191.html