Gentoo genkernel

在解决 Gentoo Linux在MacBook Pro配置Wifi 安装 net-wireless/broadcom-sta ( Broadcom 的私有 wl 驱动),需要完成内核编译。为了方便完成内核编译,按照推荐先安装 sys-kernel/genkernel ,然后使用这个工具来完成自动的内核编译

genkernel 是一个由Gentoo创建的用于自动化完成 Kernel Atlasinitramfs 构建的工具:

  • 配置内核源代码

  • 编译压缩的内核 bzImage 并复制到 /boot

  • 创建 initramfs 并复制到 /boot

  • /boot 中创建软链接

  • 添加指向initramfs的定制内容,例如加密相关文件,启动splash图像,扩展模块等

  • 配置bootloader来启动新创建的kernel和initramfs

备注

genkernel 并不是 “自动” 生成自定义内核配置,它只是自动执行内核构建过程并组装initramfs,所以并不会生成自定义配置文件。

如果没有提供内核配置,那么 genkernel 将使用 “通用内核配置” (generic kernel configuration) 文件,来生成适合日常使用的通用内核(代价就是非常大的模块化内核)

genkernelinitramfs 也是如此: initramfs 主要用途 是 调用挂载包含根文件系统的块设备,以便能够尽快将控制权转交给真实的系统(磁盘上的操作系统)

安装

  • 安装 genkernel :

安装 genkernel
emerge --ask sys-kernel/genkernel

使用

genkernel 的大多数选线可以在 /etc/genkernel.conf 配置,或者通过 genkernel 命令参数传递。通过命令行参数传递的选项优先级高于配置文件

内核源代码

  • 首先在系统中安装内核源代码:

Gentoo安装内核源代码
emerge --ask sys-kernel/gentoo-sources

备注

在MacBook Pro上安装Gentoo Linux 安装的内核是 Distribution Kernel ,也就是通用的(庞大的) sys-kernel/gentoo-kernel 。需要注意这个 sys-kernel/gentoo-kernel 也是源代码,只不过gentoo为原生内核源代码打过补丁,并且每次(重新)安装 sys-kernel/gentoo-kernel 都会全面重新编译一次内核,这个内核编译是不需要任何人工干预的,编译生成的是最通用的内核。类似于其他发行版,如 Ubuntu Linux 安装的发行版内核

  • 编辑 /etc/genkernel.conf 参考注释修改配置参数:

修改 /etc/genkernel.conf
# 在编译内核前先运行 'make menuconfig' 以便微调配置
MENUCONFIG="yes"

# 内核编译前不执行 'make mrproper'
# 有关 make clean, make mrproper 和 make distclean 区别参考 https://blog.csdn.net/yi412/article/details/34900267
MRPROPER="no"

# 编译并发通常设置 <number of processors>*<number of cores per processor>+1
# 默认配置 MAKEOPTS="$(portageq envvar MAKEOPTS)" 就可以,能够自动计算出系统cpu core数量,除非你想限制少用一些cpu core

# Add LVM support: 我使用ZFS,所以去掉了LVM支持
LVM="no"

# Add LUKS support: Linux Unified Key Setup(LUKS) 是加密存储子系统 dm-crypt 所需,我没有用
LUKS="no"

# Add DMRAID support: device-mapper raid 我没有使用
DMRAID="no"

# Include busybox in the initramfs. If included, busybox is rebuilt
# if the cached copy is out of date.
BUSYBOX="yes"

UDEV="yes"

# Add MDRAID support: 我不使用software raid
MDADM="no"

# Add firmware(s) to initramfs
FIRMWARE="no"
  • 执行创建内核:

编译内核
genkernel all

采用 在MacBook Pro上安装Gentoo Linux 同样的 efibootmgr 设置启动,不过需要注意内核名称稍微有所调整(因为编译配置时修改了后缀名):

MacBook Air 13” Mid 2013 设置efibootmgr,启动 genkernel 新编译的内核
efibootmgr --disk /dev/sda --part 1 --create --label "Gentoo Linux" --loader /vmlinuz-6.1.67-gentoo-x86_64 --unicode \
    'root=PARTUUID=1c16164d-fab1-49f8-8d95-7c7dd02ec8ed rw initrd=\initramfs-6.1.67-gentoo-x86_64.img' --verbose

报错: failed to compile the “prepare” target

首次使用 genkernel all 遇到报错:

