一.内核与内核模块

回到顶部

主机硬件由内核驱动工作,内核一般都是压缩文件,在加载内存之前需要先解压缩。
对于新开发的硬件,一般有两种方式可以将驱动程序加入内核:
1.直接在内核源码中编写硬件驱动程序,然后重新编译内核;
2.不需要重新编译内核,单独编写硬件驱动程序并编译为模块,在内核启动后自动(或手动)加载该模块;
上面第一种方式需要重新编译内核,内核编译是一项相对繁杂的工作.我们有单独的主题介绍内核编译。 市面上的硬件设备层出不穷,每出一款新设备,就要将驱动程序加入内核源码并编译,驱动程序的开发调试变得繁琐和困难. 同时也会导致内核源码无限膨胀,显然这不利于内核的开发维护. 比较方便和有趣的是第二种方式,将驱动程序独立出内核,编译成为模块.内核可以在系统正常运作的过程当中加载这个模块到内核的支持, 在需要的时候将模块加载到内核就可以了.我在不需要更动内核的前提之下,只要编译出适当的内核模块. 既方便驱动程序的开发调试,也不会对内核源码产生不可控影响.简单又方便!
内核驱动程序以模块(modules)的形式动态加载到内核中,驱动模块类似插件,除了少部分内核自带的驱动程序, 大部分都由硬件开发商提供.作为普通用户,我们不必亲自编写驱动程序.只需要使用硬件开发商提供的驱动程序就可以了.
本文主要介绍如何使用硬件商提供的驱动程序以使内核正确的驱动硬件工作.
内核文件包含了硬件侦测与驱动模块. 模块文件存放在/lib/modules/$(uname -r)/kernel/目录中.

内核与内核模块存放的路径:

内核: /boot/vmlinuz 或 /boot/vmlinuz-version;
内核解压缩所需ramdisk: /boot/initramfs 或 /boot/initramfs-version;
内核模块: /lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel;
内核源码: /usr/src/linux 或 /usr/src/kernels/ (需安装,默认不安装)
内核版本: /proc/version
系统内核功能: /proc/sys/kernel/

二.查看内核模块

回到顶部

基本上内核模块大都存放在/lib/modules/$(uname -r)/kernel目录中,该目录还有以下几个子目录:

arch: 与硬件平台有关的项目,例如CPU的等级等;
crypto: 内核所支持的加密技术,例如md5,des等;
drivers: 一些硬件的驱动程序,例如显卡、网卡、PCI设备等;
fs: 内核支持的filesystems,例如vfat, reiserfs, nfs等;
lib: 一些函数库;
net: 与网络有关的各项协议数据,还有防火墙模块(net/ipv4/netfilter/*)等;
sound: 与音效有关的各项模块;
lsmod列出内核中已加载的模块:
              [root@initroot ~]# lsmod
              Module                  Size  Used by
              vboxsf                 77824  1
              snd_intel8x0           40960  2
              snd_ac97_codec        131072  1 snd_intel8x0
              ac97_bus               16384  1 snd_ac97_codec
              snd_pcm               102400  2 snd_intel8x0,snd_ac97_codec
              snd_seq_midi           16384  0
              snd_seq_midi_event     16384  1 snd_seq_midi
              joydev                 24576  0
              crct10dif_pclmul       16384  0
              ....
              ttm                   106496  1 vboxvideo
              libahci                32768  1 ahci
              i2c_piix4              24576  0
              e1000                 143360  0
              drm                   401408  5 drm_kms_helper,vboxvideo,ttm
              pata_acpi              16384  0
              video                  49152  0
              drm还被drm_kms_helper,vboxvideo,ttm等模块使用.
            
lsmod为list module的简称,列出内核中已经加载的模块,显示的内容包括:
模块名称(Module);
模块的大小(size);
此模块是否被其他模块所使用 (Used by)。
有些内核模块有相依性.例如drm先被加载后,ttm这个模块才能被加载到内核中! 这两个模块是有相依性的。

三.内核模块的依赖性

回到顶部

通过lsmod可以看出有些内核模块之间有依赖关系,/lib/modules/$(uname -r)/modules.dep文件记录了内核模块的依赖关系。
depmod命令分析并建立该文件:

              [root@initroot ~]# depmod [-Ane]
              选项与参数:
              -A:没有参数的情况下depmod默认会分析内核的模块,并重新写入/lib/modules/$(uname -r)/modules.dep文件中。
                加入-A参数时后,depmod会搜索比modules.dep内更新的模块,找到新模块后,才会更新文件。
              -n :不写入modules.dep ,而是将结果输出到屏幕(standard out);
              -e :显示目前已加载的不可执行的模块名称
            
假设网卡驱动程序文件名为a.ko,更新内核相依性:
              [root@initroot ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
              [root@initroot ~]# depmod
            
内核模块文件扩展名必须是.ko, depmod会分析模块标准放置目录/lib/modules/$(uname -r)/kernel下的全部模块,将分析结果写入modules.dep文件!
这个文件很重要,会影响到后面介绍的modprobe命令的使用!

四.查看模块信息

回到顶部

使用modinfo查看某个模块的信息:

            [root@initroot ~]# modinfo [-adln][module_name|filename]
            选项与参数:
            -a :仅列出作者名称;
            -d :仅列出该 modules 的说明 (description);
            -l :仅列出授权 (license);
            -n :仅列出该模块的详细路径。
          
列出drm模块的相关信息:
            [root@initroot ~]# modinfo drm
            filename: /lib/modules/4.15.0-191-generic/kernel/drivers/gpu/drm/drm.ko
            license: GPL and additional rights
            description: DRM shared core routines
            author: Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl
            ......
            name: drm
            vermagic: 4.15.0-191-generic SMP mod_unload modversions
            signat: PKCS#7
            signer:
            sig_key:
            sig_hashalgo: md4
            parm: edid_firmware:Do not probe monitor, use specified EDID blob from built-in data or /lib/firmware instead.
            (string)
            parm: vblankoffdelay:Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)
            (int)
            ........
          
可以看到这个模块的来源,以及该模块的简易说明!
modinfo后还可以是一个模块文件名:
            [root@initroot ~]# modinfo a.ko
            ....(省略)....
          
modinfo除了可以查看已加载的模块信息外,还可以查看模块文件.

五.内核模块的加载与移除

回到顶部

modprobe和insmod都可以加载模块.modprobe会先搜索modules.dep文件查询模块的依赖关系, 加载所有相关的模块。
而insmod并不会主动分析模块依赖性,只加载用户指定的模块,

              [root@initroot ~]# insmod [/full/path/module_name] [parameters]
            
加载cifs.ko这个文件系统模块
              [root@initroot ~]# insmod /lib/modules/$(uname -r)/kernel/fs/fat/fat.ko
              [root@initroot ~]# lsmod | grep fat
              fat  65913 0
            
insmod命令用来安装模块,insmod后面必须要是完整的文件名才行.

              [root@initroot ~]# rmmod [-fw] module_name
              选项与参数:
              -f: 强制将该模块移除掉,不论是否正被使用;
            
将刚刚加载的fat模块移除:
              [root@initroot ~]# rmmod fat
            
加载vfat这个文件系统模块
              [root@initroot ~]# insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko
              insmod: ERROR: could not load module /lib/modules/3.10.0-229.el7.x86_64/kernel/fs/vfat/
              vfat.ko: No such file or directory
              无法加载vfat模块
            
insmod与rmmod要求必须提供模块的完整文件名,如果模块有依赖性,将无法直接加载或移除该模块! 所以建议直接使用modprobe加载或移除模块.
              [root@initroot ~]# modprobe [-cfr] module_name
              选项与参数:
              -c: 列出系统所有的模块;
              -f: 强制加载该模块;
              -r: 类似rmmod,移除某个模块
            
加载vfat模块:
              [root@initroot ~]# modprobe vfat
            
不需要完整的模块文件名,这是因为文件名已经记录到/lib/modules/`uname -r`/modules.dep文件中.
移除vfat模块:
              [root@initroot ~]# modprobe -r vfat
            
modprobe比insmod方便很多,因为他是直接去搜寻modules.dep的纪录,可以解决模块的相依性问题,而且还不需要知道该模块的详细路径
使用modprobe加载cifs模块,再以lsmod配合grep观察该模块的依赖的模块有哪些:
              [root@initroot ~]# modprobe cifs
              [root@initroot ~]# lsmod | grep cifs
              cifs 456500 0
              dns_resolver 13140 1 cifs
            
可以看到cifs模块依赖dns_resolver模块.
移除此模块:
              [root@initroot ~]# modprobe -r cifs
            
内核模块的额外参数设定:/etc/modprobe.d/*conf
如果有某些特殊的需求导致你必须要让内核模块加上某些参数时,需要自己建立扩展名为.conf的文件,通过options来带入内核模块参数!

initroot编辑整理,转载请注明www.initroot.com