一:linux内核裁剪:
1:编译内核源码:
今天的重点内容是内核驱动的编写,在编写驱动之前首先的了解linux内核源码,linux主要是由五个子系统组成:进程调度,内存管理,文件系统,网络接口以及进程间通信;下面是解压的linux内核源码文件:
下面对linux内核里面的文件进行简单的说明:
arch目录中包含于体系结构有关的子目录和文件,arm的相关平台信息在arch/arm目录下。
scripts目录中存放着对核心配置的脚本文件。
crypto目录中包含着常见的加密算法。
drivers目录包含各种各样的驱动,包括字符型,快型,网络设备驱动程序。
fs目录中包括了linux系统所支持的文件系统类型,比如ext4 nfs
init目录中存放着与linux内核相关的启动代码。
kernel目录中包含许多linux进程调度子系统相关的源代码。
lib目录存放linux内核所用的库文件。
mm目录存放linux内存管理的源代码。
net目录存放有关网络协议的源代码。
编译linux内核源码,最重要的是Makefile,在linux内核中每个文件都有一个Makefile,统一由最外层的Makefile来调用:Makefile这个文件中包含了许多linux内核配置的信息,我们Linux内核要编译的平台,交叉编译器的选择(如下图),编译链接Linux内核的参数;
由于linux源代码非常庞大,我们找起来非常困难;在编译linux之前先介绍一个管理工具ctags
在linux源码中我们使用命令[root@192 linux-3.5]# ctags -R ./
等它执行完毕(要几分钟),我们可以用vim任意打开一个文件,在命令模式下输入:ta <需要找的函数名>回车就可以了
2:linux源码编译
下面是linux源码编译步骤:
(1)在编译之前首先使用make clean, make distclean清除原编译和配置文件
(2)找到运行平台(arm)下面的配置文件拷贝到源码目录一命名为 .config,.config文件是在进行内核配置的时候,经过配置后生成的内核编译参考文件,命令如下
[root@192 linux-3.5]# cp arch/arm/configs/exynos4_defconfig .config
(3)拷贝完成之后就可以运行make命令,这个过程要等很久:
[root@192 linux-3.5]#make
(4)编译完成之后就会在arch/armboot目录下生成zImage,生成的这个文件就是linux镜像
[root@192 linux-3.5]# arch/arm/boot/zImage
之后我们就可以使用linux的镜像文件了
(2):linux内核裁剪
以上编译的是没有裁剪过linux源码,如果我们不想使用源码里面的部分功能,我们就可以通过裁剪的方式阻止它编译:在linux源码包中我们可以使用make menuconfig,图形化界面很容易操作;就可以进行linux的源码的裁剪:
(1)首先在源码包中运行make menuconfig这个命令
如果不想使用它的某些功能,取消前面*即可,按空格键来控制选择
(2)保存退出,执行make
二:编译可加载模块
内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块,模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。
总之,模块是一个为内核(从某种意义上来说,内核也是一个模块)或其他内核模块提供使用功能的代码块。
Linux内核模块是一种可被动态加载和卸载的可执行程序。通过内核模块可以扩展内核功能,内核模块通常用于设备驱动、文件系统等。如果没有内核模块,需要向内核添加功能就需要自发代码、重新编译内核、安装新内核等步骤;
下面我们实现一个简单的linux模块:
1 #include <linux/init.h>
2 #include <linux/module.h>
3
4 MODULE_LICENSE("GPL");//指定GPL协议
5 MODULE_AUTHOR("BUNFLY");
6
7 int bunfly_init()
8 {
9 printk("this is bunfly_init\n");
10
11 return 0;
12 }
13
14 void bunfly_exit()
15 {
16 printk("this is bunfly_exit\n");
17 }
18
19 module_init(bunfly_init);
20 module_exit(bunfly_exit);
需要注意的是:编写模块函数时,声明模块的授权协议,如果没有的话,编译器有警告的,如果在模块函数中调用的设备驱动模型的代码,就必须要指定为GPL协议,否则是不能加载到内核中,在linux内核中输出函数不再是printf(), 而是用的是printk();printk相当于printf的孪生姐妹,她们一个运行在用户态,另一个则在内核态。
模块是动态加载内核中,是内核的一部分,它没有main函数,因此在编译的时候我们要需调用内核中的Makefile来编译模块;下面是Makefile文件内容:
1 all:
2 make -C /home/bunfly/source_code/linux-3.5 M=`pwd`
3
4 clean:
5 make -C /home/bunfly/source_code/linux-3.5 M=`pwd` clean
6
7
8 obj-m += bunfly.o
在编辑Makefile的时候我们需要注意的是代码第8行:它分为三种模式:
(1)obj-不编入内核
(2)obj -y编入内核
(3)obj-m编译成模块
如果要将自己的模块写到make menuconfig菜单中去,就要用到另一个配置文件Kconfig,在Linux 内核源码树的每个目录下都有两个文档Kconfig和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个 Kconfig分别描述了所属目录源文档相关的内核配置菜单。在执行内核配置make menuconfig时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文档中。在内核编译时,主Makefile调用这 个.config,就知道了用户的选择。这个内容说明了,Kconfig就是对应着内核的每级配置菜单。