# 核心与核心模块

整个开机流程讲完,在整个开机过程中,是否能够成功的驱动我们主机的硬件设备,是核心的工作,而核心一般都是压缩文件,因此需要先解压后才能加载主存储器中

目前的核心都是具有可读取模块化驱动程序的功能,即模块化(modules),该模块可能由硬件开发厂商提供,也有可能核心本来就支持,较新的硬件,通常都需要硬件开发商提供驱动程序的模块

核心与核心模块位置:

  • 核心:/boot/vmlinuz/boot/vminuz-version
  • 核心解压缩需 RAM disk:/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

问题来了:如果有个新的硬件,我的操作系统不支持怎么办?

  • 重新编译核心,并加入最新的硬件驱动程序原始码
  • 将该硬件的驱动程序编译成为模块,在开机时加载该模块

关于怎么编译可以参考后续的第 21 章。

# 核心模块与相依性

基本上核心模块在 /lib/modules/$(uname -r)/kernel 中,主要分成几个目录

arch:与硬件平台有关项目,例如 CPU 的等级等
crypto:核心所支持的加密技术,例如 md5 或则是 des 等
drivers:一些硬件的驱动程序,例如显卡、网卡、PCI 相关硬件
fs:核心所支持的 filesystems,例如 vfat、reiserfs、nfs 等
lib:一些函数库
net:与网络有关的各项协议数据,还有防火墙模块(net、ipv4、netfilter) 等
sound:与音效有关
1
2
3
4
5
6
7

有一个文件记录了核心支持的模块的各项相依性:/lib/modules/$(uname -r)/modules.dep, 可以使用 depmod 指令来管理

depmod [-Ane]

选项与参数:
	-A:不加任何参数时,depmod 会主动分析目前核心的模块,并且重新写入该文件中。若加入 -A 参数时,则会去搜索比 modules.dep 内还要新的模块,如果找到新模块,才会更新
	-n:不写入 modules.dep ,而是将结果输出到屏幕上
	-e:显示出目前已加载的不可执行的模块名称
1
2
3
4
5
6
# 范例:若我做好一个网卡驱动程序,文件名为 a.ko  ,如何更新核心想依性?
cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
depmod
1
2
3

核心模块扩展名一定是 .ko 结尾,当使用 depmod 后,该程序会在 /lib/modules/$(uname -r)/kernel/ 目录内,根据相关目录的定义将全部的模块拿来分析,最终才会将分析的结果写入 modules.dep 文件中

该文件很重要,会影响到本章后续会介绍的 modprobe 指令的应用

# 核心模块的观察

可以通过 lsmod 知道目前核心加载了多少模块

[root@study ~]# lsmod 
# 模块名									大小		模块是否被其他模块所使用
Module                  Size  Used by
xt_CHECKSUM            12549  1 
ipt_MASQUERADE         12678  3 
nf_nat_masquerade_ipv4    13430  1 ipt_MASQUERADE
tun                    32026  1 
bridge                151336  0 
stp                    12976  1 bridge
llc                    14552  2 stp,bridge
...
drm										 311588 4 qx1,ttm,drm_kms_helper

1
2
3
4
5
6
7
8
9
10
11
12
13

模块是有相依性的,比如上面 nf_nat_masquerade_ipv4 先加载,ipt_MASQUERADE 模块才能够进一步加载到系统中,这两者是有相依性的

想要了解某个块,可以使用 modinfo

modinfo [-adln] [module_name|filename]
选项与参数:
	-a:仅列出作者名称
	-d:仅列出该 modules 的说明(description)
	-l:仅列出授权 license
	-n:仅列出该模块的详细路径
1
2
3
4
5
6
# 范例:列出 drm 模块的相关信息
[root@study ~]# modinfo drm
# 该模块的来源
filename:       /lib/modules/3.10.0-1062.el7.x86_64/kernel/drivers/gpu/drm/drm.ko.xz
license:        GPL and additional rights
# 该模块的简介
description:    DRM shared core routines
author:         Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl
license:        GPL and additional rights
description:    DRM bridge infrastructure
author:         Ajay Kumar <ajaykumar.rs@samsung.com>
retpoline:      Y
rhelversion:    7.7
srcversion:     0B7C5A6948CEE2DF7C405B0
depends:        drm_panel_orientation_quirks
...
sig_hashalgo:   sha256
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)
parm:           timestamp_precision_usec:Max. error on timestamps [usecs] (int)
parm:           edid_fixup:Minimum number of valid EDID header bytes (0-8, default 6) (int)
parm:           debug:Enable debug output, where each bit enables a debug category.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

该指令处理可以查询在核心内的模块,还可以检查某个模块文件。

# 核心模块的加载与移除

如想手动加载模块?有很多方法,这里推荐最简单的方式,就是使用 modprobe 指令来加载模块,因为它会主动搜索 modules.dep 的内容,先克服了模块的相依性后,才决定需要加载的模块有哪些

而 insmod 则完全由使用者加载一个完整文件名的模块,并不会主动分析模块的相依性

insmod [/full/path/module_name] [parameters]
1
# 范例 1:尝试载入 cifs.ko 文件系统模块
[root@study ~]# insmod /lib/modules/$(uname -r)/kernel/fs/fat/fat.ko.xz
[root@study ~]# lsmod | grep fat
fat                    65950  0 

1
2
3
4
5

like就被加载了,但是需要完整的路径

rmmod [-fw] module_name

-f:强制移除该模块,无论是否正在使用
1
2
3
# 范例 1:将刚刚加载的模块移除
[root@study ~]# rmmod fat
[root@study ~]# lsmod | grep fat
# 就被移除掉了

# 范例 2:加载 vfat 这个文件系统模块
[root@study ~]# insmod /lib/modules/$(uname -r)/kernel/fs/fat/vfat.ko.xz
insmod: ERROR: could not insert module /lib/modules/3.10.0-1062.el7.x86_64/kernel/fs/fat/vfat.ko.xz: Unknown symbol in module
# 无法加载
1
2
3
4
5
6
7
8
9

上面就由于有模块相依性,无法直接被加载,就可以使用 modprobe 来处理

modprobe [-cfr] module_name

选项与参数:
	-c:列出目前系统所有的模块(更详细的代号对应表)
	-f:强制加载该模块
	-r:类似 rmmod
1
2
3
4
5
6
# 范例 1: 加载 vfat 模块
[root@study ~]# modprobe vfat
[root@study ~]# lsmod | grep vfat
vfat                   17461  0 
fat                    65950  1 vfat

# 可以看到,自己就帮我们解决了模块的相依性问题,而且只需要知道模块名
1
2
3
4
5
6
7

# 核心模块的额外参数设置:/etc/modprobe.d/*.conf

如果有某些特殊的需求导致你必须要让核心模块加上某些参数时,这个时候可以回到上一章的最后一小节 开机过程会用到的主要配置文件 中去了解,重点就是要自己建议 .conf 的文件,通过 options 来带入核心模块参数