更换虚拟机的内核版本

前言

因为一些原因,我需要切换使用不同的内核版本,因而我硬盘里面有一份完整的linux git内核源码

我安装了一个ubuntu20.04的虚拟机,它的内核是5.11。我以它作为母本,克隆生成虚拟机。在虚拟机中,编译安装上面的内核源码,以使用不同版本内核。

所以总体思路分为以下几步:

  1. 使用virt-manager管理虚拟机,搭建虚拟机母本。

  2. virt-manager设置主机和虚拟机之间文件共享,linux源码位于共享文件夹中,为多个虚拟机提供服务。

  3. Compiling a Custom Linux Kernel on a Virtual Machine,替换虚拟机的内核为指定版本。


在虚拟机上编译自定义 Linux 内核

在虚拟机中安装必要的软件包。

sudo apt install make gcc flex bison libssl-dev libelf-dev libncurses-dev

在主机中编译内核。

cd linux
sudo make mrproper

cp /boot/config-$(uname -r) ../linux_image/5.5/.config
# make defconfig O=../linux_image/5.5
make menuconfig O=../linux_image/5.5
make -j `nproc` O=../linux_image/5.5

# 将 CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem" 
# 修改为
CONFIG_SYSTEM_TRUSTED_KEYS=""

将主机中的linux源码和编译之后的内核代码文件夹,共享到虚拟机中。因为编译之后的内核代码的部分文件会通过软连接的方式指向源码,比如source -> /mnt/data/linux(source是编译生成的文件,其指向linux源码目录)。所以,我们需要将主机中的linux源码文件夹,以相同的位置,挂载在虚拟机中。这样软连接才能找见对应的源文件。

# 将主机中的linux源码挂在到虚拟机中。
# linux源码在主机中的绝对路径:/mnt/data/linux 
# linux源码在虚拟机中挂载的绝对路径,应保持一致:/mnt/data/linux
sudo mount -t 9p -o trans=virtio /linux /mnt/data/linux 

# 将编译生成内核代码挂载到 ~/image
sudo mount -t 9p -o trans=virtio /image ~/image

# 挂载其他需要的共享文件夹
# sudo mount -t 9p -o trans=virtio /cve ~/cve

更换虚拟机的内核版本

cd ~/image
sudo make modules_install -j `nproc`
sudo make install -j `nproc`

安装输出内容。

dacao@dacao-0:~/linux_image$ sudo make install -j `nproc`
sh /home/dacao/linux/arch/x86/boot/install.sh 5.5.0 arch/x86/boot/bzImage \
	System.map "/boot"
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 5.5.0 /boot/vmlinuz-5.5.0
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 5.5.0 /boot/vmlinuz-5.5.0
update-initramfs: Generating /boot/initrd.img-5.5.0
run-parts: executing /etc/kernel/postinst.d/unattended-upgrades 5.5.0 /boot/vmlinuz-5.5.0
run-parts: executing /etc/kernel/postinst.d/update-notifier 5.5.0 /boot/vmlinuz-5.5.0
run-parts: executing /etc/kernel/postinst.d/xx-update-initrd-links 5.5.0 /boot/vmlinuz-5.5.0
I: /boot/initrd.img.old is now a symlink to initrd.img-5.11.0-34-generic
I: /boot/initrd.img is now a symlink to initrd.img-5.5.0
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 5.5.0 /boot/vmlinuz-5.5.0
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
正在生成 grub 配置文件 ...
找到 Linux 镜像:/boot/vmlinuz-5.11.0-34-generic
找到 initrd 镜像:/boot/initrd.img-5.11.0-34-generic
找到 Linux 镜像:/boot/vmlinuz-5.11.0-27-generic
找到 initrd 镜像:/boot/initrd.img-5.11.0-27-generic
找到 Linux 镜像:/boot/vmlinuz-5.5.0
找到 initrd 镜像:/boot/initrd.img-5.5.0
Found memtest86+ image: /boot/memtest86+.elf
Found memtest86+ image: /boot/memtest86+.bin
完成

修改grub配置文件,使得开机进入grub选择界面。

gedit /etc/default/grub
# 开机的时候,显示grub引导界面。默认停留10秒。超过10秒没有选择之后,默认选择第一个进入启动项。
# 注释掉 GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=10

sudo update-grub

开机在引导界面的高级选项中,选择需要的内核版本,进入系统。更多内容,可参考:How can I boot with an older kernel version?

在这里插入图片描述


为调试内核做的准备工作

  1. 添加内核调试信息的编译选项
    make defconfig O=../linux_image/5.5
    
    	Kernel hacking  --->
        Compile-time checks and compiler options  --->  
            [*] Compile the kernel with debug info
    
  2. 关闭地址随机化。类似于qemu-system-x86_64-append 'nokaslr' \
    sudo gedit /etc/default/grub
    # 在GRUB_CMDLINE_LINUX_DEFAULT或GRUB_CMDLINE_LINUX中,添加nokaslr
    # 我的配置是
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    GRUB_CMDLINE_LINUX="locale=zh_CN nokaslr"  <----------nokaslr为后期添加
    

错误处理

  1. recipe for target 'certs' failed

    参考:Attempting to compile kernel yields a certification error

    .config 中的CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem",修改为CONFIG_SYSTEM_TRUSTED_KEYS=""

    我不知道为什么需要这么修改,但确实是有效。

  2. warning: the frame size of 1072 bytes is larger than 1024 bytes

    参考:安卓驅動編譯warning: the frame size of 1072 bytes is larger than 1024 bytes

    这是一个警告,我并没有修改它。这里仅记录下。

  3. 使用make defconfig默认生成的配置文件,编译安装之后的启动,在了"ubuntu loading initial ramdisk",卡住。

    关于initial ramdisk的相关内容,可参考:initrd 的重要性与创建新 initrd 文件-鸟哥私房菜

    我们在本章稍早之前『会需要initrd 的原因,是因为核心模块放置于/lib/modules/$(uname -r)/kernel/ 当中, 这些模块必须要根目录(/) 被挂载时才能够被读取。但是如果核心本身不具备磁碟的驱动程序时, 当然无法挂载根目录,也就没有办法取得驱动程序,因此造成两难的地步。

    initrd 可以将/lib/modules/… 内的『启动过程当中一定需要的模块』包成一个文件(档名就是initrd), 然后在启动时透过主机的INT 13 硬件功能将该文件读出来解压缩,并且initrd 在内存内会模拟成为根目录, 由于此虚拟文件系统(Initial RAM Disk) 主要包含磁碟与文件系统的模块,因此我们的核心最后就能够认识实际的磁碟, 那就能够进行实际根目录的挂载啦!

    系统在"ubuntu loading initial ramdisk"处停住,无法进入系统。可能是,使用默认配置编译生成的内核,initrd.img中缺少一些进入系统的必要模块。

    所以,这里,我使用当前系统内核的配置来编译生成新的内核:cp /boot/config-$(uname -r) ../linux_image/.config。编译安装之后,顺利进入新内核的系统。


参考链接

Compiling a Custom Linux Kernel on a Virtual Machine

linux内核实验环境搭建

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

da1234cao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值