李守中

Gentoo 安装相关

Table of Contents

1. 进入 LiveCD

从 Gentoo 官方网站的资源下载页面 https://www.gentoo.org/downloads/ 下载 Boot media (LiveCD) 和 Stage archives (以仅有 systemd 标签的 Stage 包为例)。

将 LiveCD 写入 U 盘:

  • Windows 上用 Rufus 将 ISO 写入 U 盘
  • Linux 上直接运行 dd bs=4M if=<iso-file> of=/dev/<disk> status=progress oflag=sync (将 <iso-file> 替换为 LiveCD 的文件名,将 <disk> 替换为 U 盘的设备名)

注意: U 盘内数据将丢失。

将 U 盘插入物理机,进入 BIOS 后,以 UEFI 的方式启动 LiveCD。

2. 网络配置

2.1. 有线网络

如果使用拨号网络,先执行 pppoe-setup 根据提示填入对应值后,再执行 pppoe-start 进行连接。

LiveCD 默认会运行 dhcpcd 服务,如果网络环境中有 DHCP 服务那么网络会自己配好,ping 一下百度确认网络连通即可。

需要手动配置网络的,需要知道网关 IP、可用的网络地址然后执行:

# 列出所有的网卡
ip link

# 有线网卡的名称通常是 enp#s#,假设网卡名为 enp2s0
# 开启网卡
ip link set dev enp2s0 up

# 配置静态地址,假设:
# 网关 192.168.2.3
# 本机 IP 为 192.168.2.160
# 子网掩码为 255.255.255.0 (即 CIDR 为 /24)
ip addr add 192.168.2.160/24 dev enp2s0
ip route add default via 192.168.2.3 dev enp2s0

命令执行完后执行 ip a (完整写法是 ip address) 可以看到类似如下的输出:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:e0:4c:68:a8:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.160/24 brd 192.168.2.255 scope global dynamic noprefixroute enp2s0
       valid_lft 4124sec preferred_lft 3224sec
    inet6 fe80::a535:ecfb:157c:8035/64 scope link
       valid_lft forever preferred_lft forever

2.2. 无线网络

执行 iw dev 查询网卡设备, Interface 后的字符串即为无线网卡名,这里以 wlp#s# 代替。

iw dev wlp#s# scan | grep SSID 获取无线网络的 SSID。

执行 ip link set wlp#s# up 开启无线网卡设备。

开始连接无线网络:

  • 无认证的无线网络:
    • 执行 iw dev wlp#s# connect -w <ssid> 即可。需要连接后打开网页再认证的,可以在连接网络后执行 links 打开网页尝试认证
  • 使用 WEP 认证的无线网络 (基本弃用):
    • 执行 iw dev wlp#s# connect -w <ssid> key 0:<password>
    • 若密码采用 16 进制 (比如密码是 7451236985),执行 iw dev wlp#s# connect -w <ssid> key d:0:7451236985
  • 使用 WPA/WPA2/WPA3 认证的无线网络 (常用):
    • 执行 wpa_supplicant -i wlp#s# -c <(wpa_passphrase <ssid> <password>)

认证通过、连接上无线网络后,通常会被 DHCP 服务器分配一个 IP;如果没有,参考 2.1 配置一节的操作,将有线网卡的名称替换为对应无线网卡的名称即可。

2.3. DNS 配置

执行 cat /etc/resolv.conf 查看 DNS 配置,通常使用 DHCP 配置的网络会自动获取并配置 DNS。

如若输出为空,则需要手动配置地址:

# 223.5.5.5 为阿里云公共 DNS 服务器地址
echo 'nameserver 223.5.5.5' >/etc/resolv.conf

配置后 ping 百度检查网络是否连通。

3. 硬盘配置

3.1. 硬盘分区

  • 不涉及硬盘加密、RAID 和 LVM
  • 不创建 swap 分区,使用 swap file 来代替专门的分区

系统所在的硬盘 (假设为 /dev/sda) 使用 GPT 分区,分两个区:

  • 第一个分区 /dev/sda1:
    • 大小 2GiB
    • 文件系统使用 FAT32 mkfs.vfat -F 32 /dev/sda1
    • 用 fdisk 将分区标记为为 EFI System
  • 第二个分区 /dev/sda2:
    • 大小为硬盘剩余的所有空间
    • 文件系统使用 btrfs mkfs.btrfs /dev/sda2

3.2. 创建文件系统

挂载 btrfs 并建立子卷:

# 创建临时挂载目录
mkdir /mnt/btrfs

# 挂载文件系统到临时目录
mount /dev/sda2 /mnt/btrfs

# 创建子卷 (root 和 home 的数据分离)
btrfs subvolume create /mnt/btrfs/root
btrfs subvolume create /mnt/btrfs/root/home

# 取消挂载文件系统
umount /mnt/btrfs

3.3. 挂载分区

执行 blkid 获取到 /dev/sda1 和 /dev/sda2 的 UUID 后,向 /etc/fstab 写入挂载信息:

# 注意被注释的行此时应该被注释
UUID=<uuid> /mnt/gentoo          btrfs noatime,compress=zstd,space_cache=v2,subvol=/root      0 0
#UUID=<uuid> /mnt/gentoo/home     btrfs noatime,compress=zstd,space_cache=v2,subvol=/root/home 0 0
#UUID=<uuid> /mnt/gentoo/boot/efi vfat  defaults                                                   0 2

开始挂载:

  1. 执行 mount -a 将 /root 子卷挂载到 /mnt/gentoo 目录 (配置从 /etc/fstab 读到)
  2. 执行 mkdir -p /mnt/gentoo/boot/efi && mkdir /mnt/gentoo/home 为 EFI 分区 (/dev/sda1) 和 home 子卷 (btrfs 的子卷) 创建挂载点
  3. 取消 /etc/fstab 中的注释,执行 mount -a 挂载 EFI 分区和 home 子卷

4. 开放 SSH 连接 (可选)

如果有另一台 PC 的话,可以在 LiveCD 中开放 SSH 的连接权限然后在另一台机器上继续安装过程。

将 LiveCD 中的 /etc/ssh/sshd_config 中的 PermitRootLogin 和 PasswordAuthentication 的值改为 yes 后,执行 /etc/init.d/sshd restart 重启 SSH 服务。

再在 LiveCD 中执行 passwd root 给 root 用户改个密码就可以使用另一台 PC 通过 SSH 连接到 LiveCD 了。

5. 安装 stage 包

Stage 的含义是构建 Gentoo 过程中的阶段。(Gentoo 的构建工具为 Catalyst,详见 Catalyst 文档)

stage1 tar 包主要包含从 stage1 到 stage2 所需的基础二进制文件以及其依赖。

stage1 到 stage2 的过程是编译 GNU C 库、GCC 和一些其他关键的系统级程序 (这个过程叫 bootstrap)。然后再根据 USE 参数指定的依赖重新编译 stage1 tar 包中的部分文件到 stage2 中。

stage2 到 stage3 的过程是编译操作系统所需要的基础包 (执行 emerge --pretend system 可以查看哪些包在这个阶段被编译安装)。

自 2007 年 stage1 和 stage2 就不再供用户使用了。官方 wiki 中的 FAQ 也说明了 用户应从 stage3 开始构建自己的系统,而不是 stage1 ,只有 Gentoo 官方才从 stage1 开始构建,而且官方也不再提供 stage1 和 stage2 的 tar 包。

