红联Linux门户
Linux帮助

64位Ubuntu14.04系统下加载内核模块hello world

发布时间:2017-05-07 11:09:57来源:linux网站作者:Lucien_zhou
1.感谢这篇文章,让折腾了好久的我实现了内核模块加载
64位Ubuntu14.04系统下加载内核模块hello world
 
2.为什么要构造源码树?
我们做 Linux 开发一般是在PC机上编译好,下到板子上去运行,板子上的 Linux 内核和 PC 机上的 Linux 版本很多时候都是不一样的,比如:pc机上的是 Linux 2.6,板子上的系统是 Linux 3.1,这个时候就要在pc本地编译环境中下载 Linux 3.1 的内核,用它编译出驱动模块,从而在板子上加载,不然会因为内核版本不一致而出错。如果只是在PC上运行,内核模块不是用在板子上去,是不用下载内核源码树和编译内核源码的。
 
3.驱动程序和用户程序不一样,它是作为一个模块连接到内核模块来运行的,运行在内核空间里面。所以要运行我们自己构造的模块,需要自己的系统已经配置好内核树,然后把目标模块和内核树连接起来运行!
如何查看自己的 ubuntu 系统中是否已经有了内核源码树了?直接去查看 /lib/modules/ 目录下是否存在 build 目录,如果存在,则表示我们自己的系统已经拥有内核源码树了(我的本地编译环境 ubuntu14.04 是拥有内核源码树的),如下所示。
64位Ubuntu14.04系统下加载内核模块hello world
 
4.但为了熟悉整个的过程,我们也重新下载对应自己的编译环境的“内核源码”并对其进行编译,构造内核源码树。首先要查看自己使用的系统“内核版本 ”:
我用的是 Ubuntu 14.04
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
查看自己 ubuntu 系统的版本:有两种方法,第一种,cat /etc/issue ; 第二种,lsb_release -a 命令
64位Ubuntu14.04系统下加载内核模块hello world
 
5.内核源码树构建步骤:
64位Ubuntu14.04系统下加载内核模块hello world
(1)安装编译内核所需的软件(要用 make menuconfig 命令的话得安装,用 make oldconfig 的话就不用安装,不论采用哪种生成配置文件的方式,都在系统中安装下面的软件)
sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot
(2)下载内核源码,执行上面的命令 sudo apt-cache search Linux-source ,系统会给出适合我们所安装系统的“内核源码版本 ”
64位Ubuntu14.04系统下加载内核模块hello world
(3)使用命令 sudo apt-get install linux-source-3.13.0 下载安装该“内核源码 ”
(4)解压内核源码包:进入 /usr/src/ 目录,能找到 linux-source-3.13.0.tar.bz2 文件,用解压命令 sudo tar xjvf linux-source-3.13.0.tar.bz2  解压。要注意上面目录下的 linux-source-3.13.0.tar.bz2 文件并不是软件压缩包文件,而是一个软链接,不能直接使用 tar 进行解压。
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
进入 linux-source-3.13.0 文件夹,发现真正的 tar 源码压缩包,解压。
64位Ubuntu14.04系统下加载内核模块hello world
(5)对“内核源码”进行编译前的配置从下面截图可以看出,在解压后,该文件夹下并没有 .config 文件。
64位Ubuntu14.04系统下加载内核模块hello world
进入源码解压后的文件夹里,为了方便,可以直接在使用 make menuconfig 命令打开可视化配置窗口,然后什么都不要修改的退出。
64位Ubuntu14.04系统下加载内核模块hello world
在运行完 sudo make menuconfig 命令后并不会像上面那样执行完毕,生成一个 .config  文件,而是会先打开下面的可视化配置,毕竟我们的命令是 menuconfig(菜单配置)。
64位Ubuntu14.04系统下加载内核模块hello world
什么都不要操作,直接 Esc 退出,选择 Save,从而可以在该文件夹下生成一个 .config 编译配置文件。
64位Ubuntu14.04系统下加载内核模块hello world
.config 配置文件如下图所示:
64位Ubuntu14.04系统下加载内核模块hello world
(6)使用 sudo make 命令进行内核编译,当然不只是下面截图那样简单,整个内核编译过程是以小时计算的,编译吧,linux君,我玩会再来看你。
64位Ubuntu14.04系统下加载内核模块hello world
编译完,该文件夹下就生成了一个名为 vmlinux 的文件了,但网上的教程大都说要执行完下面的 sudo make bzImage 命令才会生成 vmlinux 文件。
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
(7)sudo make zImage 命令在我的本地编译环境下是不能使用的。
64位Ubuntu14.04系统下加载内核模块hello world
(8)使用命令 sudo make bzImage 后,下面两个截图对其过程的中间过程省略。
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
(9)使用 sudo make modules 命令编译模块
(10)使用 sudo make modules_install 命令安装模块,执行完后,会在 /lib/modules 目录下生成一个新的目录 /lib/modules/3.13.0/ 。至此,内核就编译完成了。
64位Ubuntu14.04系统下加载内核模块hello world
(11)由于我的本地 ubuntu 编译环境中的内核版本就是为 3.13.0-32-generic,所以 /lib/modules/3.13.0-24-generic 本身就存在,所以其实我们这里的 sudo make modules 和 sudo make modules_install 这两步是不需要执行的。
64位Ubuntu14.04系统下加载内核模块hello world
(12)但我们这里还是执行了 sudo make modules 和 sudo make modules_install 命令,看上面的截图也就能判断出,其实,在我们执行完 sudo make moduels 和 sudo make modules_install 命令后编译生成了目录 /lib/modules/3.13.11-ckt39 
 
