这篇文章上次修改于 317 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

关于环境搭建的内容请看之前的文章:折腾网络启动

编译树莓派4B的 iPXE

iPXE 有一个适配树莓派的 piPXE 仓库,但是并没有发布适配树莓派4B的 Releases,需要自己编译。

git clone https://github.com/ipxe/pipxe.git

修改Makefile将所有的 RPi3 替换为 RPi4

修改IPXE_TGT的值为 bin-arm64-efi/snp.efi

git submodule update --init --recursive

更新子模块

vim ipxe/src/config/general.h

修改 iPXE 的配置文件,开启nfsmenu功能,也可以开启你需要的功能

...
#define    DOWNLOAD_PROTO_NFS    /* Network File System Protocol */
...
    
...
#define    PXE_MENU        /* PXE menu booting */
...

开始编译

make

我在编译的时报出codecs.lookup('ucs-2') LookupError: unknown encoding: ucs-2的错误,看样子是 edk2 与 python3.9 兼容性还有点问题,我的办法是去下载 edk2 stable 版本 relsease 进行替换

mv edk2 edk2.old
wget https://github.com/tianocore/edk2/releases/download/edk2-stable202111/edk2-edk2-stable202111.zip
unzip edk2-edk2-stable202111.zip
mv edk2-edk2-stable202111 edk2

这样编译就能过了

编译好的文件在ipxe\src\bin-arm64-efi\snp.efi

嫌麻烦可以用我编译好的固件

创建 Archlinuxarm 客户端系统

首先需要创建 Archlinuxarm 系统 SD 卡,然后在树莓派上,修改系统。我尝试通过 chroot 的方法修改系统,但是测试引导没有成功。

将系统安装到 SD 卡的方法就不演示了,直接看官网说明