如果用户需要定制前两个阶段的行为,在用 LiveCD 启动后,可以在解压的 stage3 tar 包中修改 /var/db/repos/gentoo/scripts/bootstrap.sh 脚本的内容后,再次执行此脚本 (这个脚本中的内容就是 stage1 到 stage3 的流程)。

5.1. 校准时间

由于 Gentoo 网络基础服务使用了安全证书,如果系统时间误差较大,可能无法下载安装文件。有些软件在编译时也依赖于系统时间,错误的系统时间会导致编译失败。

执行 date 查看当前时间,如果不准的话执行 ntpd -q -g 使用时间服务器校准时间。

无法访问时间服务器时,需要使用 date <MMDDhhmmYYYY> 命令手动校准:

# MMDDhhmmYYYY 含义为两位数的月、两位数的日、两位数的小时、两位数的分钟、四位数的年连在一起
# 比如,2021 年 10 月 3 日的 13:16 被格式化为
date 100313162021

建议所有 Linux 系统使用 UTC 时间。稍后在安装期间将定义时区,这将修改时钟的显示为本地时间。

5.2. 选择 stage 包

执行 cd /mnt/gentoo 进入前面已经挂载好的要安装的系统的根目录。

执行 links https://mirrors.tuna.tsinghua.edu.cn/gentoo 并定位到 releases/amd64/autobuilds/ 目录,选择一个带有合适 profile 的 stage3 tar 包按下 d 开始下载 (文件存储再当前 bash 所处的目录下),然后继续下载以 .DIGESTS 结尾的校验值文件,完成后按下 q 退出。

鉴于许多发行版都用了 systemd,所以选择带有 systemd 标签的 stage3 继续操作。需要注意,安装好的系统也使用 systemd 而不是 openrc。比如下载的 stage3 为 stage3-amd64-systemd-20230115T170214Z.tar.xz (使用 systemd 作为初始化程序,可以运行 32 位的程序,只包含必要的系统组件),校验值文件名为 stage3-amd64-systemd-20230115T170214Z.tar.xz.DIGESTS

计算 stage3 tar 包的 SHA512 值:

# 使用 openssl 计算 SHA512
openssl dgst -r -sha512 stage3-amd64-<release>-<init>.tar.?(bz2|xz)

# 使用独立程序计算 SHA512
sha512sum stage3-amd64-<release>-<init>.tar.?(bz2|xz)

计算出的校验值与 .DIGESTS 文件中的值做比对,完全一致则表示 tar 包与 gentoo 官方发布的一致。

最后解压 stage3 tar 包:

# xpf 中
#     x 表示解包 (Extract)
#     p 表示保留权限 (Preserve permissions)
#     f 后跟被解的包的文件名
#     可以多加一个参数 v 来输出详细信息 (Verbose)
# --xattrs-include="*.*" 用于匹配要被解压出来的文件 (值表示所有文件)
# --numeric-owner 被用于确保从 tarball 中提取的文件的用户和组 ID 与
# Gentoo 团队预期的值保持一致,即使有些大胆的用户没有用 Gentoo live
tar xpf stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner

如果想对下载好的 stage3 tar 包做更加严格的验证,还要从下载 stage3 tar 包的页面中再下载以 .DIGESTS.asc 结尾的文件以校验 DIGESTS 文件:

# 导入 Gentoo Linux 的发布公钥
gpg --keyserver hkps://keys.gentoo.org --recv-keys 0x13EBBDBEDE7A12775DFDB1BABB572E0E2D182910

# 校验 DIGEST 文件
gpg --verify -o stage3-amd64-<release>-<init>.tar.?(bz2|xz).DIGESTS{,.asc}

提示 Good signature from "Gentoo Linux Release Engineering (Automated Weekly Release Key)" 则校验成功,否则说明文件有损坏或被篡改。可不理会警告。

关于 profile 的详细说明可以看 官方 wiki 中关于 Profile (Portage) 的文档 。简单来说,profile 是一个完整的系统配置集合,它不仅指定 USE , CFLAGS 和其它重要变量的默认值,还会锁定系统的包版本范围。这些设定全是由 Gentoo 的 Portage 开发者们来维护。系统安装完成后依旧可以切换到其他的 profile。但在安装过程中,只能使用官方提供的 stage3 中的 profile。

常用的 profile 标签有:

  • openrc: 表示其默认的初始化程序为 openrc (Gentoo 默认)
  • systemd: 表示其默认的初始化程序为 systemd,而不是 openrc
  • nomultilib: 表示其不包含 32 位的系统库文件,即无法执行 32 位程序 (默认不包含此标签)
  • selinux: 表示其默认包含 SELinux 相关配置,启用 SELinux
  • hardened: 表示其默认包含强化安全性相关的配置

6. 配置软件仓库镜像地址

第一步配置镜像站点的地址。

可以用官方工具选一个镜像地址,空格选中,回车保存:

mirrorselect -i -o >> /mnt/gentoo/etc/portage/make.conf

但由于众所周知的原因,该页面可能打不开,这时候需要手动写到配置文件里:

echo 'GENTOO_MIRRORS="https://mirrors.tuna.tsinghua.edu.cn/gentoo"' >>/mnt/gentoo/etc/portage/make.conf

第二部步配置 ebuild 软件仓库。

# 创建用于存放配置文件的目录
mkdir --parents /mnt/gentoo/etc/portage/repos.conf
# 复制默认的配置模板到刚刚创建的目录下。
cp /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf

编辑 /mnt/gentoo/etc/portage/repos.conf/gentoo.conf 文件将 sync-uri = ... 一行改为:

sync-uri = rsync://mirrors.tuna.tsinghua.edu.cn/gentoo-portage

7. 进入新安装环境

执行 cp --dereference /etc/resolv.conf /mnt/gentoo/etc/ 将 DNS 信息复制到新环境中。 --dereference 可以保证如果 /etc/resolv.conf 是一个符号链接的话,最终被复制的文件不是符号链接而是符号链接指向的真正的文件。

挂载必要的文件系统:

# 安装 systemd 需要 --make-rslave
mount --types proc /proc /mnt/gentoo/proc
mount --rbind /sys /mnt/gentoo/sys
mount --make-rslave /mnt/gentoo/sys
mount --rbind /dev /mnt/gentoo/dev
mount --make-rslave /mnt/gentoo/dev
mount --bind /run /mnt/gentoo/run
mount --make-slave /mnt/gentoo/run

最后 chroot 到新的环境中:

chroot /mnt/gentoo /bin/bash
source /etc/profile && export PS1="(chroot) ${PS1}"

从现在开始,所有的动作将立即在新 Gentoo Linux 环境里生效。

8. 文件系统信息

这一步要做的就是把文件系统如何挂载写入新环境的 /etc/fstab (即原来的 /mnt/gentoo/etc/fstab) 即可。

根据 挂载分区 一节提到的 fstab 文件的配置,将其挂载点修改到正常,并且取消对应注释:

# 将第二个参数 (挂载点) 修改正常即可
UUID=<uuid>	/	btrfs	defaults,noatime,compress=lzo,autodefrag,subvol=/root	0 0
UUID=<uuid>	/home	btrfs	defaults,noatime,compress=lzo,autodefrag,subvol=/root/home	0 0
UUID=<uuid>	/boot/efi	vfat	defaults	0 2

9. 配置 Portage

