"); //-->
第14章 内核空间与用户空间数据交互实验
在“第12章 字符设备驱动框架实验”中,已经对file_operations结构体的进行了填充,该结构体的每一个成员都对应着一个系统调用,例如read、write等,在对应的实验中,只是对调用函数进行了标志打印,并没有真正实现设备的读写功能,而在本章节将对内核空间与用户空间的数据交换功能进行实现。
14.1 内核空间与用户空间
Linux系统将可访问的内存空间分为了两个部分,一部分是内核空间,一部分是用户空间。操作系统和驱动程序运行在内核空间(内核态),应用程序运行在用户空间(用户态)。
那么为什么要区分用户空间和内核空间呢?
(1)内核空间中的代码控制了硬件资源,用户空间中的代码只能通过内核暴露的系统调用接口来使用系统中的硬件资源,这样的设计可以保证操作系统自身的安全性和稳定性。
(2)从另一方面来说,内核空间的代码更偏向于系统管理,而用户空间中的代码更偏重业务逻辑实现,俩者的分工不同。
硬件资源管理都是在内核空间完成的,应用程序无法直接对硬件进行操作,只能通过调用相应的内核接口来完成相应的操作。比如应用程序要对磁盘上的一个文件进行读取,应用程序可以向内核发起一个“系统调用”申请——我要读取磁盘上的文件。这个过程其实是通过一个特殊的指令让进程从用户态进入到了内核态。在内核空间中,CPU可以执行任何命令,包括从磁盘上读取数据,具体过程是先把数据读取到内核空间中,然后再把数据拷贝到用户空间并从内核态切换到用户态。此时应用程序已经从系统调用中返回并拿到了想要的数据,可以继续往下执行了。
进程只有从用户空间切换到内核空间才可以使用系统的硬件资源,切换的方式有三种:系统调用,软中断,硬中断,如下图(图 14-1)所示:
14.2 用户空间和内核空间数据交换
内核空间和用户空间的内存是不能互相访问的。但是很多应用程序都需要和内核进行数据的交换,例如应用程序使用read函数从驱动中读取数据,使用write函数向驱动中写数据,上述功能就需要使用copy_from_user和copy_to_user俩个函数来完成。copy_from_user函数是将用户空间的数据拷贝到内核空间。copy_to_user函数是将内核空间的数据拷贝到用户空间。
这俩个函数定义在了kernel/include/linux/uaccess.h文件下,如下所示:
copy_to_user
函数原型:
unsigned long copy_to_user_inatomic(void __user *to, const void
*from, unsigned long n);
函数作用:
把内核空间的数据复制到用户空间。
参数含义:
*to是用户空间的指针
*from是内核空间的指针
n是从内核空间向用户空间拷贝的字节数
copy_from_user
函数原型:
unsigned long copy_from_user(void *to, const void __user *from,
unsigned long n)
函数作用:
把用户空间的数据复制到内核空间。
参数含义:
*to是内核空间的指针
*from是用户空间的指针
n是从用户空间向内核空间拷贝的字节数
14.3 实验程序编写
14.3.1 驱动程序编写
本驱动程序对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\09\module。
在该实验中将实现内核空间和用户空间进行数据交换的功能。以12章编写的字符设备驱动框架实验为基础编写驱动程序,程序使用copy_to_user函数和copy_from_user函数来实现内核空间和用户空间互传数据的功能,编写完成的file.c代码如下所示:
以上代码在cdev_test_read函数中使用copy_to_user函数将内核数据拷贝到用户空间,在cdev_test_write函数中使用copy_from_user函数将用户空间数据拷贝到内核空间。
14.3.2 编写测试 APP
本应用程序对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\09\app。
编写测试APP其实是在编写Linux应用,编译完成的应用程序app.c代码如下所示:
14.4 运行测试
14.4.1 编译驱动程序
在上一小节中的file.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下 所示:
对于Makefile的内容注释已在上图添加,保存退出之后,来到存放file.c和Makefile文件目录下,如下图(图14-2)所示:
然后使用命令“make”进行驱动的编译,编译完成如下图(图14-3)所示:
编译完生成 file.ko目标文件,如下图(图 14-4)所示:
至此我们的驱动模块就编译成功了,下面进行应用程序编译.
下面进行驱动程序的测试。
输入以下命令运行应用程序,如下图(图 14-7)所示
由上图可知,打印“This is cdev_test_open”信息说明成功打开了字符设备驱动。
打印“ This is cdev_test_read”和“buf1 is This is cdev_test_read!”说明应用程序成功读取到内核的数据。
打印“This is cdev_test_write”和“kbuf is nihao”说明应用程序向内核写数据成功。
最后打印“This is cdev_test_release”说明卸载字符设备。
更多内容可以了解迅为RK3568开发板
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。