前言
网上关于在aarch64的qemu虚拟机使用的磁盘镜像中使用grub的文章较少,我自己摸索了一下
环境信息
ubuntu22.04
qemu-8.1.5
linux-6.6.57
本文所用内容已上传github,文章全部内容均在arco-qemu/arco-virt路径下
github仓库地址:https://github.com/ARCO-D/arco-qemu
系列文章
QEMU入门1:ubuntu22.04搭建QEMU运行环境
QEMU入门2:使用qemu简单的运行一个aarch64 linux内核
QEMU入门3:制作initrd、根文件系统
grub简介
嵌入式系统的话,一般是uboot引导内核
如果是服务器芯片的话,比较常见的就是UEFI+grub引导
grub就相当于bootloader
编译grub
需要有交叉编译工具链,没工具链不用看了,依赖项配的人想s
制作交叉编译工具链
编译依赖项
grub-2.06
efibootmgr-18
efivar-39
popt-1.18
pkg-config简介
通过xxx.pc文件来查找库的位置(大概吧
编译说明
虽然放到这里有点晚了,但还是要说明下为什么不直接在宿主机上搞——x86的ubuntu上直接执行报错缺arm64的某些模块,apt install也只能装x86的,难绷。
编译popt
(它是efivar的依赖项)
popt是有configure的,指定prefix到交叉编译工具链的…/sysroot/usr目录就行了
编译efivar
(它是efibootmgr的依赖项)
这什么老古董的配置方式(真老古董啊,现在的潮流是meson+ninja)
它指定编译器的配置在src/include/default.mk文件里,这里配置了CC加上CROSS_COMPILE前缀
emm,有个小问题,在make的时候中通过make DESTDIR=…指定DESTDIR不生效,我不知道是为啥
所以我手动编辑了src/Makefile,在前几行指定了
DESTDIR = /home/arco/x-tools/aarch64-arco-linux-gnu/aarch64-arco-linux-gnu/sysroot
注意:通过Make指定的DESTDIR只到sysroot,通过configure指定的需要到sysroot/usr这一层
编译efibootmgr
(不编译efibootmgr也能编grub,但是运行不起来,所以还是得编)
首先,需要导出两个环境变量,EFIDIR是后面会用到的EFI分区的路径,PKG这个是指定pkg-config搜索的路径(不指定的话他又会去搜索系统默认的那堆x86的了
export EFIDIR=/boot/efi
export PKG_CONFIG_PATH="/home/arco/x-tools/aarch64-arco-linux-gnu/aarch64-arco-linux-gnu/sysroot/usr/lib/pkgconfig"
然后,它也是个老古董
它指定编译器的配置方式在Make.defaults里(有些项目是Make.rules)
也默认指定了CROSS_COMPILE前缀,make就行
编译grub
终于。。。我们可以编译grub了,编的人都麻了。。。
不过要说依赖地狱还得是systemd,一个接一个的依赖,还有要处理版本匹配关系
1、下载grub2.06
gnu grub下载地址
不要下载2.12,2.12的归档文件里缺东西,必须要git才行,我很烦且不理解这种行为
2、编译
./configure --prefix=/home/arco/x-tools/aarch64-arco-linux-gnu/aarch64-arco-linux-gnu/sysroot --host=x86_64 --build=aarch64-arco-linux-gnu --with-platform=efi
–with-platform=efi(我已经忘记这是啥了,加上吧)
编译efivars.ko
grub需要这个
linux-6.6.57版本的内核中这个驱动叫efivarfs.ko了,不过没关系,编出来能插就行
安装grub
划EFI分区
这一步需要说明下:网上的示例大部分都是直接使用真实磁盘,没有这个动作
但我这dd出来的空文件哪有这个,得自己划:
参考 划分带分区的文件系统镜像
脚本示例:
mkdir rootfs
# create empty image file
dd if=/dev/zero of=arco.img bs=1024k count=2048
echo "n
p
1
+100M
n
p
2
+1800M
t
1
ef
w
"| fdisk arco.img
lof=`losetup -f`
# p1 is for uefi, p2 is for rootfs
echo "free loop device:$lof"
losetup -P $lof arco.img
mkfs.vfat -F32 "${lof}p1"
mkfs.ext4 "${lof}p2"
mount "${lof}p2" rootfs
启动
进入系统,安装grub
insmod efivarfs.ko
mount -t efivarfs efivarfs /sys/firmware/efi/efivars/
grub-install --efi-directory=/boot/efi --target arm64-efi /dev/vda1
mkdir /boot/efi/EFI/BOOT
cp /boot/efi/EFI/grub/grubaa64.efi /boot/efi/EFI/BOOT/BOOTAA64.EFI
–efi-directory指定的是EFI分区的根目录,这个我挂载的就是/boot/efi,而不是/boot(ubuntu22.04也是,照着搞总没错的)
注意: aarch64的UEFI并不会去查找grubaa64.efi这个文件,它识别的名称是BOOTAA64.EFI
记得sync
更改qemu启动脚本
我之前的启动脚本是:
../build/qemu-system-aarch64 \
-nographic \
-M virt \
-cpu cortex-a55 \
-smp 4 \
-m 1G \
-bios edk2-aarch64-code.fd \
-kernel Image-6.6.57 \
-initrd initrd.cpio.gz \
-append "root=/dev/ram0 console=ttyAMA0 init=/linuxrc ignore_loglevel nokaslr" \
-drive file=arco.img,if=none,id=sdc,format=raw \
-device virtio-blk-device,drive=sdc \
-netdev tap,id=n1,ifname=tap0,script=qemu-ifup,downscript=qemu-ifdown \
-net nic,model=virtio-net-pci,netdev=n1 \
-s
但这样不是通过UEFI启动的,qemu自带的bootloader貌似不会读EFI分区,而是直接加载内核
所以想通过grub启动需要改一下:
../build/qemu-system-aarch64 \
-nographic \
-M virt \
-cpu cortex-a55 \
-smp 4 \
-m 1G \
-bios edk2-aarch64-code.fd \
-net none \
-drive file=arco.img,if=none,id=sdc,format=raw \
-device virtio-blk-device,drive=sdc \
-netdev tap,id=n1,ifname=tap0,script=qemu-ifup,downscript=qemu-ifdown \
-net nic,model=virtio-net-pci,netdev=n1 \
-s
取消了对kernel、initrd的指定,加上了和-bios和-net参数(防止通过PXE启动)
进入grub!
这里进入的还是grub命令行(grub菜单参见下一段)

通过linux、initrd指定文件位置,然后执行boot引导
(和uboot有点像嗷)
配置grub菜单
更改etc/grub.d/下的配置文件
暂时没深入了解,写个简单的示例(两个略微不同版本的内核来回切):
首先把两个内核的Image放到磁盘镜像的/boot目录下(我这里是6.6.57和6.6.63)
然后编辑40_custom和41_custom两个文件
## 40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry "arco-linux-6.6.57" {
set root=(hd0,msdos2)
linux /boot/Image-6.6.57 root=/dev/ram0 console=ttyAMA0 init=/linuxrc ignore_loglevel nokaslr
initrd /boot/initrd.cpio.gz
}
## 41_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry "arco-linux-6.6.63" {
set root=(hd0,msdos2)
linux /boot/Image-6.6.63 root=/dev/ram0 console=ttyAMA0 init=/linuxrc ignore_loglevel nokaslr
initrd /boot/initrd.cpio.gz
}
grub配置文件不是直接修改grub.cfg来的,而是通过编辑etc/grub.d下的这些配置文件,然后grub-mkconfig生成的:
grub-mkconfig -o /boot/grub/grub.cfg
再次重启,就可以看到像装了双系统那样,熟悉的grub菜单啦

6891

被折叠的 条评论
为什么被折叠?