9.1. ebuild 数据库的安装和更新

安装 Gentoo ebuild 数据库的快照到本机:

emerge-webrsync

这个命令使用 http/ftp 协议下载数据,下载到的数据是 24 小时内最新的。如果程序在执行过程中提示找不到 /var/db/repos/gentoo 位置,可以不用理会,这个路径会被自动创建。

从现在开始,Portage 可能会提示建议运行某些更新。这是因为安装了新的 repository 快照后,Portage 发现了 stage 文件中已经安装的某些软件包有更新的版本。现在可以忽略更新提示等到 Gentoo 安装完成之后再更新。

如果需要将 repos 更新到最新版本 (1 小时内的最新数据),可以:

emerge --sync

这个命令使用 rsync 协议更新之前通过 emerge-webrsync 获得的 Gentoo ebuild 数据库到最新状态。在慢速的终端上,比如一些 framebuffer 或者串口控制台,建议使用 emerge --sync --quiet 以提升更新速度。

9.2. 阅读新闻条目

同步 ebuild 数据库时,Portage 可能会输出类似于这样的信息:

* IMPORTANT: 2 news items need reading for repository 'gentoo'.
* Use eselect news to read news items.

这个 news 是 ebuild 数据库给用户提供的重要信息。可以通过 eselect news 管理新闻条目:

  • eselect news list 显示新闻条目的预览
  • eselect news read [<number>] 阅读新闻条目,不提供 <number> 参数则默认显示所有条目
  • eselect news read --quiet 将所有新闻条目标为已读
  • eselect news purge 阅读新闻条目后删除条目,不能再次阅读

可以通过 man news.eselect 查看更多新闻阅读器的用法。

也可以通过浏览器在 Gentoo 官方的 news 页面 查看新闻。

9.3. 选择正确的 profile

在这里选择 profile 时,要确保使用与最初使用的 stage3 相同的版本 (比如 17.1)。使用 systemd 时,要确保 profile 名中包含 systemd;不使用时,则确保不包含。

执行 eselect profile list 可以看到当前可选的 profile:

$ eselect profile list
Available profile symlink targets:
  [1]   default/linux/amd64/17.1 (stable)
  [2]   default/linux/amd64/17.1/selinux (stable)
  [3]   default/linux/amd64/17.1/hardened (stable)
  [4]   default/linux/amd64/17.1/hardened/selinux (stable)
  [5]   default/linux/amd64/17.1/desktop (stable)
  [6]   default/linux/amd64/17.1/desktop/gnome (stable)
  [7]   default/linux/amd64/17.1/desktop/gnome/systemd (stable)
  [8]   default/linux/amd64/17.1/desktop/gnome/systemd/merged-usr (stable)
  [9]   default/linux/amd64/17.1/desktop/plasma (stable)
  [10]  default/linux/amd64/17.1/desktop/plasma/systemd (stable)
  [11]  default/linux/amd64/17.1/desktop/plasma/systemd/merged-usr (stable)
  [12]  default/linux/amd64/17.1/desktop/systemd (stable)
  [13]  default/linux/amd64/17.1/desktop/systemd/merged-usr (stable)
  [14]  default/linux/amd64/17.1/developer (exp)
  [15]  default/linux/amd64/17.1/no-multilib (stable)
  [16]  default/linux/amd64/17.1/no-multilib/hardened (stable)
  [17]  default/linux/amd64/17.1/no-multilib/hardened/selinux (stable)
  [18]  default/linux/amd64/17.1/no-multilib/systemd (dev)
  [19]  default/linux/amd64/17.1/no-multilib/systemd/merged-usr (dev)
  [20]  default/linux/amd64/17.1/no-multilib/systemd/selinux (exp)
  [21]  default/linux/amd64/17.1/no-multilib/systemd/selinux/merged-usr (exp)
  [22]  default/linux/amd64/17.1/systemd (stable) *
  [23]  default/linux/amd64/17.1/systemd/merged-usr (stable)
  [24]  default/linux/amd64/17.1/systemd/selinux (exp)
  [25]  default/linux/amd64/17.1/systemd/selinux/merged-usr (exp)
  [26]  default/linux/amd64/17.1/clang (exp)
  [27]  default/linux/amd64/17.1/systemd/clang (exp)
  [28]  default/linux/amd64/17.1/systemd/clang/merged-usr (exp)
  [29]  default/linux/amd64/17.0/x32 (dev)
  [30]  default/linux/amd64/17.0/x32/systemd (exp)
  [31]  default/linux/amd64/17.0/x32/systemd/merged-usr (exp)
  [32]  default/linux/amd64/17.0/musl (dev)
  [33]  default/linux/amd64/17.0/musl/clang (exp)
  [34]  default/linux/amd64/17.0/musl/hardened (exp)
  [35]  default/linux/amd64/17.0/musl/hardened/selinux (exp)

由于 systemd 在 2023 下半年将取消对于 split-usr/unmerged-usr system 的支持 ,而当前没有被选中的 profile 23 才包含 merged-usr,所以需要执行 eselect profile set 23 选择合适的条目。

如果安装时使用的是 split-usr/unmerged-usr profile,则在安装完成后可以根据 Gentoo 的 2022-12-01-systemd-usrmerge news 中的指导手动切换到 merged-usr:

  1. 备份系统数据
  2. 安装 sys-apps/merge-usr
  3. 以 root 用户的权限执行 merge-usr --dryrun 检查有没有文件冲突。这些冲突的内容会被输出到终端上,以 ERROR 开头。
  4. 解决冲突。这可能涉及删除重复文件。如果有疑问,可以通过 Gentoo support channel 寻求支持。
  5. 从 root shell 中执行 merge-usr 。不要用 sudo 执行脚本,如果脚本执行过程中出现问题,可能用户自己都没法切到 root 用户来修复问题。
  6. 将当前 profile 切换到正确的条目:
    • 执行 eselect profile list 显示所有的 profile
    • 执行 eselect profile set <number> 选择条目或者直接通过指定全称的方式选择 profile eselect profile set default/linux/amd64/17.1/systemd/merged-usr
  7. 执行 emerge --changed-use --deep --newuse @world 或者简写 emerge -uDN @world 来更新所有含有 split-usruse flag 的软件包。

9.4. 更新 @world set

set 是一大组软件包的便捷缩写。set 也可以作为参数传给 emerge:

# emerge -p @world 为简写
emerge --pretend @world

可以用命令查看当前有哪些 set:

$ emerge --list-sets
changed-deps
changed-subslot
deprecated-live-rebuild
downgrade
golang-rebuild
installed
live-rebuild
module-rebuild
preserved-rebuild
profile
rebuilt-binaries
rust-rebuild
security
selected
selected-packages
selected-sets
system
unavailable
unavailable-binaries
world
x11-module-rebuild

目前有 6 个 set 始终可用 (系统级的 set):

  • @selected-packages 是包含 /var/lib/portage/world 中定义的软件的 set。它是用户已明确安装的一组软件包。
  • @selected-sets 是 set 的 set。用户自定义的 set 可以被显式的合并到这个 set 中。用户自定义的 set 存储在 /var/lib/portage/world_sets 中,这个文件可能是空的,也可能不存在。
  • @selected (是前两个 set 的并集):
    • = selected-packages + selected-sets
  • @system@profile 两个 set 一同定义了 Gentoo 所需的最小软件包集合。
  • @profile@system 两个 set 一同定义了 Gentoo 所需的最小软件包集合。这两个 set 的差异在 man portage 中有记录,但这些差距对用户来说知道了也没有什么意义。组成这个 set 的包由配置文件和操作系统架构决定。
  • @world (是前三个 set 的并集)
    • = (@selected) + @system + @profile
    • = (selected-packages + selected-sets) + @system + @profile