官网只提供了一个根目录压缩包,没有 IMG 镜像,这很 Arch(Windows用户震怒

记得使用 AArch64 版本,ARMv7 版本没有 vmlinux 文件,iPXE 引导可能会有问题

修改系统

将 SD 卡插入树莓派,启动系统

修改方法和上一篇文章基本一致,修改 mkinitcpio 让其支持 NFS 网络启动

pacman -S mkinitcpio-nfs-utils nfs-utils
vim /etc/mkinitcpio.conf
......
MODULES=(nfs broadcom)

BINARIES=(/usr/bin/mount.nfs)

HOOKS=(base udev autodetect modconf block filesystems keyboard fsck net)
......

生成initramfs

mkinitcpio -c /etc/mkinitcpio.conf -g /boot/initramfs-linux.img -k 5.15.1-1-ARCH

使用 ls /usr/lib/modules 查看当前系统的可用内核

如果出现找不到 fsck.nfs 的错误,可以在配置文件中关闭fsck 这个 HOOKS,重新生成。

开启 dhcp 服务,修改fstab关闭本地挂载

 systemctl enable dhcpcd
 vim /etc/fstab

服务端配置

DHCP 和 TFTP

将编译好的树莓派4B版 iPXE 传输到 TFTP 文件夹下

修改dnsmasq.conf,添加 aarch64 iPXE 引导支持

...

dhcp-match=set:aarch64,option:client-arch,11
dhcp-match=set:aarch32,option:client-arch,10

dhcp-boot=tag:aarch64,ipxe/bootaa64.efi

# 建议将这个条目放在底部
dhcp-boot=tag:ipxe,ipxe/boot.ipxe

NFS 服务

把 SD 卡中的系统导出为.img镜像文件,传输到服务器(将内存卡挂载也可以)

挂载镜像

mkdir archlinuxarm-mount
losetup -P /dev/loop0 archlinuxarm-copy.img 
mount /dev/loop0p2 archlinuxarm-mount/
mount /dev/loop0p1 archlinuxarm-mount/boot/

修改 NFS 服务配置,让其支持 mount 的文件夹

vim /etc/exports
/data/boot/    192.168.xx.0/24(rw,sync,no_root_squash,crossmnt)

重启服务

systemctl restart nfs-kernel-server

修改 boot.ipxe (iPXE MENU)

添加启动项

...
item --key r nfs_raspi_netboot (R)ArchlinuxARM NetBoot NFS
...
...
:nfs_raspi_netboot
echo Boot Raspberry Pi NETBOOT
set server_ip 192.168.xx.xx
set nfs_path /data/boot/archlinuxarm-mount
kernel nfs://${server_ip}${nfs_path}/boot/Image
initrd nfs://${server_ip}${nfs_path}/boot/initramfs-linux.img
imgargs Image initrd=initramfs-linux.img nfsroot=${server_ip}:${nfs_path} netboot=nfs ip=dhcp rootwait
boot || goto failed

然后就可以使用 iPXE 强大的引导功能了,这也是我折腾 UEFI+iPXE 启动的原因之一(主要是想给吃灰派找点事干

...
chain --autofree https://boot.netboot.xyz

通过 UEFI 启动 iPXE

树莓派4B 内嵌了一块小EEPROM,可以在没有内存卡下工作,但是需要特定的 PXE 环境引导(之后会讲到)

为了让其兼容 iPXE 需要一张内存卡,让 UEFI 使用通用的 PXE 加载 iPXE

下载 Raspberry Pi 4 UEFI Firmware Images ,删除原来 boot 分区的文件,将 UEFI Images 的文件解压到这里

将 SD 卡插入树莓派,UEFI 没有检测到本地系统便会开始尝试 PXE 引导

丢掉 SD 卡,尝试无盘启动

树莓派4B 的EEPROM在没有检测到内置储存的时候便会尝试进行网络启动。这样就可以在没有内存卡下运行系统,方便做多节点部署,节省一点买内存卡的钱。

首先更新系统,同时会更新 EEPROM 中的固件

sudo apt update && sudo apt full-upgrade

使用Raspbian查看本机的序列号

cat /proc/cpuinfo
....
Hardware    : BCM2835
Revision    : d03114
Serial        : 10000000xxxxxxxx #最后8位
Model        : Raspberry Pi 4 Model B Rev 1.4

在 TFTP 共享文件夹目录创建以树莓派序列号最后8位的文件夹

然后将内存卡 boot 分区的文件复制到这个文件夹下

cd tftproot
mkdir xxxxxxxx #树莓派序列号后8位
cd xxxxxxxx

wget https://github.com/pftf/RPi4/releases/download/v1.32/RPi4_UEFI_Firmware_v1.32.zip
unzip RPi4_UEFI_Firmware_v1.32.zip
# 我这里直接下载UEFI,懒得传了

修改 dnsmasq.conf ,添加以下内容:

...
pxe-service=0,"Raspberry Pi Boot" 
# 使用了这条配置BIOS PXE启动方式好像会失效

把内存卡拔下,通电开机试试

无盘启动 Raspbian

树莓派 UEFI 固件现在对树莓派硬件支持并不完整,比如不能支持 WIFI 等,如果要使用完整的功能就需要使用官方提供的方式引导。

首先把 SD 卡中的系统导出为.img镜像文件,传输到服务器(和上面一致)

挂载镜像

mkdir raspbian-mount
losetup -P /dev/loop1 raspbian-copy.img 
mount /dev/loop1p2 raspbian-mount/
mount /dev/loop1p1 raspbian-mount/boot/

删除 TFTP 文件夹内树莓派序列号文件夹的内容,然后将 Raspbian 系统内存卡的 boot 分区内的文件复制过去

cd tftproot/
mv xxxxxxxx xxxxxxxx-uefi #xxxxxxxx是树莓派序列号后8位
mkdir xxxxxxxx && cd xxxxxxxx
sftp [email protected]
get -R /data/boot/raspbian-mount/boot/* ./

修改 cmdline.txt 让内核在启动时通过 nfs 挂载根目录

console=serial0,115200 console=tty1 rw root=/dev/nfs nfsroot=192.168.xx.xx:/data/boot/raspbian-mount,v4,tcp ip=dhcp elevator=deadline rootwait

记得修改fstab关闭本地挂载,以免启动报错

参考

Raspberry pi无盘网络启动(network booting)
Network Booting
PXE无盘启动树莓派集群
How can I mount a Raspberry Pi Linux distro image?
mkinitcpio (简体中文))
Setup armv7h chroot under x86_64 host (Archlinux/Archlinuxarm biased)
Raspberry Pi 4? #2
Raspberry Pi PXE Boot – Network booting a Pi 4 without an SD card

フィッシュル