前言
Linux内核是操作系统的核心,也是操作系统最基本的部分。
我们说的Linux其实指的就是 内核(kernel)而已。这个内核控制你主机的所有硬件并提供系统所有的功能,所以它非常重要。我们开机的时候就是利用开机管理程序加载这个内核文件来检查硬件,在内核加载适当的驱动程序后,系统才能够顺利运行。
现今的系统由于强调在线升级机制,因此非常不建议自定义内核编译!但是,如果你想将你的Linux安装到USB移动设备,将你的PC安装自己的Linux,想让你的Linux可以驱动你的PC,内核编译就是相当重要的一个任务。
Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。
认识内核与取得内核源代码
内核(kernel)是整个操作系统的最底层,它负责了整个硬件的驱动,以及提供各种系统所需的核心功能。包括防火墙机制、是否支援LVM或Quota等文件系统。如果你的内核不认识某个最新的硬件,那么该硬件也就无法被驱动,当然也就无法使用该硬件。
什么是内核(kernel)?
Kernel
电脑真正在工作的东西其实是 “硬件”,例如数值运算要使用到CPU、储存资料要用到硬盘、图形显示要用到显卡、音频需要声卡、连接Internet需要网卡等等。那么如何控制这些硬件呢?那就是内核的工作了。
你想让计算机进行的工作,都必须要内核支持才行,这个标准不论是LInux还是Windows都一样。
其实内核就是系统上面的一个文件而已,这个文件包含了驱动主机各项硬件的检测程序与驱动模块。在开机流程分析中,这个文件被读入主存储器的时机,当系统读完BIOS并加载MBR内的引导装载程序后,就能够加载内核到内存当中。然后内核开始检测硬件,挂载根目录并取得内核模块来驱动所有的硬件,之后调用 systemd就能依序启动所有系统所需的服务了。
这个内核文件通常被放置在 /boot/vmlinuz-xxx,不过也不见得,因为一台主机上可以拥有多个内核文件,而开机的时候仅能选择一个来加载而已。我们甚至可以在一个distribution上面放置多个核心,然后以这些核心来做成多重开机。
内核模块(Kernel module)用途
既然内核文件都已经包含了硬件检测与驱动模块,那么什么是内核模块?
如果我的内核比较旧,但是我换了新的硬件,这个内核肯定无法识别,而重新编译内核是很麻烦的。为了这个缘故,Linux就开始使用所谓的模块化设置了。即是将一些不常用的类似驱动程序的内容独立出内核,编译成模块,然后,内核可以在系统正常运行的过程中加载这个模块到内核的支持。如此一来,我在不需要更改内核的前提下,只要编译出适当的内核模块,在加载它,Linux就可以使用这个硬件了。模块组放置于 /lib/modules/$(uname -r)/kernel/中。
自制内核-内核编译
内核文件是通过 源码(source code)编译而成的。因为内核是直接被读入主存储器中,所以要将它编译成为系统可认识的文件才行,也就是说,我们要取得内核的源码,然后进行编译。
关于驱动程序:
是厂商的责任还是内核的责任
在驱动程序的开发这个工作上来说,应该是属于硬件发展厂商的问题。主要是Linux上面的使用人员实在是少于Windows人员。
更新内核的目的
除了BIOS(或UEFI)之外,内核是操作系统中最早被加载到主存储器的,它包含了所有可以让硬件和软件工作的信息。所以,如果没有搞定核心,系统肯定会有小问题。
内核编译的重点在于 “你的Linux做什么?”,如果没有必要的工作,就不用加在内核当中,这样才能让你的Linux跑的更快更稳健。这也是为什么我们需要编译内核的最主要原因。
Linux内核特色与默认内核对终端用户的角色
Linux内核有几个主要的特色,除了Kernel可以随时、 随各人喜好而改动之外,版本改动次数太频繁也是一个特点。所以,除非你有特殊需求,否则一次编译成功就可以啦!不需要随时保持最新的内核版本,而且也没有必要(便以一次内核要很久。)
对于一般的使用者,由于系统已经将内核编译的相当得相当适合普通用户使用了,因此一般入门的用户基本上不太需要编译内核。
内核编译的可能目的
当然是有需要才回来编译内核啦!
编译内核的时机可以归纳为以下几类:
新功能的需求
我需要新的功能,而这个功能只在新的内核里面才有,为了获得这个功能,只好重新编译我的内核;
原本的内核太过于臃肿
如果你对系统稳定性很要求,对于内核多编译了很多莫名其妙的功能不太喜欢的时候,那么就可以重新编译内核来取消该功能;
与硬件搭配的稳定性
内核也可能没有正确的驱动新的硬件,此时就得重新编译核心来让系统取得正确的模块才好;
其他需求(如嵌入式系统)
你需要特殊的环境需求时,就得自行设计你的内核;
如果为了增加性能来编译内核的话,基本上,效益不大。然而,如果是针对“系统稳定性”来考量的话,那么就有充分的理由来支持你重新编译内核。
如果系统已经运行很久了,而且也没有什么问题,加上我又不想增加冷门的硬件设备,那么建议就不需要重新编译内核。因为重新编译内核的主要目的是“想让系统变得更加稳定”。
由于内核的主要工作是控制硬件,所以编译之前,请先了解硬件设备和主机未来的功能。内核当然是越简单越好啦!
内核的版本
系统版本:uname -srm
详细版本:cat /proc/version
主机信息&架构:hostnamectl
准备工具
Linux操作系统 Debian 11
1.配置需要安装的环境
nano /etc/apt/sources.list
添加软件源:
deb http://mirrors.163.com/debian/ stretch main
deb http://mirrors.163.com/debian/ stretch-updates main non-free contrib
deb-src http://mirrors.163.com/debian/ stretch-updates main non-free contrib
deb http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib
更新软件列表:
apt-get update
更新软件:
apt-get upgrade
配置内核编译环境:
apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison libncurses5-dev gcc
2.编译内核
下载并解压内核
内核下载官网:https://www.kernel.org/
解压内核:tar xvf linux-5.17-rc2.tar.xz(本文以5.17-rc2内核为例)
配置内核
复制原配置文件并重命名文件
cp -v /boot/config-5.10.0-10-amd64 /root/Kernel/.config
(/root/Kernel/
为内核源代码所在目录)
定制内核,启用或者禁用你需要或者不需要的模块
make menuconfig
编译内核和模块
make -j 8 deb-pkg
make -j 选项表示并行编译。
make -j8,让make最多允许8个编译命令同时执行,这样可以更有效的利用CPU资源。
在多核CPU上,适当的进行并行编译可以明显提高编译速度。但并行的任务不宜太多,一般是以CPU核心数目的两倍为宜。
3.编译完成
编译需要花费很长的时间,编译完成,会在源文件外生成四个deb包
执行命令升级内核
dpkg -i *.deb
更新 grub
update-grub
重启系统,查看内核版本
uname -a
解决编译过程中遇到的问题
问题一:
BTF: .tmp_vmlinux.btf: pahole (pahole) is not available
Failed to generate BTF for vmlinux
Try to disable CONFIG_DEBUG_INFO_BTF
解决办法:
修改配置文件
CONFIG_DEBUG_INFO_BTF=y
改成
CONFIG_DEBUG_INFO_BTF=n
问题二:
编译内核时的sys/types.h问题
如果你出现了ubuntu fatal error : sys/types.h: 没有那个文件或目录 这个错误的时候,
解决办法:
那么你需要安装一个软件包build-essential,输入如下命令:
apt-get install build-essential |
问题三:
invalid option `abi=aapcs-linux'选项错误
scripts/kconfig/conf -s arch/arm/Kconfig
CHK include/linux/version.h
SYMLINK include/asm-arm/arch -> include/asm-arm/arch-s3c2410
make[1]: `include/asm-arm/mach-types.h' is up to date.
CHK include/linux/utsrelease.h
CC arch/arm/kernel/asm-offsets.s
cc1: error: invalid option `abi=aapcs-linux'
make[1]: *** [arch/arm/kernel/asm-offsets.s] Error 1
make: *** [prepare0] Error 2
解决方法:
You're building an EABI kernel with an OABI compiler. You can either turn off the EABI option in your config file (Kernel Features->Use EABI),or, you can use an EABI toolchain such as the ARM/GNU Linux one from < recommend the latter, because then you can run Arjan's new images.
上述的关掉EABI选项可以通过测试
问题四:
drivers/video/console/vgacon.o:987:warning:comparison is always true due to limited range of data type
make[3]:***[drivers/video/console/vgacon.o] error 1
make[2]:***[drivers/video/console2] error 2
make[1]:***[drivers/video1] error 2
make:***[drivers] error 2
解决方法:
在make menuconfig 时选哪个设备驱动的选项进去在选Graphics support ->
console display driver support->
vga text console(不选这个)
再编译就行了!
问题五:
`rtc_lock'未定义错误(未完全解决)
解决方法:
drivers/built-in.o(.text+0x281e4):drivers/char/nvram.c:350: more undefined references to `rtc_lock' follow
查 找drivers/char/nvram.c有关的rtc_lock定义,发现2.6.21与以往的kernel不同,于是在包含文件中查找,在 include/linux/mc146818rtc.h中发现了rtc_lock的定义,但是有一个__KERNEL__的条件编译选项,去掉这个条件 编译选项,再make zImage,但是问题好像依然存在,继续在drivers/char/nvram.c中增加这个定义spinlock_t rtc_lock;再编译,发现编译通过。
问题六:
make zImage和make xipImage
Kernel configured for XIP (CONFIG_XIP_KERNEL=y)
Only the xipImage target is available in this case
make[1]: *** [arch/arm/boot/zImage] Error 1
make: *** [zImage] Error 2
解决方法:
好象是make menuconfig的时候Boot options--->Kernel Execte-In-Place from ROM选项问题,去掉这个选项编译通过(如果是make xopImage时則需要将这个选项选上),最终成功编译了make zImage。
问题七:
出现make:***[.tmp_vmlinux1] Error 1这类错误
解决方法:
修改arch/arm/kernel/vmlinux.lds
[arm@localhost linux2.6.14]$
vi arch/arm/kernel/vmlinux.lds
将文件尾2条的ASSERT注释掉(1439行)
/* ASSERT((__proc_info_end __
proc_info_begin), "missing CPU support") */
/* ASSERT((__arch_info_end __
arch_info_begin), "no machine record defined") */
然后重新make zImage即可