所以更新 @world set 的意思是更新整个系统。

当系统应用了任何升级 (比如升级内核)、从任何 profile 构建了 stage3 后、应用了 USE 参数的修改后,必须更新 @world set:

emerge --ask --verbose --update --deep --newuse @world

9.5. 配置 USE 变量

USE 变量可以给程序增加或者移除某些依赖。比如,一些程序可以在编译时加入对 GTK 或 QT 的支持,一些程序可以在编译时加入或者移除对 SLL 的支持。

大多数发行版会使用尽可能多的支持特性来编译它们的软件包,这既增加了软件大小也减慢了软件的启动时间,这还没有算上可能涉及到的大量的依赖包的问题。Gentoo 可以让用户自己定义软件的编译选项,这就是 USE 变量要做的事情。

USE 变量里可以定义关键字,比如,添加 ssl 会把 SSL 编译到支持它的程序中,添加 -x (注意减号) 会在编译程序时移除 X 服务器相关的功能。

默认的 USE 设置全放在了系统所使用的 profile 的 make.defaults 文件中, find /var/db/repos/gentoo -name make.defaults 可以找到默认的配置。Gentoo 为每个 profile 使用了复杂的继承系统,这里不展开。执行 emerge --info 得到的输出中,以 USE 开头的行说明了系统当前的 USE 变量的内容。

可以在 /var/db/repos/gentoo/profiles/use.desc 中找到可用的 USE 标记的完整描述。

9.5.1. USE_EXPAND 变量 CPU_FLAGS_<ARCH>

一些架构 ( 包括 AMD64/X86、ARM、PPC) 有称为 CPU_FLAGS_<ARCH> 的 USE_EXPAND 变量 (<ARCH> 为相关的系统架构)。

这个变量用来配置用于特定的汇编代码和内置函数的编译构建,通常要么是手写的要么是额外的,并且不同于要求编译器输出针对特定 CPU 特性优化的代码的参数 (比如 -march=)。

安装读取 CPU 架构信息的包:

emerge --ask app-portage/cpuid2cpuflags

查看 CPU 架构信息:

cpuid2cpuflags

将输出写入 USE 变量的配置文件:

echo "*/* $(cpuid2cpuflags)" > /etc/portage/package.use/00cpu-flags

9.5.2. USE_EXPAND 变量 VIDEO_CARDS

VIDEO_CARDS 变量应根据使用的 GPU 进行适当配置。Xorg 指南 介绍了如何执行此操作。

仅使用控制台则不需​​要设置 VIDEO_CARDS。

9.5.3. 针对包配置 USE flag

编辑 /etc/portage/package.use/microcode 写入以下内容:

# for intel cpu microcode
sys-firmware/intel-microcode initramfs

# for amd cpu microcode
sys-kernel/linux-firmware initramfs

给这两个包都配上 initramfs 这个 USE flag 后,在更新 CPU 微码时系统会自动生成 /boot/intel-uc.img 或者 /boot/amd-uc.img 并自动重新生成对应的 initramfs。

这样以后每次微码更新时只需要执行 grub-mkconfig -o /boot/grub/grub.cfg 更新一下 GRUB 配置即可。

9.6. 配置 ACCEPT_LICENSE 变量

Gentoo 软件包的许可证存储在 ebuild 的 LICENSE 变量中。系统接受的特定许可证或许可证组在以下文件中定义。

  • profile 中的配置作用于整个系统
  • /etc/portage/make.conf 中的配置作用于整个系统,可覆盖 profile 中关于 ACCEPT_LICENSE 的配置
  • /etc/portage/package.license 作用于每个软件包 (该目录可能不存在,需要手动创建)

可以在 shell 中查看当前系统级的值:

$ portageq envvar ACCEPT_LICENSE
@FREE

给一个在 /etc/portage/make.conf 中配置全局 ACCEPT_LICENSE 的例子:

# 接受所有的 license
# 系统只由个人使用的话,这样配置比较简便
ACCEPT_LICENSE="*"

# 不接受 @FREE @BINARY-REDISTRIBUTABLE 以外的 license
ACCEPT_LICENSE="-* @FREE @BINARY-REDISTRIBUTABLE"

给一个在 etc/portage/package.license 目录下配置接受单个包的许可的例子:

# 创建 /etc/portage/package.license/kernel_and_system 文件,内容为:
app-arch/unrar unRAR
sys-kernel/linux-firmware @BINARY-REDISTRIBUTABLE
sys-firmware/intel-microcode intel-ucode

在 Gentoo 仓库中定义的许可证组,由 Gentoo Licenses project 项目管理,有:

Gentoo 官方自己维护了一个许可证组 (属于这个组的包都采用这个许可证):

  • @GPL-COMPATIBL 兼容自由软件基金会的 GPL 许可的许可,见此链接
  • @FSF-APPROVED 由 FSF 批准的自由软件许可证 (包括上一个许可 @GPL-COMPATIBLE)
  • @OSI-APPROVED 由开放源代码促进会批准的许可证,见此链接
  • @MISC-FREE 使用 Misc 许可证的软件可能是自由软件,即遵循 自由软件定义 ,但不被 FSF 或 OSI 批准
  • @FREE-SOFTWARE (包含前三个许可证) = @FSF-APPROVED + @OSI-APPROVED + @MISC-FREE
  • @FSF-APPROVED-OTHER 经 FSF 批准的「免费文档」和「除软件和文档外的实际使用作品 (包括字体)」许可证
  • MISC-FREE-DOCS 遵循 自由定义免费文档和其他作品 (包括字体) 且没有在 @FSF-APPROVED-OTHE 中列出的杂项许可
  • @FREE-DOCUMENTS (包含前两个许可证) = @FSF-APPROVED-OTHER + @MISC-FREE-DOCS
  • @FREE (包含上述所有许可证) = @FREE-SOFTWARE + @FREE-DOCUMENTS
  • @BINARY-REDISTRIBUTABLE 包括 @FREE 许可证。至少允许以二进制形式自由分发软件的许可证
  • @EULA 试图剥夺用户权力的许可协议。与 "all-rights-reserved" 和需要明确的批准相比,@EULA 有更多限制

10. 本地化配置 (systemd)

10.1. 时区 (TimeZone)

使用 systemd 时需要生成一个符号链接到正确的位置:

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

之后当 systemd 运行时,时区和相关设置可以使用 timedatectl 命令配置。

10.2. 区域 (locale)

locale 配置不仅指定了用户与系统进行交互的语言,也指定了字符串排序方式,日期和时间的显示等规则。

要分清楚两个文件:

  • /etc/locale.gen
    • 由 locale-gen 程序读取并使用
    • 这个文件应记录所有需要在系统上使用的 local 相关的配置
    • locale.gen 文件中写了的配置才被 locale-gen 编译到 /usr/lib/locale/locale-archive 中供系统读取
  • /etc/locale.conf
    • 由系统读取并使用
    • 里面记录了系统要使用的 local 相关的配置

