我们在 Linux 下可能会碰到不能识别一些硬件,如无线网卡、蓝牙等问题,而解决这类问题的方法有三种,一是单独编译安装驱动;二是升级发行版;三是单独升级内核。而以 Ubuntu 为例,升级内核又分为三种,一是发行版仓库推送的升级;二是安装 Ubuntu 主线内核;三是手工编译安装新内核。本文在 Ubuntu 20.04 下面简述一下手工编译最新主线内核 6.7 的步骤,其中含有固件安装及制作 linux-headers 文件夹供后面编译其它驱动模块使用。视频演示地址:【怎样在 Ubuntu 下手工编译安装 6.* 最新内核】 https://www.bilibili.com/video/BV1ae411H75b/?share_source=copy_web&vd_source=d1925b070926f23b2b6676137251e9ea
一、下载内核
假定电脑是 UEFI 类型的 BIOS,手工编译内核之前先在主板 BIOS 中禁止 UEFI 的安全启动。
查看安全启动状态:
sudo apt update
sudo apt install mokutil -y
mokutil --sb-state # 显示 “SecureBoot disabled” 表示已经禁止了安全启动
内核的官网可以在 The Linux Kernel Archives 下载,国内的一些镜像网站可能速度更快,如清华大学开源软件镜像站内核镜像的6.7内核。
建议使用最接近你当前内核的并且能支持你的硬件的版本,我这里编译当前最新的6.7主线内核仅作为一个示例。
二、内核配置
寻找一个接近编译版本的可靠内核配置文件,在这个配置文件的基础上进行配置。我这里使用 Ubuntu 22.04 的最新 HWE 6.5 内核,从相应镜像网站下载包含内核配置文件(config-6.5.0-14-generic)模块包 linux-modules-6.5.0-14-generic_6.5.0-14.14~22.04.1_amd64.deb。
用下面的命令提取出内核配置文件。进入下载的目录中。
sudo apt install binutils -y
mkdir tmp
ar x linux-modules-6.5.0-14-generic_6.5.0-14.14~22.04.1_amd64.deb --output=tmp
cd tmp
tar -xf data.tar.zst ./boot
cd boot
cp config-6.5.0-14-generic ~/ -v
三、编译安装内核
1、下载编译工具包
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev dwarves zstd -y
2、编译安装内核
# 把内核解压到家目录下
tar -xf linux-6.7.tar.xz -C ~/
cd ~/linux-6.7
cp ~/config-6.5.0-14-generic .config -v
# ubuntu 20.04 的 kmod 版本是27,不支持 zstd 压缩模块,kmod 28 及以上的版本才支持
sed -i 's/CONFIG_MODULE_COMPRESS_ZSTD=y/# CONFIG_MODULE_COMPRESS_ZSTD is not set/' .config
make olddefconfig
# 可以进一步查看和编辑生成的 .config 文件内容,以确保生成的配置文件包括必须支持的硬件模块。编辑完成保存后再执行一次 make olddefconfig。
# 也可以进一步用 make menuconfig 作进一步的修改和保存。
scripts/config --disable SYSTEM_TRUSTED_KEYS
scripts/config --disable SYSTEM_REVOCATION_KEYS
scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS ""
scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS ""
make -j8
echo $? # 如果结果是 0 表示编译成功,接着安装内核模块和内核
sudo make INSTALL_MOD_STRIP=1 modules_install -j8
sudo make install
如果最后没有看到报错信息就重启进入系统,执行 uname -r
确认是否使用的是新编译的 6.7 内核。
四、固件安装
有时安装了新内核硬件仍然不能正常工作,可能还需要安装相应的固件(firmware)。
这时可以在 dmesg
命令的结果中看到相关线索,如 一款式 Intel 的蓝牙不能工作 ,“Bluetooth: hci0: failed to load intel firmware file intel/ibt-0040-1050.sfi (-2)”。
这里可以去内核网站下载最新的固件包,如当前的 linux-firmware-20231211.tar.gz。
比如上面是“Intel 的 WiFi 6 和蓝牙 5.2 AX101 模块”,在解压开的固件包里找到"ibt-0040-1050.sfi"并复制到 "/lib/firmware/intel"。重启就应该行了。
五、制作 linux-headers 文件夹
可用于后续驱动模块编译的编译内核过的文件夹有约30G,怎样瘦身还能正常用于以后的其它驱动模块的编译呢?如 nvidia 显卡闭源驱动模块。
这方面我没找到权威的文档,就根据 Ubuntu 22.04 当前的 6.5 内核的 linux-headers 包内容,对编译内核文件夹作一些瘦身。瘦身下来还有约 800M。命令如下:
mkdir ~/tmp2
cd ~/linux-6.7
mv arch include scripts tools .checked*.h ~/tmp2/ -v
find ~/linux-6.7 -iname '*.c' -o -iname '*.h' -o -iname '*.cmd' -o -iname '*.o' -o -iname '*.a' -o -iname '*.ko' | xargs rm -v
cd ~/tmp2
find ./arch -iname '*.c' -o -iname '*.a' -o -iname '*.ko' -o -iname '*.zst' | xargs rm -v
find ./ -iname '*.cmd' | xargs rm -v
cd ~/linux-6.7
mv ~/tmp2/.check*.h ~/tmp2/* ./ -v
rm System.map vmlinux* -v
rm .clang-format .cocciconfig .config.old .get_maintainer.ignore .gitattributes .mailmap .rustfmt.toml .tmp_vmlinux.* .version .vmlinux.objs -v
cd ~/
sudo mv linux-6.7 /usr/src/linux-headers-6.7.0 -v
sudo ln /usr/src/linux-headers-6.7.0 /lib/modules/6.7.0/build -sfv
请注意,上面的命令中会查找并自动删除文件,请谨慎操作,不要在错误的文件夹中执行以致误删除文件。
六、参考链接
1、How to Compile and Install the Linux Kernel on Ubuntu https://davidaugustat.com/linux/how-to-compile-linux-kernel-on-ubuntu
2、modprobe can't load ZSTD compressed kernel modules #128 https://github.com/linuxserver/docker-wireguard/issues/128
3、Ubuntu 主线内核 https://kernel.ubuntu.com/mainline/
4、Ubuntu 内核发布周期 https://ubuntu.com/about/release-cycle#ubuntu-kernel-release-cycle