6.现在可以编写 hello world 程序并加载该内核模块了
下面是 hello.c 文件:
64位Ubuntu14.04系统下加载内核模块hello world
 
7.下面是是 Makefile (必须为这个文件名,连 makefile 都是不能直接使用 make 命令来进行编译的)文件,解释下该文件,加深理解。
(1)obj-m 的意思是将后面的东东编译为“内核模块”,相对应的还有 obj-y 是编译进内核,obj-n 是不编译。
(2)KERNELDIR 是 Makefile 文件中的一个内容标识,这里标识内核源码目录,目录中包含了内核驱动模块所需要的各种头文件及依赖。
(3)-C 表示让 make 命令进入指定的目录,这里即 KERNELDIR ,是内核源代码目录,调用该目录顶层下的 Makefile,目标为 modules。
(4)M=$(PWD) 选项是让该 Makefile 在构造 modules 目标之前返回到模块源代码目录,并在当前目录下生成 obj-m 指定的 xxx.o 目标模块。
(5)三种赋值等号的区别 ?= ,=,:=
“:=”表示:它的右边如果为变量,那么该变量在这条语句之前就要定义好,而不能在使用这条语句之后定义的变量
“=”表示:当它右边如果变量时,这个变量可以在这条语句之前或者之后使用
“?=”表示:当它左边的变量在这条语句之前没有定义过,则执行本条语句,如果已经定义了,则什么都不做。
所以下面截图中的 Makefile 文件中三种赋值都是可以的。
(6)modules 和 modules_install 是 make 需要执行的命令
(7)整理到这里,请继续先阅读:
64位Ubuntu14.04系统下加载内核模块hello world
64位Ubuntu14.04系统下加载内核模块hello world
(8)make 定义了很多默认变量,像常用的命令或者是命令选项之类的,什么 CC ,什么 CFLAGS,$(MAKE) 就是预设的 make 这个命令的名称(或者是路径)。make -p 可以查看所有预定义的变量的当前值。看下面的截图的最后一行就可以看出, $(MAKE) 变量其实就是 make 命令。
64位Ubuntu14.04系统下加载内核模块hello world
 
8.对驱动程序进行编译的时候,发现 /lib/modules/ 目录下的两个库文件夹都是能用的(在前面说过,其实安装好的 ubuntu本地编译环境是拥有内核源码树的)。
(1)在写好 Makefile 文件的驱动程序目录下,可以直接使用用户权限执行 make 命令编译。
(2)CC是编译
(3)LD是链接
64位Ubuntu14.04系统下加载内核模块hello world
 
本文永久更新地址:http://www.linuxdiyf.com/linux/30594.html