完整的 locale.gen 可用条目的列表已在 /usr/share/i18n/SUPPORTED 文件中列出,且写在 locale.gen 中的配置条目的必须与 /usr/share/i18n/SUPPORTED 中的条目完全匹配。

/etc/locale.gen 配置条目的典型格式是:

<language>[@<modifier>][_<territory>][.<charset>] [<charset>]
  • <language> 是 ISO 639 语言代码
  • <modifier> 是修正符。用 cat 查看 /usr/share/i18n/locales/de_DE 和 cat /usr/share/i18n/locales/de_DE@euro 两个文件的内容就可以知道它们的差别在于 de_DE 用的是德国的排序和缩进等习惯,而 de_DE@euro 用的是欧洲的习惯
  • <territory> 是 ISO-3166 国家代码
  • <charset> 是 字符编码 (ISO-8859-1, UTF-8 这样的):
    • 如果配置的语言使用了默认的字符编码,则 [.<charset>] 可以省略而 [<charset>] (注意空格) 不可省。比如: zh_CN GB2312
    • 如果使用其他字符编码,则两个都不可省。比如: zh_CN.UTF-8 UTF-8

10.2.1. 生成 locale

现在向 /etc/locale.gen 写入这样的配置:

en_US.UTF-8 UTF-8
zh_CN.GBK GBK
zh_CN.UTF-8 UTF-8

执行 locale.gen 后将生成所有在 /etc/locale.gen 文件中指定的 locale 并且把他们写入到 /usr/lib/locale/locale-archive 文件中:

$ locale-gen
 * Generating 4 locales (this might take a while) with 4 jobs
 *  (1/4) Generating en_US.UTF-8 ...                                                                                                                                                                                                          [ ok ]
 *  (2/4) Generating zh_CN.GBK ...                                                                                                                                                                                                            [ ok ]
 *  (3/4) Generating zh_CN.UTF-8 ...                                                                                                                                                                                                          [ ok ]
 *  (4/4) Generating C.UTF-8 ...                                                                                                                                                                                                              [ ok ]
 * Generation complete
 * Adding locales to archive ...

locale -a 验证所选择的 locale 是否可用:

$ locale -a
C
C.utf8
en_US.utf8
POSIX
zh_CN.gbk
zh_CN.utf8

可以用 localedef 命令查看 /usr/lib/locale/locale-archive 有哪些 locale 配置:

$ localedef --list-archive
C.utf8
en_US.utf8
zh_CN.gbk
zh_CN.utf8

或者用 strings 命令显示原始数据:

$strings /usr/lib/locale/locale-archive | less

10.2.2. 设定 locale

systemd 使用 localectl 命令设置 locale。

检查可用 locale 列表:

$ localectl list-locales
C.UTF-8
en_US.UTF-8
zh_CN.UTF-8

然后设置所需的 local:

$ localectl set-locale LANG=en_US.UTF-8

最后检查结果:

$ localectl | grep "System Locale"
System Locale: LANG=en_US.UTF-8

10.3. 键盘映射 (Keymap)

键盘映射文件存储在 /usr/share/keymaps 目录下,通常一个键盘映射文件对应一个键盘布局,但一个键盘映射文件也可以包含多个布局。

常用操作有:

  • 列出所有的键盘布局: localectl list-keymaps
  • 列出所有 X11 可用的键盘布局: localectl list-x11-keymap-layouts
  • 更改控制台的键盘映射 (也会应用到 x11): localectl set-keymap <keymap>
  • 更改 x11 的键盘映射 (也会应用到控制台): localectl set-x11-keymap <keymap>
  • 更改控制台但不改变 X11 的键盘映射: localectl set-keymap --no-convert <keymap>

,- 更改 x11 但不改变控制台的的键盘映射: localectl set-x11-keymap --no-convert <keymap>

这一步可以执行 localctl set-keymap us 直接设为美式键盘布局即可。命令执行后会生成一个 /etc/vconsole.conf 文件:

$ cat /etc/vconsole.conf
KEYMAP=us

KEYMAP 变量设置了键盘映射。systemd 会在启动时加载 /etc/vconsole.conf 中的配置。如果变量 KEYMAP 没有设置,那么 us 为变量的默认值。

11. 安装固件、微代码以及内核

11.1. 安装固件和微代码

在开始配置内核部分之前,需要知道,一些设备需要在操作系统上安装额外的的固件才能正常运行。

比如,网卡设备有可能需要额外的固件才能正常运行,特别是常用于个人 PC 的无线网卡。此外,想要使用 AMD 和 Intel 出售的显卡通常也需要为系统安装额外的固件程序。

现代硬件的大多数固件都被放在 sys-kernel/linux-firmware 软件包中。如果硬件上用了 AMD 和 Intel 的显卡,最好 emerge 这个固件包,以便在配置和编译内核之前使用。

emerge --ask sys-kernel/linux-firmware

但是,如果用了 Nvidia 的显卡,那就需要参考这篇 如何给 Gentoo 安装 Nvidia 显卡驱动 的文章了。

Fuck-You-Nvidia.png

除了独立显卡硬件和网络接口之外,CPU 可能也需要固件更新。通常这种固件被称为微码。有时需要更新版本的微码来修补 CPU 硬件中的不稳定性、安全问题或其他错误。

AMD CPU 的微码更新通常与前面提到的 sys-kernel/linux-firmware 一起分发。Intel CPU 的微码可以在 sys-firmware/intel-microcode 包中找到,需要单独安装:

emerge --ask sys-firmware/intel-microcode

关于如何更新 CPU 微码的详细描述,可以参考 Gentoo 更新 CPU 微码笔记

11.2. 安装内核 (从源码安装)

11.2.1. 安装源码

通常,执行 emerge --ask sys-kernel/gentoo-kernel-bin 安装 Gentoo 官方预编译的内核就够用了。但是由于这个内核并不包含 btrfs 的驱动,所以还是需要手动编译一下内核。

给内核源码包添加对应的 USE flag:

echo "sys-kernel/gentoo-sources symlink" > /etc/portage/package.use/gentoo-sources

安装内核源码:

emerge --ask sys-kernel/gentoo-sources

这将在 /usr/src 目录下安装特定版本的 Linux kernel 源码。同时,有了 symlink 这个 flag,系统会自动生成 /usr/src/linux 这个符号链接,这个链接指向源码目录。由于源码所在目录包含 kernel 版本号,每次更新 kernel 都会更改源码所在目录的名称,所以后续主要使用 /usr/src/linux 这个符号链接来引用源码所在目录。

如果没有配置 symlink 那么默认情况下系统不会创建这个符号链接。要创建这个符号链接,除了使用 link 命令外,还可以用 eselect 的内核选择模块来操作:

$ eselect kernel list
Available kernel symlink targets:
[1]   linux-5.15.88-gentoo

$ eselect kernel set 1

$ eselect kernel list
Available kernel symlink targets:
[1]   linux-5.15.88-gentoo *

$ ls -lh /usr/src/
total 4.0K
lrwxrwxrwx 1 root root   29 Jan 24 10:22 linux -> /usr/src/linux-5.15.88-gentoo
drwxr-xr-x 1 root root 1.3K Jan 30 23:51 linux-5.15.88-gentoo

11.2.2. 手动配置

手动配置内核时,需要了解硬件的相关信息。大多数信息可以通过安装包含 lspci 命令的 sys-apps/pciutils 来收集:

emerge --ask sys-apps/pciutils

另外,在 chroot 中,可以安全的忽略任何 lspci 可能抛出的关于 pcilib 的警告。比如 pcilib: cannot open /sys/bus/pci/devices

进入内核源码目录并执行 make menuconfig ,这将启动一个配置面板:

cd /usr/src/linux
make menuconfig

Linux kernel 配置展开来可以说很多,这里只列出一些必须激活的选项:

# 基本配置
#   最后两行的选择取决于 init 系统,同时启用两种 init 系统也没坏处
Gentoo Linux --->
  Generic Driver Options --->
    [*] Gentoo Linux support
    [*]   Linux dynamic and persistent device naming (userspace devfs) support
    [*]   Select options required by Portage features
        Support for init systems, system and service managers  --->
          [*] OpenRC, runit and other script based systems and managers
          [*] systemd

# 启用 devtempfs
#   对应 /boot/config-<kernel-version>-gentoo 这个内核配置文件
#   中的 CONFIG_DEVTMPFS 和 CONFIG_DEVTMPFS_MOUNT
Device Drivers --->
  Generic Driver Options --->
    [*] Maintain a devtmpfs filesystem to mount at /dev
    [*]   Automount devtmpfs at /dev, after the kernel mounted the rootfs

# 启用 SCSI 磁盘支持 (注意 SCSI 和 SATA 没啥关系)
#   对应 CONFIG_BLK_DEV_SD
Device Drivers --->
   SCSI device support  --->
      <*> SCSI disk support

# 启用文件系统驱动
#   选上准备用的文件系统,没啥好说
File systems --->
  <*> Second extended fs support
  <*> The Extended 3 (ext3) filesystem
  <*> The Extended 4 (ext4) filesystem
  <*> XFS filesystem support
  <*> Btrfs filesystem support
  DOS/FAT/NT Filesystems  --->
    <*> MSDOS fs support
    <*> VFAT (Windows-95) fs support
  Pseudo Filesystems --->
    [*] /proc file system support
    [*] Tmpfs virtual memory file system support (former shm fs)

# 如果使用 PPP 连接到网络 (比如 PPPoE) 需要开启以下功能
#   对应 CONFIG_PPP, CONFIG_PPP_ASYNC, CONFIG_PPP_SYNC_TTY
#   即使不用也推荐选上,万一要用呢
Device Drivers --->
  Network device support --->
    <*> PPP (point-to-point protocol) support
    <*>   PPP support for async serial ports
    <*>   PPP support for sync tty ports

# 开启多核心支持
#   对应 CONFIG_SMP
Processor type and features  --->
  [*] Symmetric multi-processing support

# 开启 USB 设备支持
#   USB 键盘鼠标等都需要这里的功能
#   对应 CONFIG_HID_GENERIC and CONFIG_USB_HID, CONFIG_USB_SUPPORT,
#   CONFIG_USB_XHCI_HCD, CONFIG_USB_EHCI_HCD, CONFIG_USB_OHCI_HCD
Device Drivers --->
  HID support  --->
    -*- HID bus support
    <*>   Generic HID driver
    [*]   Battery level reporting for HID devices
      USB HID support  --->
        <*> USB HID transport layer
  [*] USB support  --->
    <*>     xHCI HCD (USB 3.0) support
    <*>     EHCI HCD (USB 2.0) support
    <*>     OHCI HCD (USB 1.1) support

