linux内核编译与简易驱动

来源:互联网 发布:电磁仿真软件 feko 编辑:程序博客网 时间:2024/06/05 12:07

一、内核编译

我们常常因为升级内核或者其他原因编译内核源码。


(一)下载源码 

首先,我们需要一份内核的源码,虽然现在linux发布版本很多,但是内核总是一样的。

目前linux kernel发布在http://www.kernel.org中,我们去这里找到我们需要的版本的源代码。

下载源码的方法很多,我们这里直接在终端下通过wget命令下载。

在写本博文时,最新的稳定版本为kernel 3.17.4,我们使用该版本,该版本的下载链接为https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.17.4.tar.xz。

终端下输入命令:

# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.17.4.tar.xz

之后,开始下载源码。

下载完成后,解压该tar.xz文件。

# xz -d linux-3.17.4.tar.xz

以上命令可以把tar.xz格式转换为tar格式,生成linux-3.17.4.tar文件。

# tar -xvf linux-3.17.4.tar

通过两条命令解压完毕,生成了linux-3.17.4文件夹。

其实我们也可以直接一条命令解压缩tar.xz文件。

# tar -xvJf linux-3.17.4.tar.xz

这条命令一样可以达到效果。

一般来说内核源码都放在/usr/src路径下,我们将解压后的文件夹linux-3.17.4也移动到这个路径下。


(二)root权限

在后面的操作可能经常会遇到权限问题,为了方便,我们切换到root用户。

如果没有设置过root密码,先设置root用户的密码。

# sudo passwd

按提示输入密码。

然后切换到root用户。

# su root

按提示输入密码。


(三)编译配置

在编译前需要先安装必备的基础库。

# apt-get install build-essential

# apt-get install libncurses5-dev

安装好这两个基础库后,进入当前文件夹:

# cd /usr/src/linux-3.17.4

现在开始生成配置文件。在这之前最好执行:

# make mrproper

这个命令是删除所有的编译生成文件、内核配置文件(.config文件)和各种备份文件。

当然,一般刚下载的源码是不需要这个步骤。

生成.config配置文件:

# make menuconfig

进行相应配置后记得在最下面的Save处进行保存生存.config文件。

(四)编译内核

在/usr/src/linux-3.17.4路径下,输入命令:

# make

开始编译源代码,下面要做的就是等了,这个过程会比较长,要有一定耐心。

编译完成后,再编译内核模块:

# make modules

安装内核模块:

# make modules_install


(五)安装内核

之前的步骤已经编译完成了一个kernel,现在只差最后一步了,安装kernel:

# make install

然后重启,就可以使用新内核了:

# reboot

我们可以使用命令:

# uname -r

来查看当前kernel版本,可以在安装新内核前后分别输入以作对比。


二、简易驱动

我们完成一个打印hello world的简易驱动模块。


(一)驱动源码

我们将这个驱动命名为hello。

新建hello.c文件:

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>//模块初始化函数static int __int my_init(void){        printk(KERN_ALERT "Hello, my world!\n");        return 0;}//模块退出函数static void __exit my_exit(void){        printk(KERN_ALERT "My world exit!\n");}module_init(my_init);module_exit(my_exit);//模块的许可证声明MODULE_LICENSE("GPL");</span>

linux/init.h,包含了宏__init,__exit定义;

linux/modules.h,包含了加载模块时需要的符号和函数定义;

linux/kernel.h,包含了常用的内核函数;

my_init(void),加载函数,其中__init表示编译器相关函数或变量仅用于初始化。

my_exit(void),释放函数,其中__exit同理也是告诉编译器。

printk是内核中的输出函数。

KERN_ALERT是指消息的级别。

所有的消息级别:

#define KERN_EMERG     "<0>"

#define KERN_ALERT     "<1>"

#define KERN_CRIT      "<2>"

#define KERN_ERR       "<3>"

#define KERN_WARNING   "<4>"

#define KERN_NOTICE    "<5>"

#define KERN_INFO      "<6>"

#define KERN_DEBUG     "<7>"

这里用<1>和KERN_ALERT效果是一样的,当然也可以用其他的消息级别。

但是只有在消息级别高于控制台级别时,才会显示在控制台上。

module_init(my_init)是把我们写的初始化函数与模块初始化函数挂钩,也就是在加载模块时能够调用my_init(void)函数。

module_exit(my_exit)同上。

最后我们需要许可证声明,GPL是相应的规范。


(二)Makefile文件

新建Makefile文件:

obj-m:=hello.oPWD := $(shell pwd)KERNEL := /usr/src/linux-3.17.4all:        $(MAKE) -C $(KERNEL) M=$(PWD) modulesclean:        $(MAKE) -C $(KERNEL) M=$(PWD) clean

PWD是指当前路径。

KERNEL是指当前内核源码路径。

(三)编译模块

在当前路径下输入命令:

# make

编译完成后将生成hello.ko文件,这就是编译好的模块文件。

(四)加载模块

命令:

# insmod hello.ko

可以通过以下方式查看:

查看模块的详细信息:

# cat modules | grep hello

查看已加载的模块:

# lsmod

(五)卸载模块

命令:

#rmmod hello

(六)静态加载

以上加载模块方式是动态加载,那么我们怎么把模块内容编译进内核呢?

这时就用到了静态加载。

# cd /usr/src/linux-3.17.4/drivers

# mkdir hello

drivers文件夹下放置了各种驱动,我们在里面创建文件夹hello,表示hello这个驱动模块,把上面创建的hello.c移动该文件夹里。

创建Kconfig文件:

menuconfig HELLO        bool "CONFIG_HELLO"        default y

这里是给内核配置时(生成.config文件时)添加是否编译hello模块选项,bool值表示是否编译,后面是描述,最后一行默认了bool值为y,即默认编译hello模块。

创建Makefile文件:

obj-$(CONFIG_HELLO) += hello.o

CONFIG_HELLO值就是上面的bool值,这里是固定的“CONFIG_”加上menuconfig后面的“HELLO"。

这时该文件夹内有hello.c,Kconfig,Makefile三个文件。我们退回到drivers文件夹里:

# cd /usr/src/linux-3.17.4/drivers

这个文件夹里也有一个Kconfig文件和Make文件,分别进行编辑。

在Kconfig中添加

source "drivers/hello/Kconfig"

Makefile中添加

obj-$(CONFIG_HELLO) += hello/

这时我们重新生成配置文件。

# cd /usr/src/linux-3.17.4

# make menuconfig

点开Device Drivers

我们就会发现多了一项CONFIG_HELLO。

然后下面就可以编译了。

0 0
原创粉丝点击