编译前注意事项
由于我们的核心原本就有提供很多的核心工具给硬件开发商来使用, 而硬件开发商也需要针对核心 所提供的功能来设计他们的驱动程序模块,因此, 我们如果想要自行使用硬件开发商所提供的模块 来进行编译时,就需要使用到核心所提供的原始档当中, 所谓的头文件案 (header include file) 来取 得驱动模块所需要的一些函式库或标头的定义啦! 也因此我们常常会发现到,如果想要自行编译核心模块时,就得要拥有核心原始码嘛!
那核心原始码我们知道他是可能放置在 /usr/src/ 底下,早期的核心原始码被要求一定要放置到 /usr/src/linux/ 目录下,不过,如果你有多个核心在一个 Linux 系统当中,而且使用的原始码并不相 同时,所以,在 2.6 版以后,核心使用比较有趣的方法来设计他的原始码放置目录, 那就是以 /lib/modules/$(uname -r)/build 及 /lib/modules/$(uname -r)/source 这两个连结档来 指向正确的核心原始码放置目录。如果以我们刚刚由 kernel 3.10.89vbird 建立的核心模块来说, 那 么他的核心模块目录底下有什么咚咚?
[root@study ~]# ll -h /lib/modules/3.10.89vbird/
lrwxrwxrwx. 1 root root 30 Oct 20 14:27 build -> /usr/src/kernels/linux-3.10.89
drwxr-xr-x. 11 root root 4.0K Oct 20 14:29 kernel
-rw-r--r--. 1 root root 668K Oct 20 14:29 modules.alias
-rw-r--r--. 1 root root 649K Oct 20 14:29 modules.alias.bin
-rw-r--r--. 1 root root 5.8K Oct 20 14:27 modules.builtin
-rw-r--r--. 1 root root 7.5K Oct 20 14:29 modules.builtin.bin
-rw-r--r--. 1 root root 208K Oct 20 14:29 modules.dep
-rw-r--r--. 1 root root 301K Oct 20 14:29 modules.dep.bin
-rw-r--r--. 1 root root 316 Oct 20 14:29 modules.devname
-rw-r--r--. 1 root root 81K Oct 20 14:27 modules.order
-rw-r--r--. 1 root root 131 Oct 20 14:29 modules.softdep
-rw-r--r--. 1 root root 269K Oct 20 14:29 modules.symbols
-rw-r--r--. 1 root root 339K Oct 20 14:29 modules.symbols.bin
lrwxrwxrwx. 1 root root 30 Oct 20 14:27 source -> /usr/src/kernels/linux-3.10.89
单一模块编译
想象两个情况:
- 如果我的默认核心忘记加入某个功能,而且该功能可以编译成为模块,不过, 预设核心却也没有将该项功 能编译成为模块,害我不能使用时,该如何是好?
- 如果 Linux 核心原始码并没有某个硬件的驱动程序 (module) ,但是开发该硬件的厂商有提供给 Linux 使 用的驱动程序原始码,那么我又该如何将该项功能编进核心模块呢?
上面那两种情况的模块编译行为是不太 一样的,不过,都是需要 make, gcc 以及核心所提供的 include 头文件与函式库等等。
- 硬件开发商提供的额外模块
很多时候,可能由于核心默认的核心驱动模块所提供的功能你不满意,或者是硬件开发商所提供的核心模块具有更强大的功能, 又或者该硬件是新的,所以预设的核心并没有该硬件的驱动模块时,那 你只好自行由硬件开发商处取得驱动模块,然后自行编译啰!
举例来说,假设你将下载的文件放置到 /root/raidcard 目录内喔!
# 1. 将文件解压缩并且开始编译:
[root@study ~]# cd /root/raidcard
[root@study raidcard]# ll
-rw-r--r--. 1 root root 501477 Apr 23 07:42 RR64xl_Linux_Src_v1.3.9_15_03_07.tar.gz
[root@study raidcard]# tar -zxvf RR64xl_Linux_Src_v1.3.9_15_03_07.tar.gz
[root@study raidcard]# cd rr64xl-linux-src-v1.3.9/product/rr64xl/linux/
[root@study linux]# ll
-rw-r--r--. 1 dmtsai dmtsai 1043 Mar 7 2015 config.c
-rwxr-xr-x. 1 dmtsai dmtsai 395 Dec 27 2013 Makefile # 要有这家伙存在才行!
[root@study linux]# make
make[1]: Entering directory `/usr/src/kernels/linux-3.10.89'
CC [M] /root/raidcard/rr64xl-linux-src-v1.3.9/product/rr64xl/linux/.build/os_linux.o
CC [M] /root/raidcard/rr64xl-linux-src-v1.3.9/product/rr64xl/linux/.build/osm_linux.o
.....(中间省略).....
LD [M] /root/raidcard/rr64xl-linux-src-v1.3.9/product/rr64xl/linux/.build/rr640l.ko
make[1]: Leaving directory `/usr/src/kernels/linux-3.10.89'
[root@study linux]# ll
-rw-r--r--. 1 dmtsai dmtsai 1043 Mar 7 2015 config.c
-rwxr-xr-x. 1 dmtsai dmtsai 395 Dec 27 2013 Makefile
-rw-r--r--. 1 root root 1399896 Oct 21 00:59 rr640l.ko # 就是产生这家伙!
# 2. 将模块放置到正确的位置去!
[root@study linux]# cp rr640l.ko /lib/modules/3.10.89vbird/kernel/drivers/scsi/
[root@study linux]# depmod -a # 产生模块相依性文件!
[root@study linux]# grep rr640 /lib/modules/3.10.89vbird/modules.dep
kernel/drivers/scsi/rr640l.ko: # 确定模块有在相依性的配置文件中!
[root@study linux]# modprobe rr640l
modprobe: ERROR: could not insert 'rr640l': No such device
# 要测试加载一下才行,不过,我们实际上虚拟机没有这张 RAID card,所以出现错误是正常的啦!
# 3. 若开机过程中就得要加载此模块,则需要将模块放入 initramfs 才行喔! [root@study linux]# dracut --force -v --add-drivers rr640l \
> /boot/initramfs-3.10.89vbird.img 3.10.89vbird
[root@study linux]# lsinitrd /boot/initramfs-3.10.89vbird.img | grep rr640
透过这样的动作,我们就可以轻易的将模块编译起来,并且还可以将他直接放置到核心模块目录中, 同时以 depmod 将模块建立相关性,未来就能够利用 modprobe 来直接取用啦! 但是需要提醒你的 是,当自行编译模块时, 若你的核心有更新 (例如利用自动更新机制进行在线更新) 时,则你必须 要重新编译该模块一次, 重复上面的步骤才行!因为这个模块仅针对目前的核心来编译的。
- 利用旧有的核心原始码进行编译
如果你后来发现忘记加入某个模块功能了,那该如何是好?其实如果仅是重新编译模块的话, 那么 整个过程就会变的非常简单!我们先到目前的核心原始码所在目录下达 make menuconfig , 然后将
NTFS 的选项设定成为模块,之后直接下达:
make fs/ntfs/
那么 ntfs 的模块 (ntfs.ko) 就会自动的被编译出来了! 然后将该模块复制到 /lib/modules/3.10.89vbird/kernel/fs/ntsf/ 目录下, 再执行 depmod -a ,就可以在原来的核心底 下新增某个想要加入的模块功能啰
核心模块管理
核心与核心模块是分不开的,至于驱动程序模块在编译的时候,更与核心的原始码功能分不开~因 此,你必须要先了解到:核心、核心模块、驱动程序模块、核心原始码与头文件案的相关性, 然后才有办法了解到为何编译驱动程序的时候老是需要找到核心的原始码才能够顺利编译!