编译安装linux内核

阅读量: searchstar 2020-12-28 13:58:21
Categories: Tags:

下载内核

https://www.kernel.org/

在这里插入图片描述

一般下载tarball,也就是.tar.xz格式的源码包。如果/够大,可以直接解压到/usr/src,也可以解压到机械盘上。

配置

.config

里面是一些flag,内核编译的时候会读取这个文件,根据这些flag来配置。

常用的有:

附加在在内核的version string后面。自动生成的通常默认是-amd64-desktop+,生成的内核版本类似于5.1.0-amd64-desktop+。设置CONFIG_LOCALVERSION="-default-config"后,编译生成的内核版本号就是类似于5.1.0-default-config。来源:https://stackoverflow.com/questions/28684811/how-to-change-version-string-of-the-kernel

make menuconfig

如果手动编辑了.config的话,这一步可能会根据手动编辑的内容调整一些其他选项,比如如果设置了CONFIG_KASAN=y,执行make menuconfig后会自动加上CONFIG_KASAN_GENERIC=yCONFIG_KASAN_OUTLINE=y

sudo apt install -y flex bison libelf-dev
make menuconfig

如果没有特殊需求,可以直接按右键头选中Exit

在这里插入图片描述

然后按enter,选保存即可。

也可以在里面更改一些内核配置,常见的:

KASAN

KASAN是一个动态检测内存错误的工具:在Linux内核使用Kasan

对应.config里的:

CONFIG_SLUB_DEBUG=y
CONFIG_KASAN=y

CONFIG_KASAN_OUTLINE=y生成的二进制文件更小,而CONFIG_KASAN_INLINE=y更快。

参考:https://www.kernel.org/doc/html/v5.1/dev-tools/kasan.html

kobject debugging

kobject debugging

kobject release debugging

这俩开了之后dmesg里有意义不明的输出。

make

多线程编译

make -j$(nproc) > /dev/null

> /dev/null是为了防止warning和error被刷掉,比如让我们装libelf-dev的警告。

安装到系统目录

内核模块

如果没有特殊需求,一般可以把内核模块的debug信息给去掉,节约安装空间。

make INSTALL_MOD_STRIP=1 modules_install > /dev/null

注意对于centos不能INSTALL_MOD_STRIP=1,不然启动貌似会出问题。应该

make modules_install

然后再用这里的方法去/usr/lib/modules里手动把debug信息去掉:

解决编译安装内核时/lib/modules过大的问题

内核

make install

如果有类似于这样的报错:

没有规则可制作目标“certs/rhel.pem”,由“certs/x509_certificate_list” 需求。

那可能要把.config里的CONFIG_SYSTEM_TRUSTED_KEYS后面引号里的东西删掉。

另外要注意看看有没有要我们安装console-setupplymouth-themes的提示。

参考:make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。

(可选)用于编译内核模块的文件

这个安装的头文件只能给用户态程序用,不能用于编译内核模块:

# make INSTALL_HDR_PATH=$target_dir headers_install
make headers_install

如果用包管理器安装linux-headers-xxx的话,会把头文件安装在/usr/src/linux-headers-xxx-amd64/usr/src/linux-headers-xxx-common下面,里面有用的只有这几个文件或文件夹:

arch/x86/include/ arch/x86/Makefile* include/ Makefile Module.symvers scripts/ tools/

所以如果要安装用于编译内核模块的文件到系统目录,只需要把这些文件或文件夹放进/usr/src/linux-headers-我们编译的内核版本即可。

之前安装的内核模块的目录/usr/lib/modules/我们编译的内核版本里的buildsource符号链接原先是指向编译时使用的源码的路径,现在改到/usr/src/linux-headers-我们编译的内核版本/即可。

安装到指定目录

这样可以在服务器上编译内核,安装到$target_dir,然后$target_dir打包传到目标机器,再安装到目标机器上的系统目录即可。

内核模块

把内核模块安装到$target_dir/lib/modules/$kernel_version_to_install

# INSTALL_MOD_PATH=$target_dir make modules_install
INSTALL_MOD_PATH=$target_dir make INSTALL_MOD_STRIP=1 modules_install

内核

System.map-$kernel_version_to_installvmlinuz-$kernel_version_to_install安装到$target_dir下面:

INSTALL_PATH=$target_dir make install

会报错:

ln: 无法创建符号链接'/boot/System.map': 权限不够
ln: 无法创建符号链接'/boot/vmlinuz': 权限不够
ln: 无法创建符号链接'/boot/System.map': 权限不够

不用管这个报错,因为我们不安装到系统目录。

(可选)内核配置

config-$kernel_version_to_install安装到$target_dir下:

kernel_version_to_install=$(make kernelrelease)
cp .config $target_dir/config-$kernel_version_to_install

(可选)用于编译内核模块的文件

把这些文件安装到$target_dir/linux-headers-$kernel_version_to_install

kernel_version_to_install=$(make kernelrelease)
header_dir=$target_dir/linux-headers-$kernel_version_to_install
mkdir -p $header_dir/arch/x86/
cp -r arch/x86/include/ arch/x86/Makefile* $header_dir/arch/x86/
cp -r include/ Makefile Module.symvers scripts/ tools/ $header_dir/

在目标机器上安装到系统目录

在编译服务器上把$target_dir压缩,传输到目标机器上,解压出来,进入$target_dir,然后执行以下指令来安装到目标机器上的系统目录里:

kernel_version_to_install=$(ls lib/modules/)
# 内核模块
sudo cp -r lib/modules/$kernel_version_to_install /lib/modules/
# 内核
sudo cp -r vmlinuz-$kernel_version_to_install System.map-$kernel_version_to_install /boot/
# (可选)安装内核配置
sudo cp config-$kernel_version_to_install /boot/
# (可选)安装用于编译内核模块的文件
sudo rm -rf /usr/src/linux-headers-$kernel_version_to_install
sudo cp -r linux-headers-$kernel_version_to_install/ /usr/src/linux-headers-$kernel_version_to_install
sudo rm /lib/modules/$kernel_version_to_install/build /lib/modules/$kernel_version_to_install/source
sudo ln -s /usr/src/linux-headers-$kernel_version_to_install/ /lib/modules/$kernel_version_to_install/build
sudo ln -s /usr/src/linux-headers-$kernel_version_to_install/ /lib/modules/$kernel_version_to_install/source

然后给刚刚安装的内核生成initramfs:Linux生成initramfs

更新grub

如果电脑上装了多个linux,那选系统界面的grub可能不是当前系统提供的,这个时候就要去提供grub的那个系统更新grub才行。

Debian系

sudo update-grub

CentOS

# Legacy启动
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# EFI启动
sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

CentOS的启动内核是通过grubby设置的,所以CentOS的grub2-mkconfig可能只会输出发现的其他操作系统的启动项,比如只输出Windows

Generating grub configuration file ...
Found Windows Boot Manager on /dev/sda1@/efi/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for EFI firmware configuration
done

但是其实也同时把当前操作系统的内核给识别出来了。

设置默认内核

grubby

CentOS使用grubby来管理启动项,因此需要使用grubby来设置默认内核。首先添加内核:

sudo grubby --add-kernel=/boot/vmlinuz-xxxx --title="随便写点啥"

注意还需要用grub2-mkconfig更新一下grub.cfg,新加的内核的args和root才会正常。

然后设置为默认内核:

sudo grubby --set-default=/boot/vmlinuz-xxxx

其他实用grubby子命令:

# 查看grubby列表中的所有内核
sudo grubby --info ALL
# 查看指定内核的信息
sudo grubby --info=kernel-path
# 查看当前的默认内核
sudo grubby --default-kernel
# 查看默认内核在grubby列表中的index
sudo grubby --default-index
# 将指定内核从grubby列表中移出
sudo grubby --remove-kernel=kernel-path

参考:https://www.golinuxcloud.com/grubby-command-examples/

设置GRUB默认项

Ubuntu 切换系统默认启动内核

如果可以与GRUB菜单交互,那么也可以这样:GRUB菜单记住上次的选择的内核

删除旧内核(可选)

https://www.cnblogs.com/amanlikethis/p/3599170.html