linux使用自定义内核

Linux 使用自定义内核

以archlinux为例。 比如当前使用发行版archlinux

$ uname -a  
Linux archlinux 5.18.10-arch1-1 #1 SMP PREEMPT\_DYNAMIC Thu, 07 Jul 2022 17:18:13 +0000 x86\_64 GNU/Linux

内核编译

https://wiki.archlinux.org/title/Kernel_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) https://wiki.archlinux.org/title/Kernel_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)/Traditional_compilation_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

到https://www.kernel.org 下载你想使用版本的标准内核, 这里选的是tarball类型的压缩包,https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.55.tar.xz 若要查找老版本内核, 可以截取前面部分链接https://cdn.kernel.org/pub/linux/kernel/ 自行查找。

解压到用户目录(不要使用root)

cd ~/Downloads
mkdir ~/kernelBuild
mv ./linux-5.15.55.tar.xz ~/kernelBuild

tar -zxvf linux-5.15.55.tar.xz

当前运行的linux内核的配置, 应该在/proc/config路径下, 可以直接复制一份

cp /proc/config ~/kernelBuild/linux-5.15.55/

#zcat config .config
gzip -dv config.gz

编译内核

编译时间将从15分钟到超过一小时不等。这很大程度依赖于选择了多少选项/模块和处理器性能。详情参考 Makeflags.config 配置好之后,在内核目录运行:

$ make -j64

-j 参数根据你cpu情况酌情设置

可能还要执行make bzImage

编译内核模块

警告: 从这里开始,需要 root 权限执行命令,否则会失败.

编译完内核后编译模块:

# make modules_install

该命令将编译好的模块拷贝至 /lib/modules/<kernel version>-<config local version>,例如 /lib/modules/3.18.28-ARCH。这样,这些模块和那些被你电脑上其他内核使用的模块就独立开来。

编译模块前, 可能要先执行一遍 make V=1 all

sudo cp arch/x86/boot/bzImage /boot/vmlinuz-linux-5.15.55

##或者
sudo cp arch/x86_64/boot/bzImage /boot/vmlinuz-linux-5.15.55

制作初始化内存盘

初始化内存盘,是一个在真正的根文件系统可访问之前被挂载的初始化根目录文件系统。初始化内存盘(initrd)被绑定到对应的内核,且作为内核启动过程的一部分被载入。内核将该初始化内存盘(initrd)作为两阶段启动过程的一部分挂载起来,以载入模块使得真正的文件系统可用,然后得到真正的根文件系统。初始化内存盘包含实现以上过程的目录和可执行文件的最小集合,例如用来将内核模块安装到内核的insmod工具。对桌面或服务器Linux系统来说,初始化内存盘(initrd)就是一个临时的文件系统。其生命周期短暂,仅作为到真正的根文件系统的桥梁。在没有可变存储的嵌入式系统中,初始化内存盘就是永久的根文件系统。参考 Initramfs on Wikipediamkinitcpio

/boot 中的文件可以取任何名字。然而,为了方便区分,建议采取统一的命名规范,例如使用 linux<major revision><minor revision>

如果你使用LILO且其无法与内核设备映射器驱动连通,你可能需要先运行modprobe dm-mod命令。

自动生成

复制和修改 mkinitcpio preset,就能用官方内核一样的方式生成自定义内核的 initramfs 镜像。下面例子中将已有的 preset 复制到 linux-5.15.55 要使用的版本:

# cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux5.15.55.preset

针对定制内核编辑和修改此文件,ALL_kver= 应该和定制内核匹配:

/etc/mkinitcpio.d/linux-5.15.55.preset

...
ALL_kver="/boot/vmlinuz-linux-5.15.55"
...
default_image="/boot/initramfs-linux-5.15.55.img"
...
fallback_image="/boot/initramfs-linux-5.15.55-fallback.img"

用官方内核一样的方式生成 initramfs 镜像:

# mkinitcpio -p linux-5.15.55

手动方法

不使用 preset 文件,可以用 mkinitcpio 手动生成:

# mkinitcpio -k <kernelversion> -g /boot/initramfs-<file name>.img
  • -k (–kernel <kernelversion>): 生成 initramfs image 的内核版本. <kernelversion> 需要和内核源代码目录和/usr/lib/modules/下的模块目录一致.
  • -g (–generate <filename>): 要生成的 initramfs 文件。

示例:

# mkinitcpio -k linux-3.18.28 -g /boot/initramfs-linux318.img

拷贝System.map

System.map文件并非 Linux 启动必须的。它是一种“电话本”,列出内核的某够特定构建的功能。System.map 包含一张内核标识符的列表(例如函数名,变量名等等)和他们相应的地址。该“标识符到地址的映射”是用于:

  • 某些进程,像klogd, ksymoops等
  • OOPS处理程序,当内核崩溃出错信息释放到屏幕时(例如类似于内核在某个函数中崩溃了的信息)。

提示: UEFI partitions are formatted using FAT32, which does not support symlinks.

如果 /boot 支持软链接(i.e., not FAT32), 将 System.map 复制到 /boot, 然后创建 /boot/System.map 软链接到 /boot/System.map-YourKernelName:

# cp System.map /boot/System.map-YourKernelName
# ln -sf /boot/System.map-YourKernelName /boot/System.map
sudo cp System.map /boot/System.map-5.15.55
sudo ln -sf /boot/System.map-5.15.55 /boot/System.map

完成以上所有步骤之后,你的/boot目录中应该多出以下三个文件和一个软链接:

  • Kernel: vmlinuz-YourKernelName
  • Initramfs: Initramfs-YourKernelName.img
  • System Map: System.map-YourKernelName
  • System Map kernel symlink

重新生成GRUB配置文件

sudo cp /boot/grub/grub.cfg /boot/grub/grub.cfg_bak

/boot/grub/grub.cfg中复制如下启动行 (即### BEGIN /etc/grub.d/10_linux ###后面的几行)

menuentry 'Arch Linux' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-ee799581-62d3-4e97-8a1c-8d1c61d39611' {  
       load_video  
       set gfxpayload=keep  
       insmod gzio  
       insmod part_gpt  
       insmod ext2  
       search --no-floppy --fs-uuid --set=root ee799581-62d3-4e97-8a1c-8d1c61d39611  
       echo    'Loading Linux linux ...'  
       linux   /boot/vmlinuz-linux root=UUID=ee799581-62d3-4e97-8a1c-8d1c61d39611 rw  loglevel=3 quiet  
       echo    'Loading initial ramdisk ...'  
       initrd  /boot/intel-ucode.img /boot/initramfs-linux.img  
}
cd /etc/grub.d/
sudo vim 40_custom

将上面从/boot/grub/grub.cfg中复制的menuentry内容,追加到/etc/grub.d/40.custom中,稍作修改, 改为我们的linux内核版本,如下:

menuentry 'Arch Linux(linux-5.15.55)' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-ee799581-62d3-4e97-8a1c-8d1c61d39611' {  
       load_video  
       set gfxpayload=keep  
       insmod gzio  
       insmod part_gpt  
       insmod ext2  
       search --no-floppy --fs-uuid --set=root ee799581-62d3-4e97-8a1c-8d1c61d39611  
       echo    'Loading Linux linux-5.15.55 ...'  
       linux   /boot/vmlinuz-linux-5.15.55 root=UUID=ee799581-62d3-4e97-8a1c-8d1c61d39611 rw  loglevel=3 quiet  
       echo    'Loading initial ramdisk-5.15.55 ...'  
       initrd  /boot/intel-ucode.img /boot/initramfs-linux-5.15.55.img  
}

注意:不要从这里/网页直接复制, 这里可能已经自动把tab替换成了空格, 而grub好像不认前导的空格的。 直接在你电脑上复制修改对应的文件吧。

根据上面的grub配置, 重新生成grub引导条目

sudo grub-mkconfig -o /boot/grub/grub.cfg

可以看一下新引导条目和原来的有什么不同

diff /boot/grub/grub.cfg /boot/grub/grub.cfg_bak

重启试一下。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注