# 更新 CPU 微码需要的特性
#   Intel 和 AMD 的 CPU 对应的选项很明显
#   如果以后有换另一个牌子的 CPU 的打算的话可以都选上
General setup  --->
  [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
Processor type and features  --->
  [*] CPU microcode loading support
  [*]   Intel microcode loading support
  [*]   AMD microcode loading support

下面是一些针对架构特有的配置:

# 配置 CPU 类型和功能,并启用对 32 位程序的支持
#  MCE 的作用是在硬件出现问题时通知用户
Processor type and features  --->
   [*] Machine Check / overheating reporting
   [ ]   Support for deprecated /dev/mcelog character device
   [*]   Intel MCE features
   [*]   AMD MCE features
   # 这里选择当前机器的 CPU 类型,一般来说,新机器选 Generic-x86-64
   Processor family (AMD-Opteron/Athlon64)  --->
      ( ) Opteron/Athlon64/Hammer/K8
      ( ) Intel P4 / older Netburst based Xeon
      ( ) Core 2/newer Xeon
      ( ) Intel Atom
      ( ) Generic-x86-64
Binary Emulations --->
   [*] IA32 Emulation

# 启用 GPT 硬盘格式的支持
-*- Enable the block layer --->
   Partition Types --->
      [*] Advanced partition selection
      [*] EFI GUID Partition support

# 启用对 UEFI 的支持
Processor type and features  --->
  [*] EFI runtime service support
  [*]   EFI stub support
  [*]     EFI mixed-mode support
Device Drivers
  Firmware Drivers  --->
    EFI (Extensible Firmware Interface) Support  --->
      <*> EFI Variable Support via sysfs
  Graphics support  --->
    Frame buffer Devices  --->
      <*> Support for frame buffer devices  --->
          [*]   EFI-based Framebuffer Support

选择 save 执行后再选择 exit 退出配置面板。

11.2.3. 编译和安装

退出配置面板后,开始编译:

make && make modules_install

安装内核:

make install

这将复制内核、System.map 文件和内核配置文件到 /boot 目录下。

11.2.4. 生成 initramfs (可选)

在某些情况下,需要建立一个基于内存的初始化文件系统 initramfs (initial ram-based file system)。它的存在形式是文件系统中的一个文件。最常见的原因是重要的文件系统位置(如 /usr 或 /var )在分离的分区。通过 initramfs,可以使用 initramfs 里面的工具来挂载这些分区。

如果没有 initramfs 系统可能无法正常启动,因为负责挂载文件系统的工具需要读取还没有挂载的文件系统上的信息。而 initramfs 中包含了必要的文件以解决这个问题。但也因此 initramfs 在 kernel 启动后,控制权被移交给 init 工具 (systemd/openrc) 前,才被加载进内存。

首先安装 sys-kernel/dracut 然后用它生成 initramfs:

emerge --ask sys-kernel/dracut
dracut --kver=<kernel-version>

# <kernel-version> 的值可以在 /lib/modules 中找到。比如
# $ ls -lh /lib/modules/
# total 0
# drwxr-xr-x 1 root root 464 Jan 22 21:18 5.15.88-gentoo
# 则命令为
dracut --kver=5.15.88-gentoo

initramfs 文件在 /boot 目录中,文件名以 initramfs 开头:

ls -lh /boot/initramfs*

11.2.5. 内核模块

在 /etc/modules-load.d/*.conf 文件中,每行一个,列出需要自动加载的模块,还可以在每行末尾为模块设置附加选项。

查看所有可用模块:

find /lib/modules/<kernel version>/ -type f -iname '*.o' -or -iname '*.ko' | less

比如,要自动加载 3c59x.ko 模块 (3Com 网卡的特定驱动),编辑 /etc/modules-load.d/network.conf 文件并在里面输入模块名字。实际的文件名对 loader 来说无关紧要。

$ mkdir -p /etc/modules-load.d
$ echo "3c95x" > /etc/modules-load.d/network.conf

12. 安装和配置 GRUB 引导器

引导器 (bootloader) 负责在引导过程中启动内核,若没有引导器,系统就不知道按下电源键后该干什么。

在 /etc/portage/make.conf 文件中设置 GRUB_PLATFORMS 变量可以控制 GRUB 所能支持的主板 BIOS 固件类型:

# emu: 支持模拟 (可以执行 grub-emu 在命令行模拟启动 GRUB)
# efi-32: 支持老的 MAC 主板的 BIOS
# efi-64: 支持 UEFI (系统所在的硬盘使用 GPT 格式)
# pc: 支持 UEFI legacy (系统所在的硬盘使用 MBR 格式)
GRUB_PLATFORMS="emu efi-32 efi-64 pc"

12.1. 安装 GRUB

sys-boot/grub 包已经纳入 Gentoo 系统中。可以同时安装 grub-0.97 (GRUB Legacy) 和 grub-2.02,这两个版本的 GRUB 可以同时安装在同一个系统上,建议所有系统使用 GRUB2 因为它兼容 grub-0.97。但是,一次只能在硬盘驱动器的主引导记录 (MBR) 中安装一个版本。

sys-boot/os-prober 包使得 GRUB 可以在运行 grub-mkconfig 命令时探测其他操作系统并生成启动项。在大多数情况下,这样可以让 GRUB 自动探测到各类常见的操作系统 (包括 Windows 7, Windows 8.1, 10,其他 Linux 发行版等等)。

安装 GRUB 和 os-prober:

emerge --ask --verbose sys-boot/grub sys-boot/os-prober

12.2. 配置 GRUB

12.2.1. 配置文件

/usr/sbin/grub-mkconfig

POSIX shell 脚本,不推荐修改。它是 sys-boot/grub:2 自带的一部分。配置完下面所列的文件后,运行该脚本以生成最终的 /boot/grub/grub.cfg 文件

/boot/grub/grub.cfg

GRUB shell 脚本,不推荐修改。它是由 grub-mkconfig 生成的文件,被 GRUB 内置的解析器解析,并且不必支持所有的 POSIX 命令和语法。GRUB 脚本参考文档 记录了所有支持的特性。注意,对于这个文件的修改将在下次执行 grub-mkconfig 时被覆盖。

/etc/grub.d/*

POSIX shell 脚本,可以修改。/etc/grub.d/* 下的脚本分别依次运行,其输出重定向到最终的 /boot/grub/grub.cfg 文件 (或重定向到用户在 grub-mkconfig -o 中指定的文件)。这些脚本都使用当前系统的 shell 运行,故可使用任何 shell 支持的语法。理想情况下,它们都应是 POSIX 兼容的脚本,并且其输出的脚本应与 GRUB 解释器兼容。如有必要,可禁用或增加某些脚本。例如,可增加一些不能自动生成的菜单项。

/boot/grub/custom.cfg

GRUB shell 脚本,可以修改。如果 /etc/grub.d/41_custom 脚本文件存在,将在启动时读取 /boot/grub/custom.cfg 脚本。这个脚本可以用来添加额外的项目或命令,并且不需要重新生成 /boot/grub/grub.cfg 主配置文件。

/etc/default/grub

POSIX shell 脚本,推荐修改。在多数情况下这是唯一要直接修改的文件。它主要用来为 /etc/grub.d 中的脚本提供变量赋值。涉及的变量参考 GRUB 变量配置官方文档

简单总结上面的内容: /usr/sbin/grub-mkconfig 脚本被用来生成 grub 配置。它使用 /etc/grub.d/* 中的脚本再加上 /etc/default/grub 中的配置来生成最终的 /boot/grub/grub.cfg (唯一被 GRUB 本身使用的配置文件)。

在使用软件 RAID 的情况下,grub-mkconfig 不能正常工作。这种情况下需要手动配置 /etc/grub.d 中的脚本文件,否则完成安装后系统将停留在没有引导程序的状态下。

如果修改了配置,那么在运行 grub-mkconfig 工具时要使用 -o 选项将配置输出到指定的文件:

$ grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.15.88-gentoo
Found initrd image: /boot/intel-uc.img /boot/initramfs-5.15.88-gentoo.img
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done

12.2.2. 常用配置参数

配置参数的值通常被写在 /etc/default/grub 文件中。Gentoo 文档中的 GRUB 变量文档 给出了完整的参数列表。

参数如果有更新,需要执行 grub-mkconfig 命令重新生成 GRUB 配置文件。

GRUB_DISABLE_OS_PROBER

默认值为 true ,这表示 os-prober 默认是被关闭的 (不会探测、生成其他操作系统的引导项)。

注意到上一节最后的输出提到了:

Warning: os-prober will not be executed to detect other bootable partitions. Systems on them will not be added to the GRUB boot configuration. Check GRUB_DISABLE_OS_PROBER documentation entry.

在 /etc/default/grub 中启用该功能:

GRUB_DISABLE_OS_PROBER=false

然后再次执行:

$ grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.15.88-gentoo
Found initrd image: /boot/intel-uc.img /boot/initramfs-5.15.88-gentoo.img
Warning: os-prober will be executed to detect other bootable partitions.
Its output will be used to detect bootable binaries on them and create new boot entries.
Adding boot menu entry for UEFI Firmware Settings ...
done
GRUB_DEFAULT

定义启动菜单中的默认操作系统选项。默认设置为首个检测到的操作系统入口。可以是数字索引 (从 0 计数)、菜单标题、id 或者 saved

GRUB_DEFAULT=savedGRUB_SAVEDEFAULT=true 一同使用可以记忆上次启动时使用的选项,并从该选项启动。

使用 id 指定默认的启动项:

# /boot/grub/grub.cfg
...
menuentry 'Example GNU/Linux distribution' --class gnu-linux --id example-gnu-linux {
    ...
}
...

# /etc/default/grub
GRUB_DEFAULT=example-gnu-linux

GRUB_TIMEOUT

在启动默认操作系统之前的延迟时间 (按秒计),默认值 5 秒。设置为 0 时表示立即启动,设置成 -1 时表示无限期等待用户输入。

GRUB_CMDLINE_LINUX

需要传递给内核的参数,对所有 Linux 系统入口起作用。

例如,要让系统支持休眠功能,用户应该设置 GRUB_CMDLINE_LINUX="resume=/dev/sdXY" ,其中的 /dev/sdXY 是 swap 分区。

GRUB_CMDLINE_LINUX_DEFAULT

需要传递给内核命令行的参数,仅对非 Recovery Linux 菜单项起作用。

GRUB_DEVICE

初始根设备 (类似于内核的 root= 参数)。设置该参数可以覆盖 grub-mkconfig 命令自动探测到的根设备。例如, GRUB_DEVICE=/dev/ram0 将强制在内核命令行中使用 root=/dev/ram0 作为根设备。

12.2.3. 启用或禁用配置脚本

/etc/grub.d 目录中包含了 grub-mkconfig 用来生成 grub.cfg 配置文件的一系列脚本。默认情况下,该目录中看起来应该类似于下面的内容:

$ ls /etc/grub.d/
00_header  10_linux  20_linux_xen  30_os-prober  30_uefi-firmware  40_custom  41_custom  README

在 grub-mkconfig 命令执行期间,该目录下的所有可执行文件 (权限至少为 111 的文件) 都会被执行。要禁用其中某些脚本,可以直接使用 chmod 命令清除它们的可执行权限位。

12.2.4. 调整配置脚本

一些功能或特性只能通过修改配置脚本来获得。

例如,如果要为其他操作系统添加一个启动条目,那么最好用 chainload 的方式来启动这些系统,/etc/grub.d/40_custom 中的内容应该写成这样:

# (hd0,gpt5) = (hd0,3)
# 应被换成对应系统的所在硬盘与所在分区
menuentry 'FreeBSD' {
    insmod ufs2
    set root='(hd0,gpt5)'
    chainloader /boot/loader.efi
}
menuentry 'Windows7'{
    set root=(hd0,4)
    chainloader +1
}

查看 Gentoo wiki 中的链式引导文档 以获取更多关于链式引导的信息。

12.3. 安装引导程序 (bootloader)

Linux 无法启动的修复方法 一文中说明了 MBR 和 GPT 等硬盘格式的一些基本内容。

12.3.1. UEFI 引导,使用 GPT

如果使用 UEFI-CSM,请参阅下面两节,BIOS+GPT 和 BIOS+MBR。CSM (兼容性支持模块) 是用来模拟 BIOS 行为的模块,它使 UEFI 的行为类似于 BIOS。在固件设置中,它通常被称为 Legacy Mode (传统模式) 或 Compatibility Mode (兼容模式)。UEFI-CSM 一直是可选的,并于 2020 年在主流系统 (如 PC)上逐步淘汰。

以下内容假定分区方案为 3.1 中的方案,即 ESP (EFI 系统分区) 被挂载到 /boot/efi 目录下。如果 ESP 直接挂载到了 /boot 目录下,则需要用 --efi-directory=/boot 替换命令中对应的部分。

如果 /boot 目录使用了单独的分区,需要首先挂载该分区到 /boot 目录。

复制相关文件到 /boot/grub 中并安装 bootloader 到 --efi-directory 指定的目录下:

$ grub-install --efi-directory=/boot/efi
Installation finished. No error reported.

这个命令把 GRUB 安装到 /boot/grub 目录中,同时安装 bootloader 为 /boot/efi/EFI/gentoo/grubx64.efi,最后调用 efibootmgr 命令增加一个引导入口。

grub-install 命令可以通过设置 --target 选项来设置 CPU 架构和系统平台。如果用户在命令中没有指定该值,grub-install 会试图猜测合适的值。在 AMD64 UEFI-booted 的系统上,它的默认值为 x86_64-efi 。需要注意,使用 UEFI 时 64bit 的硬件并不兼容 32bit 的 bootloader。

grub-install 命令可以通过设置 --boot-directory 选项来设置 GRUB 应从何处查找引导文件,它的默认值为 /boot (即从 /boot/grub 查找 GRUB 引导文件)。

此外,为正确安装 GRUB, EFI 目录必须正确挂载,并且必须在 grub-install 命令运行之前完成 efivars 内核模块的加载。

12.3.2. BIOS 引导,使用 GPT

它经常出现在老机器配大硬盘的组合中。

在这个组合上,GRUB 依赖于一个名为 BIOS boot partition,类型为 4 (fdisk) 或 EF02 (gdisk) 或 21686148-6449-6e6f-744e656564454649 (GUID) 的分区。通常,这个分区只需要 1 MiB 大小,但使用 2-4 MiB 的空间更加可靠。这个分区不必用文件系统将其格式化,grub-install 命令在检测到 BIOS boot partition 存在后,会自动将部分 bootloader (GRUB2 的 core.img) 按字节写入到这个分区中,所以即使这个分区上有文件系统,也会被覆盖掉。

如果 /boot 目录使用了单独的分区,需要首先挂载该分区到 /boot 目录。注意 BIOS boot partition 和 /boot 目录所在的分区不是同一个分区,且 BIOS boot partition 不应被挂载到系统中 (不应在 /etc/fstab 中有定义)。

安装 GRUB:

$ grub-install /dev/sda
Installation finished. No error reported.

同样地,grub-install 命令可以通过设置 --target 选项来设置 CPU 架构和系统平台。如果用户在命令中没有指定该值,grub-install 会试图猜测合适的值。在 AMD64/x86 (64bit/32bit) 的系统上,它的默认值为 i386-pc 。需要注意的是,与 UEFI 不同,使用 BIOS legacy 时,64bit 的硬件兼容 32bit 的 bootloader。 --boot-directory 选项可以设置 GRUB 应从何处查找引导文件,它的默认值为 /boot (即从 /boot/grub 查找 GRUB 引导文件)。

12.3.3. BIOS 引导,使用 MBR

同样地,如果 /boot 目录使用了单独的分区,需要首先挂载该分区到 /boot 目录。

应确保在首个分区前预留足够的硬盘空间: 可以将第一个分区设置为从 2048 扇区开始,以便为 core.img 预留至少 1 MB 空间。

如果有迁移硬盘格式到 GPT 的打算,一般建议 (并非强制性要求) 为 GRUB 创建一个称作 BIOS boot partitoin 的额外分区 (Gentoo 官方推荐 256MiB 大小)。只需要定义这个分区,不需要格式化。如果不准备将硬盘格式迁移到 GPT,则不需要创建这样的分区。

把 GRUB 安装到 /boot/grub 目录中,同时安装一个引导镜像文件到主引导记录 (MBR) 或某个分区的启动扇区中:

$ grub-install /dev/sda
Installation finished. No error reported.

多系统启动的配置方法也是修改 /etc/grub.d/40_custom 的内容以添加 GRUB 启动项。

12.4. 最后的配置

最后一步就是基于用户在 /etc/default/grub 文件和 /etc/grub.d 目录下的脚本文件的配置,生成最终被 GRUB 使用的配置。

除此之外,编辑 /etc/default/grub 中 GRUB_CMDLINE_LINUX 变量的内容可以指定内核参数。

要生成最终的 GRUB 配置,运行 grub-mkconfig 命令:

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

12.5. 其他说明

GRUB Legacy 的分区编号从 0 开始,GRUB2 的分区编号从 1 开始。硬盘编号都从 0 开始。

GRUB 生成的引导程序 (bootloader) 是 <EFI-partition>/EFI/gentoo/grubx64.efi,这是一个二进制文件,它包含了 GRUB 配置文件所在分区使用的文件系统的驱动,以及 GRUB 配置文件在文件系统中的位置:

$ strings /boot/efi/EFI/gentoo/grubx64.efi  | grep btrfs
btrfs
fs/btrfs.c
btrfs_header.bytenr is not equal node addr
btrfs_header.uuid doesn't match sblock uuid
too deep btrfs virtual nesting
btrfs
$ strings /boot/efi/EFI/gentoo/grubx64.efi  | tail -1
(,gpt2)/root/boot/grub

硬件自检完成后,BIOS 会从找到的第一个 EFI 分区中加载并执行 bootloader 程序 (<EFI-partition>/EFI/gentoo/grubx64.efi)。执行完 bootloader 之后,GRUB 就能找到 /boot 目录 (包含 GRUB 的附加模块、内核和 initramfs 映像) 所在的分区,并用自带的文件系统驱动读取 /boot 目录。最后 GRUB 会将内核和 initramfs 映像装载到内存中,并将控制权交接到内核。



Last Update: 2023-10-16 Mon 20:14

Generated by: Emacs 28.2 (Org mode 9.5.5)   Contact: [email protected]

若正文中无特殊说明,本站内容遵循: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议