综述
LinuxBoot是一个开源的固件,用来替代UEFI BIOS加载Linux的系统。
官网是LinuxBoot。
对应的代码库位于LinuxBoot · GitHub。
另外,本文是在【UEFI实战】LinuxBoot简介基础上完成的,增加了编译和执行部分。
基础
先通过几张图来说明LinuxBoot的基础。
这里实际上将固件分为了两个部分,分别是:
-
用于处理特定硬件的部分; -
通用部分(Linux部分);
第一部分,因为CPU和PCH等都是特定厂商的,因此需要特定的初始化代码来完成这些组件的初始化,这个部分可以是原来就有的东西,比如UEFI的PEI阶段,coreboot的romstage阶段、SBL的Stage 1B阶段,等等。
第二部分实际上就是一个Linux的内核加文件系统,它在平台初始化之后加载,由于这些部分是通用的,原始的Linux代码就可以完成操作,因此在官网的开始就直接了当的写了:不要重复造轮子。
上图的前面部分实际上是Intel的PI规范中定义的BIOS启动各个阶段,原始的是这样的:
也就是说LinuxBoot替代了UEFI启动过程中DXE之后的阶段,前面的两个图表达的意思其实是一样的:LinuxBoot可以认为是跑一部分SI(Silicon Initialization)代码然后加载LinuxBoot内核再加载真正的内核。
优缺点
优点主要来自Linux代码的引入:
- 可复用的代码增加;
- 安全性的提高;
- 启动速度提高(这个存疑,其实没有完整的验证数据)。
缺点:
使用
下载源码:
git clone https://gitee.com/mirrors/LinuxBoot.git
此外,代码还依赖于额外的内容,这里简单介绍。
额外依赖
kernel
内核会被包含到linuxboot.rom中,所以首先需要编译出内核。
注意编译内核的时候需要增加配置:CONFIG_EFI_BDS=y(在LinuxBoot的README中是这个,但是实际上需要使用的是CONFIG_EFI_STUB=y ,该选项的作用是使UEFI可以直接启动内核而不需要BootLoader)。
内核编译成功之后可以在arch/x86/boot目录下找到,将文件bzImage放到LinuxBoot的根目录下。
这里需要注意的是由于linuxboot.rom的二进制大小有限,以及EDK的二进制的特性,必须保证bzImage足够小,这依赖于对内核的剪裁,不过这不在本文的讨论范围内。
u-root
u-root是嵌入式的root文件系统,配合Linux内核使用,作为Linux的initramfs。
它是由Go语言写的,不过实现的内容还是普通的root文件系统的CONFIG_EFI_STUB=y内容。
包括一系列标准的Linux命令,比如ls、cp等。
对应的代码:
git clone https://gitee.com/jiangwei0512/u-root.git
下载对应的代码到LinuxBoot目录,然后进入到u-root目录,之后就需要go编译器的操作了:
- 下载安装go;
- 通过go下载u-root命令,下载成功之后如下所示:
jw@X1C:~/code/linux-boot/u-root$ ls $GOPATH/bin
u-root
下载可能会遇到问题,可以更新代理:
jw@X1C:~/code/linux-boot/u-root$ go env -w GO111MODULE=on
jw@X1C:~/code/linux-boot/u-root$ go env -w GOPROXY=https://goproxy.cn,direct
- 在u-root目录下执行u-root命令:
jw@X1C:~/code/linux-boot/u-root$ u-root core
19:49:18 Disabling CGO for u-root...
19:49:18 Build environment: GOARCH=amd64 GOOS=linux GOROOT=/usr/local/go GOPATH=/home/jw/go CGO_ENABLED=0
19:49:18 WARNING: You are not using one of the recommended Go versions (have = go1.19, recommended = [go1.17]).
Some packages may not compile.
Go to https://golang.org/doc/install to find out how to install a newer version of Go,
or use https://godoc.org/golang.org/dl/go1.17 to install an additional version of Go.
19:49:18 NOTE: building with the new gobusybox; to get the old behavior check out commit 8b790de
19:49:18 Skipping package "cmds/core/bind": no buildable Go source files in /home/jw/code/linux-boot/u-root/cmds/core/bind
19:49:18 Skipping package "cmds/core/bind": no buildable Go source files in /home/jw/code/linux-boot/u-root/cmds/core/bind
19:49:39 Successfully built "/tmp/initramfs.linux_amd64.cpio" (size 12668312).
完成之后将/tmp/initramfs.linux_amd64.cpio压缩拷贝到LinuxBoot的根目录,并重命名为initrd.cpio.xz,压缩命令:
xz --check=crc32 -9 --lzma2=dict=1MiB --stdout /tmp/initramfs.linux_amd64.cpio | dd conv=sync bs=512 of=/tmp/initramfs.linux_amd64.cpio.xz
busybox
u-root是LinuxBoot推荐的initramfs,但是实际上它还是太大了,后面编译linuxboot.rom的时候会因为尺寸太大而编译出错,这里这里推荐另外的initramfs,即使用busybox创建的initramfs。
可以在Index of /downloads下载到busybox的源码,这里下载的是1.29.1版本,解压到指定的目录:
tar -xjvf busybox-1.29.2.tar.bz2 -C /home/jw/code
然后进入该目录进行配置(在源代码目录下执行make menuconfig):
我们这里需要配置的是选择静态编译,位置在Settings项下。需要注意为了使用menuconfig,可能需要安装额外的库(libncurses5-dev )。配置之后就可以使用make 进行编译。编译完成之后通过make install 命令进行安装:
make install
执行上述命令之后,会在当前目录生成一个新的目录称为_install,我们需要这些文件生成initramfs,供内核使用,对应的文件如下:
jw@X1C:~/code/busybox-1.29.2$ ls _install/
bin linuxrc sbin usr
创建initramfs的方法,这里使用最简单的,对应的命令如下:
mkdir initramfs
cd initramfs
mkdir dev proc sys
cp ../_install/* ./ -ra
sudo cp -a /dev/{null,console,tty1,tty2,tty3,tty4} dev/
touch init
chmod a+x init
其中init 的内容如下:
mount -t proc none /proc
mount -t sysfs none /sys
mdev -s
exec /sbin/init
最后再通过如下的命令打包:
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
不过最后还需要改名为initrd.cpio.xz,并放到LinuxBoot的根目录。
cpu
cpu更像是一个SSH,也是用Go语言实现的。
对应的代码下载:
git clone https://gitee.com/jiangwei0512/cpu.git
相关的代码已经都上传至:
https://gitee.com/jiangwei0512/linux-boot.git
edk
这里使用可以通过QEMU测试的LinuxBoot,所以它依赖于OVMF,所以需要下载edk,可以使用默认的github代码:
# If the edk2 directory doesn't exist, checkout a shallow branch of it
# and build the various Dxe/Smm files
edk2/.git:
git clone --depth 1 --branch UDK2018 https://github.com/linuxboot/edk2
但是因为网络问题,也可以使用gitee版本:
https://gitee.com/jiangwei0512/edk2.git
需要将代码下载到LinuxBoot根目录,并重命名为edk2。
默认情况下LinuxBoot使用的是UDK2018版本:
# If the edk2 directory doesn't exist, checkout a shallow branch of it
# and build the various Dxe/Smm files
edk2/.git:
git clone --depth 1 --branch UDK2018 https://github.com/linuxboot/edk2
编译会使用到的dsc是MdeModule.dsc和OvmfPkgX64.dsc,对应到Makefile里面:
# 位于boards/qemu/Makefile.board:
# We can build a firmware image from edk2
# it is not necessary to provide one
boards/$(BOARD)/$(BOARD).rom: edk2/.git
( cd edk2/OvmfPkg ; ./build.sh )
cp edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd $@
# 位于Makefile:
$(EDK2_OUTPUT_DIR)/DxeCore.efi: edk2/.git
$(MAKE) -C edk2
编译
进入LinuxBoot根目录并执行make :
jw@X1C:~/code/linux-boot$ make
./bin/create-ffs -o build/qemu/Initrd.ffs --name Initrd --version 1.0 --type FREEFORM --depex "" --guid "74696e69-6472-632e-7069-6f2f62696f73" initrd.cpio.xz
./bin/create-fv \
-v \
-o build/qemu/dxe.vol \
--size 0xA00000 \
--compress 0 \
build/qemu/DxeCore.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/fc510ee7-ffdc-11d4-bd41-0080c73c8881.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/d93ce3d8-a7eb-4730-8c8e-cc466a9ecc3c.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/6c2004ef-4e0e-4be4-b14c-340eb4aa5891.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/80cf7257-87ab-47f9-a3fe-d50b76d89541.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/b601f8c4-43b7-4784-95b1-f4226cb40cee.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/f80697e9-7fd6-4665-8646-88e33ef71dfc.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/13ac6dd0-73d0-11d4-b06b-00aa00bd6de7.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/245CB4DA-8E15-4A1B-87E3-9878FFA07520.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/a19b1fe7-c1bc-49f8-875f-54a5d542443f.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/1a1e4886-9517-440e-9fde-3be44cee2136.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/C190FE35-44AA-41A1-8AEA-4947BC60E09D.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/f6697ac4-a776-4ee1-b643-1feff2b615bb.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/11a6edf6-a9be-426d-a6cc-b22fe51d9224.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/128fb770-5e79-4176-9e51-9bb268a17dd1.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/93b80004-9fb3-11d4-9a3a-0090273fc14d.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/4b28e4c7-ff36-4e10-93cf-a82159e777c5.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/c8339973-a563-4561-b858-d8476f9defc4.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/378d7b65-8da9-4773-b6e4-a47826a833e1.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/f099d67f-71ae-4c36-b2a3-dceb0eb2b7d8.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/ad608272-d07f-4964-801e-7bd3b7888652.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/42857f0a-13f2-4b21-8a23-53d3f714b840.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/9b680fce-ad6b-4f3a-b60b-f59899003443.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/348c4d62-bfbd-4882-9ece-c80bb1c4783b.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/96b5c032-df4c-4b6e-8232-438dcf448d0e.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/f9d88642-0737-49bc-81b5-6889cd57d9ea.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/4110465d-5ff3-4f4b-b580-24ed0d06747a.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/9622e42c-8e38-4a08-9e8f-54f784652f6b.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/49970331-e3fa-4637-9abc-3b7868676970.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/7e374e25-8e01-4fee-87f2-390c23c606cd.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/bdce85bb-fbaa-4f4e-9264-501a2c249581.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/7C04A583-9E3E-4F1C-AD65-E05268D0B4D1.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/d9dcc5df-4007-435e-9098-8970935504b2.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/2ec9da37-ee35-4de9-86c5-6d9a81dc38a7.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/8657015b-ea43-440d-949a-af3be365c0fc.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/733cbac2-b23f-4b92-bc8e-fb01ce5907b7.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/22dc2b60-fe40-42ac-b01f-3ab1fad9aad8.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/fe5cea76-4f72-49e8-986f-2cd899dffe5d.ffs build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/cbd2e4d5-7068-4ff5-b462-9822b4ad8d60.ffs dxe/linuxboot.ffs build/qemu/Linux.ffs build/qemu/Initrd.ffs
Can't open build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/245CB4DA-8E15-4A1B-87E3-9878FFA07520.ffs: 没有那个文件或目录 at ./bin/create-fv line 69, <> chunk 8.
Can't open build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/C190FE35-44AA-41A1-8AEA-4947BC60E09D.ffs: 没有那个文件或目录 at ./bin/create-fv line 69, <> chunk 10.
Can't open build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/1/7C04A583-9E3E-4F1C-AD65-E05268D0B4D1.ffs: 没有那个文件或目录 at ./bin/create-fv line 69, <> chunk 29.
build/qemu/dxe.vol: 0x0071ed2e out of 00a00000 bytes in FV
alignment attribute 05
alignment attribute 05
alignment attribute 05
alignment attribute 05
./bin/create-ffs \
--compress \
--type FIRMWARE_VOLUME_IMAGE \
build/qemu/rom/0x00084000/9e21fd93-9c72-4c15-8c4b-e77f1db2d792/0.fv build/qemu/dxe.vol build/qemu/qemu.txt \
| ./bin/create-fv \
--size 0x748000 \
-o build/qemu/merged.vol
alignment attribute 05
cat > build/qemu/linuxboot.rom.tmp build/qemu/rom/0x00000000.fv build/qemu/merged.vol build/qemu/rom/0x007cc000.fv
mv build/qemu/linuxboot.rom.tmp build/qemu/linuxboot.rom
可以看到编译能够成功,不过还是会有报错。这是因为某些EDK模块并不存在,查看boards/qemu/image-files.txt文件可以看到这些模块是什么:
245CB4DA-8E15-4A1B-87E3-9878FFA07520 Legacy8259
C190FE35-44AA-41A1-8AEA-4947BC60E09D Timer
7C04A583-9E3E-4F1C-AD65-E05268D0B4D1 Shell
前面两个是必须的,并且在OvmfPkgX64.dsc中已经编译进去了,但是由于GUID不对(整个都不对或者大小写不对)导致异常,这里修改如下:
这样就不会报错了。
执行
使用QEMU执行编译出来的linuxboot.rom,可以直接执行如下命令:
make run
实际真正的命令就是QEMU操作:
jw@X1C:~/code/linux-boot$ make run
qemu-system-x86_64 \
-machine q35,smm=on \
-global ICH9-LPC.disable_s3=1 \
-global driver=cfi.pflash01,property=secure,value=on \
--serial stdio \
-drive if=pflash,format=raw,unit=0,file=build/qemu/linuxboot.rom
结果如下:
可以看到BIOS已经启动完成,不过内核启动还存在问题,一直是黑屏,应该是剪裁出问题了,这个需要后续解决,由于Linux水平有限,暂时不再这里讨论。
|