报错信息
*         >> Kernel config was not modified!
* ERROR: compile_generic() failed to compile the "prepare" target!
* Please consult '/var/log/genkernel.log' for more information and any
* errors that were reported above.
*
* Report any genkernel bugs to bugs.gentoo.org and
* assign your bug to genkernel@gentoo.org. Please include
* as much information as you can in your bug report; attaching
* '/var/log/genkernel.log' so that your issue can be dealt with effectively.
*
* Please do *not* report kernel compilation failures as genkernel bugs!

检查 /var/log/genkernel.log :

genkernel.log 错误
COMMAND: nice -n10 make -j4 ARCH='x86' AS='x86_64-pc-linux-gnu-as' AR='x86_64-pc-linux-gnu-ar' CC='x86_64-pc-linux-gnu-gcc' LD='x86_64-pc-linux-gnu-ld' NM='x86_64-pc-linux-gnu-nm' OBJCOPY='x86_64-pc-linux-gnu-objcopy' OBJDUMP='x86_64-pc-linux-gnu-objdump' READELF='x86_64-pc-linux-gnu-readelf' STRIP='x86_64-pc-linux-gnu-strip' HOSTAR='x86_64-pc-linux-gnu-ar' HOSTCC='x86_64-pc-linux-gnu-gcc' HOSTCXX='x86_64-pc-linux-gnu-g++' HOSTLD='x86_64-pc-linux-gnu-ld' prepare
make[1]: *** No rule to make target 'arch/x86/entry/syscalls/syscall_32.tbl', needed by 'arch/x86/include/generated/uapi/asm/unistd_32.h'.  Stop.
make: *** [arch/x86/Makefile:242: archheaders] Error 2

* ERROR: compile_generic() failed to compile the "prepare" target!

参考 make[1]: *** No rule to make target 原因是系统中安装了两个Kernel source: 之前 在MacBook Pro上安装Gentoo Linux 安装了 Distribution Kernel ,也就是 sys-kernel/gentoo-kernel ,然后我又安装了 sys-kernel/gentoo-sources ,所以执行:

执行 eselect kernel 检查系统中内核源代码
eselect kernel list

输出显示:

执行 eselect kernel 可以看到当前内核源代码是发行版内核
Available kernel symlink targets:
  [1]   linux-6.1.67-gentoo
  [2]   linux-6.1.67-gentoo-dist *

此时检查 ls -lh /usr/src/linux 可以看到引用的是 -dist 内核:

lrwxrwxrwx 1 root root 24 Dec 17 15:22 /usr/src/linux -> linux-6.1.67-gentoo-dist

解决方法是修改 eselect kernel ,然后删除掉发行版源代码内核

修改成 kernel-srouce :

设置成 kernel-source 源代码
eselect kernel set 1

现在再次检查 eselect kernel list 输出就可以看到切换到了标准内核:

执行 eselect kernel 可以看到当前内核源代码切换到标准内核
Available kernel symlink targets:
  [1]   linux-6.1.67-gentoo *
  [2]   linux-6.1.67-gentoo-dist

此时可以手工删除 保留 /usr/src/linux-6.1.67-gentoo-dist (只要安装了 sys-kernel/gentoo-kernel 这个目录即使手工删除也会在 升级Gentoo 时重新编译 gentoo-kerenl 发行版kernel,再次生成)

升级内核

我在部署初期Gentoo提供的内核是 6.1.67 ,但是近期升级提供了 6.6.9 ,我将原先 /usr/src/linux-6.1.67-gentoo 目录下 .config 复制到新的 /usr/src/linux-6.6.9-gentoo 目录下(以便减少重新配置项),然后执行 genkernel all

调用 make menuconfig 没有问题,正常的交互界面,稍作修改后,我保存退出。此时 genkernel 开始执行下一步时候报错:

genkernel 报错显示缺少 CONFIG_MICROCODE_AMD 配置项
*         >> Re-running 'make oldconfig' due to changed kernel options ...
* ERROR: Something went wrong: Required kernel option 'CONFIG_MICROCODE_AMD' which genkernel tried to set is missing!
* Please consult '/var/log/genkernel.log' for more information and any
* errors that were reported above.
...

检查 /var/log/genkernel.log 有报错详情:

