树莓派的内核模块编程之Hello World

引言

树莓派所使用的操作系统是基于linux内核开发的,由于linux内核完全免费公开,因此我们可以修改树莓派的操作系统,实现对树莓派更深层次的掌控。本文主要介绍树莓派内核模块编程的基础知识,为以后的深入学习奠定基础。

一、什么是内核模块?

内核模块是可以在linux操作系统运行过程中,装载或卸载于linux内核的代码段。内核模块可以在不需要重启操作系统的情况下扩展linux内核的功能。最为典型的内核模块就是设备驱动器,这种内核模块主要实现的功能是控制与计算机系统相连接的硬件。

二、内核模块与应用程序区别

大多数小型或中型规模的应用程序均是按照代码指示一次性完成某个任务。而内核模块则需要先在内核中完成注册与初始化,目的是服务于未来的任务请求,当系统用户认为不需要该模块时,可以将其从内核中卸载。换句话说,每个内核模块都有一个初始化函数与卸载函数,初始化函数的功能是告诉linux内核“我在这里,我可以完成这些功能,用户有这方面请求可以让我来完成”。这种编程方式有点类似于事件驱动的编程方法。值得注意的是,并不是所有的应用程序是事件驱动的,但所有的内核模块均是事件驱动的。卸载函数的功能则是将内核模块从linux内核中卸载,这一点也是内核模块与应用程序的主要区别。应用程序完成相关功能后会自动关闭或退出,而内核模块则需要通过rmmod命令启动卸载函数从而关闭或退出。

三、Hello World内核模块

学习过编程的读者都知道,大多数编程教材都是以“Hello World”程序示例为开端,来说明程序代码的基本特征。虽然本文主要讲解的是内核模块,但仍会遵从编程教材惯例,以“Hello World”内核模块为示例说明内核模块的基本特征。

Hello World内核模块代码,即hello.c文件,如下图所示:

树莓派的内核模块编程之Hello World

上述代码前三行是添加内核模块所需的三个宏文件。随后hello_init函数与hello_exit函数是内核模块初始化与卸载函数。在2.3.13版本的linux内核以前,内核模块的初始化函数与卸载函数必须分别使用init_module与cleanup_module作为函数名。从2.3.13版本的linux内核以后,可以自定义初始化函数与卸载函数的函数名,但同时必须使用module_init与module_exit指定初始化函数与卸载函数,如上图16与17行所示。

细心的读者会发现上述代码使用了printk函数来输出字符串,而不是printf。这是由于基于linux内核的操作系统分为内核空间与用户空间,printf是由标准C库函数所定义的输出函数,而标准C库函数运行于用户空间,同时又由于内核空间与用户空间不能直接通信,因此运行于内核空间的内核模块不能使用标准C库函数,也就不能使用printf函数,所以linux内核需要自己的输出函数printk。printk函数中的KERN_ALERT是优先级信息,printk函数的优先级一共有个8种,分别是KERN_EMERG、KERN_ALERT、KERN_CRIT、KERN_ERR、KERN_WARNING、KERN_NOTICE、KERN_INFO与KERN_DEBUG。KERN_EMERG优先级最高,该优先级下的信息会直接显示在终端中,其他优先级信息需要通过dmesg命令查看。如果printk函数中没有指定优先级,则会默认使用kernel/printk.c文件中DEFAULT_MESSAGE_LOGLEVEL定义的优先级。

上述代码最后三行说明了该模块的相关信息,分别是模块许可证信息、作者信息与模块描述信息,这些信息并不是强制要求的,但如果缺少MODULE_LICENSE信息则会在编译模块的过程中给出警告,有时也会报错。linux内核认可的模块许可证包括“GPL”、“GPL and additional rights”、“Dual BSD/GPL”与“Proprietary”。

除了hello.c文件外,内核模块的编译还需要Makefile文件,该文件代码如下图:

树莓派的内核模块编程之Hello World

上述代码中,obj-m表示把文件hello.o作为内核模块进行编译,不要编译到内核中,同时还会生成一个"hello.ko"文件。make -c指明了内核源码的所在目录,树莓派官方系统通常不包含内核源码,因此需要使用sudo apt-get install raspberrypi-kernel-headers命令来下载,该命令会在/usr/src/目录下保存树莓派系统的内核源码。安装与卸载内核模块分别使用insmod与rmmod命令,为了操作方便,我们将这两个命令写在Makefile文件中。

将hello.c与Makefile两个文件保存在同一个文件夹下,在终端分别输入sudo make、sudo make install与sudo make uninstall命令来编译、安装与卸载内核模块,命令效果如下图:

树莓派的内核模块编程之Hello World

随后我们还可以输入dmesg | grep “world”命令查看内核模块输出的信息,效果如下图:

树莓派的内核模块编程之Hello World

至此,内核模块的基本特征已说明完毕,如有建议与疑问欢迎交流。


分享到:


相關文章: