接着上一篇。Ubuntu 装在 USB 直通的外接 SSD 上,在系统里重启一切正常。等我把安装用的 ISO 和多余的虚拟盘从 UTM 里删掉,关机再开机,窗口一闪就关了,连 UEFI 的界面都没出来。
TL;DR
UTM 开机时不会自动把直通的 USB 硬盘接进虚拟机,要在菜单栏手动连接。但 Apple 的 EFI 找不到能启动的盘就直接关机,一点时间都不留。
解决办法是在 UTM 里加一块 1 GiB 的虚拟盘,里面放一个 UEFI Shell 和一个 startup.nsh。开机后虚拟机会停在 Shell 里等,这时去菜单栏把硬盘接上,脚本发现硬盘后执行 reset -w 热重启,就能进系统了。
为什么之前没发现
装系统的时候有 ISO 和安装时生成的一块小虚拟盘在,开机至少有东西可以启动,我有时间去接硬盘。装完以后的重启都是在 Ubuntu 里做的热重启,硬盘一直没断开。所以直到删掉 ISO 第一次冷启动,问题才暴露出来。
做一块启动盘
在 UTM 里给虚拟机加一块 1 GiB 的虚拟盘,然后在 Ubuntu 里给它分区、格式化,放进 Ubuntu 自带的 UEFI Shell。下面假设新盘是 /dev/vda,动手前先用 lsblk 确认一下,别把系统盘格了:
sudo apt install efi-shell-aa64 dosfstools parted
sudo parted -s /dev/vda mklabel gpt mkpart VMBOOT fat32 1MiB 100% set 1 esp on
sudo mkfs.vfat -F 32 -n VMBOOT /dev/vda1
sudo mount /dev/vda1 /mnt
sudo mkdir -p /mnt/EFI/BOOT
sudo cp /usr/share/efi-shell-aa64/shellaa64.efi /mnt/EFI/BOOT/BOOTAA64.EFI
先别急着 umount,下面的 startup.nsh 也要放进去,放完再 sudo umount /mnt。
\EFI\BOOT\BOOTAA64.EFI 是 arm64 的默认启动路径,Ubuntu 的启动项失败以后,固件会接着试其他盘,就会进到这个 Shell。
然后写 startup.nsh,在盘的根目录和 \EFI\BOOT\ 下各放一份:
@echo -off
echo "vmboot: waiting for the USB system disk"
for %r run (1 30)
connect -r
map -r
for %f in fs0 fs1 fs2 fs3 fs4 fs5 fs6 fs7
if exist %f:\EFI\ubuntu\shimaa64.efi then
echo "vmboot: found it on %f, warm resetting"
reset -w
endif
endfor
stall 1000000
endfor
echo "vmboot: USB system disk not found, check the USB passthrough"
脚本每秒重新扫描一次设备,在各个文件系统里找 Ubuntu 的 shimaa64.efi,最多等 30 秒。找到了就热重启。硬盘在热重启后还接着,这次固件的第一个启动项就是 Ubuntu,直接进系统。
30 秒内没接上也没关系,脚本结束后会停在 Shell 提示符,接上硬盘再手动敲 reset -w 就行。
这块盘 Ubuntu 用不到,不用挂载,内核和 GRUB 更新也和它没关系。/boot 和 ESP 都还在 USB 硬盘上。弄完以后 efi-shell-aa64 可以卸掉。
为什么不直接从 Shell 启动 shim
最开始的脚本是找到硬盘后直接执行 shimaa64.efi,结果卡在了这里:
efi-log.c:34@efi_assert: stubble: Assertion 'description || pcrindex == UINT32_MAX' failed at measure.c:246@tpm_log_ipl_event, halting.
stubble 是 Ubuntu arm64 内核外面包的一层 EFI stub,从 Shell 启动时,它在 TPM 度量这一步断言失败了。我翻了 Debian 的 stubble 源码,没看出空的 description 是哪来的,Ubuntu 打包的版本可能不一样,就没继续深究。改成热重启以后,Shell 不在启动链里,问题自然没了。
代价
- 每次冷启动都要去菜单栏点一次连接。
- 本来想的是带着硬盘换一台 Mac 就能开机,现在只做到一半,新 Mac 上还得带上或者重建这块启动盘。好在它很简单,照上面的步骤几分钟就能做出来。
- 如果硬盘接上了,但 Ubuntu 的启动项因为别的原因启动不了,脚本会一直找到硬盘、一直热重启。这时在 UTM 里停掉虚拟机就行。