genkernel.log 日志中有关 MICROCODE 错误
#
# No change to .config
#
*         >> Invoking menuconfig ...
COMMAND: nice -n10 make -j8 -s -j1 ARCH='x86' AS='x86_64-pc-linux-gnu-as' AR='x86_64-pc-linux-gnu-ar' CC='x86_64-pc-linux-gnu-gcc' LD='x86_64-pc-linux-gnu-ld' NM='x86_64-pc-linux-gnu-nm' OBJCOPY='x86_64-pc-linux-gnu-objcopy' OBJDUMP='x86_64-pc-linux-gnu-objdump' READELF='x86_64-pc-linux-gnu-readelf' STRIP='x86_64-pc-linux-gnu-strip' HOSTAR='x86_64-pc-linux-gnu-ar' HOSTCC='x86_64-pc-linux-gnu-gcc' HOSTCXX='x86_64-pc-linux-gnu-g++' HOSTLD='x86_64-pc-linux-gnu-ld' menuconfig
*         >> Ensure that required kernel options for genkernel's initramfs usage are set ...
*                  - Option 'CONFIG_BLK_DEV_INITRD=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Option 'CONFIG_MMU=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Option 'CONFIG_SHMEM=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Option 'CONFIG_TMPFS=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Option 'CONFIG_TTY=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Option 'CONFIG_UNIX98_PTYS=y' already set in '/usr/src/linux/.config'; Skipping ...
* Determining 'BEST' compression method for initramfs using kernel config '/usr/src/linux/.config' ...
* Checking if we can use 'XZ' compression ...
* Will use 'XZ' compression -- all requirements are met!
*                  - Option 'CONFIG_RD_XZ=y' already set in '/usr/src/linux/.config'; Skipping ...
*         >> Ensure that CONFIG_LOCALVERSION is set ...
*                  - Option 'CONFIG_LOCALVERSION="-x86_64"' already set in '/usr/src/linux/.config'; Skipping ...
*         >> Ensure that required kernel options for early microcode loading support are set ...
*                  - Option 'CONFIG_MICROCODE=y' already set in '/usr/src/linux/.config'; Skipping ...
*                  - Adding option 'CONFIG_MICROCODE_AMD' with value 'y' to '/usr/src/linux/.config'...
*                  - Adding option 'CONFIG_MICROCODE_INTEL' with value 'y' to '/usr/src/linux/.config'...
*         >> Re-running 'make oldconfig' due to changed kernel options ...
COMMAND: nice -n10 make -j8 ARCH='x86' AS='x86_64-pc-linux-gnu-as' AR='x86_64-pc-linux-gnu-ar' CC='x86_64-pc-linux-gnu-gcc' LD='x86_64-pc-linux-gnu-ld' NM='x86_64-pc-linux-gnu-nm' OBJCOPY='x86_64-pc-linux-gnu-objcopy' OBJDUMP='x86_64-pc-linux-gnu-objdump' READELF='x86_64-pc-linux-gnu-readelf' STRIP='x86_64-pc-linux-gnu-strip' HOSTAR='x86_64-pc-linux-gnu-ar' HOSTCC='x86_64-pc-linux-gnu-gcc' HOSTCXX='x86_64-pc-linux-gnu-g++' HOSTLD='x86_64-pc-linux-gnu-ld' oldconfig
#
# configuration written to .config
#
*         >> Checking if required kernel options are still present ...
*                  - 'CONFIG_TMPFS' is set to 'y'
*                  - 'CONFIG_TTY' is set to 'y'
*                  - 'CONFIG_UNIX98_PTYS' is set to 'y'
*                  - 'CONFIG_MICROCODE' is set to 'y'

* ERROR: Something went wrong: Required kernel option 'CONFIG_MICROCODE_AMD' which genkernel tried to set is missing!
* Please consult '/var/log/genkernel.log' for more information and any
* errors that were reported above.

原因是 CONFIG_MICROCODE_AMDCONFIG_MICROCODE_INTEL 已经从内核中移除

解决方法

  • 传递 --microcode=none 参数给 genkernel :

genkernel --micorcode=none
genkernel all --microcode=none
  • 或者 修订 /etc/genkernel.conf 配置:

配置 /etc/genkernel.conf 设置 MICROCODE=”none”
# Add in early microcode support: this sets the kernel options for early microcode loading
# Possible values: empty/"no", "all", "intel", "amd"
#MICROCODE="all"
MICROCODE="none"

genkernel 生成 initramfs

使用 genkernel 还可以用来构建 initramfs :

使用 genkernel 工具构建 initramfs
genkernel --install initramfs

参考