全部博文(218)
分类: LINUX
2008-03-01 19:14:33
个人用的Linux版本为:FC6/Linux,内核版本为:
1.获得Linux内核的源代码,即构建LDD3(Linux Device Drivers 3rd)上面所说的内核树。
如果安装的Linux系统中已经自带了源代码的话,应该在/usr/src目录下。如果该
目录为空的话,则需要自己手动下载源代码。下载代码的方法和链接很多,也可以在上通
过去下载。不过,下载的内
核版本最好和所运行的Linux系统的内核版本一致。当然,也可以比Linux系统内核的版
本低,但高的话应该不行(个人尚未实践)。
2.下载完成后,安装在/usr/src下,文件名为:
# tar jxvf
解压后生成一个新的目录/usr/src/
注:该目录会因内核版本的不同而不同,各位动手实践的朋友只需知道自己的源代码所在的具体位置即可。
3.稍微更改一下Makefile:
每个内核的名字都包含了它的版本号,这也是 uname -r 命令显示的值。内核Makefile 的前四行定义了内核的名字。为了保护官方的内核不被破坏,Makefile
经过了修改,以生成一个与运行中的内核不同的名字。在一个模块插入运行中的内核前,这个模块必须针对运行中的内核进行编译。为此,您必须编辑内核的
Makefile。
例如,如果 uname -r 返回字符串
EXTRAVERSION = -prep
修改为:
EXTRAVERSION = -1.2798.fc6
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 18
也就是最后一个连字符后面的所有内容。
4.配置及编译内核。
进入/usr/src/
一般情况下,需要先用命令诸如"make menuconfig", "make xconfig"或者"make oldcofig"对内核进行配置,这几个都是对内核进行配置的命令,只是它们运行的环境不一样,执行一下这几个命令中的任何一个即可对内核进行配置: make menuconfig是基于界面的内核配置方法,make xconfig应该是基于QT库的,还有make gcofig也是基于图形的配置方法,应该是需要GTK的环境,make oldcofig就是对内核树原有的.config文件进行配置一下即可。
其实内核的配置部分,主要是保证内核启动模块可动态加载的配置,默认配置里面应该已经包含了这样的内容,因此,我用的是make menuconfig.
注意:
您的内核必须已经启用这些选项进行了编译,用以支持模块的动态加载。
(用make menuconfig调出内核配置菜单):
Loadable module support --->
[*] Enable loadable module support
[*] Module unloading
[ ] Module versioning support (EXPERIMENTAL)
[*] Automatic kernel module loading
注:该步没做时,在make modules时将出错。
Kernel Feautre -> Preemptible Kernel
[*]
注:该项为内核抢占式调度设置, 必须保证在构建运行的内核与编译环境的内核时都选上,一般PC机运行的内核已经选上了,否则在insmod时将出现如下错误:
# insmod st7565p_driver26.ko
Using st7565p_driver26.ko
st7565p_driver26: version magic '
gcc-3.4'
insmod: cannot insert `st7565p_driver26.ko': Invalid module format (-1): Exec format error
在内核源码的目录下执行:
# make
# make bzImage 编译内核
其中,第一个make也可以不执行,直接make bzImage。这个过程可能比较长,因为是对整个内核重新编译了。执行结束后,可以看到在当前目录下生成了一个新的文件: vmlinux, 其属性为-rwxr-xr-x。
然后执行:
# touch * // 时间或时区设置,源代码的时间戳比本机的时间更新,否则产生:make[2]: 警告:检测到时钟错误。您的创建可能是不完整的。
# make modules 编译模块
# make modules_install 安装编译
对内核的所有模块进行编译和安装。完成“内核树”的安装:
执行结束之后,会在/lib/modules下生成新的目录/lib/modules/
5.编写模块文件及Makefile
以LDD3上的hello.c为例:
#include
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk("hello,world.\n");
return 0;
}
static void hello_exit(void)
{
printk("Good bye!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile如下:
obj-m := hello.o
#KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
上面的Makefile是这样确定内核源码树所在的目录的: 我们先到/lib/modules目录, 会看到一些以内核版本为名的目录, 目录中有一个build文件, 它是一个符号连接, 指向内核源码树. 那么如何确定进入哪个内核版本的目录呢? 这就可以通过 $ uname -r 来确定, 它指出了当前运行内核的版本.
上面的例子中只讨论了所有的代码在一个文件中的情况. 若代码分布在多个源文件中, 比如file1.c, file2.c, 生成hello.ko. 应该这样写Makefile:
obj-m := hello.o
hello-objs := file1.o file2.o
注意, 虽然我们的目的是生成.ko文件, 但在Makefile中写为.o!
hello.c和Makefile文件应该位于同一个目录下,可以放在/home下。
6.:编译和装载模块
在文件所处的目录下,执行:
# make
然后查看该目录下有哪些文件生成:可见,已经生成模块文件hello.ko.
hello.ko
hello.mod.c
hello.mod.o
hello.o
运行命令:
# insmod hello.ko
应该可以看到返回的信息:Hello, world
以通过lsmod来查看模块是否加载进内核
然后再运行命令:
# rmmod hello
应该可以看到返回的信息:Goodbye!
如果没看到,就是输出到系统的日志文件中去了,可以查看文件:
tail –f /var/log/messages
cat /var/log/syslog
应该有信息的输出。
以通过lsmod来查看该模块是否被卸载.