1633 字
8 分钟
Simple Guides for Fuwari

让UEFI支持btrfs#

装系统的时候如果要efi启动的话,启动程序文件要放在FAT格式的分区(或者有的电脑也可以放在NTFS的分区里),所以如果系统盘不是这个格式的话还要专门划一个esp分区来存放EFI启动文件。那么能不能把EFI启动文件放在btrfs上呢?

我了解折腾了下,UEFI之所以好像叫什么可扩展固件接口,就是因为它可扩展,它跟操作系统有点类似(也许就是一个操作系统”),它有类似C:盘D:盘的盘符,不过叫FS0: FS1:,并且也有驱动程序并且可以加载驱动,其中就有文件系统的驱动程序,并且系统的EFI启动程序就相当于UEFI的可执行程序啦,并且还都是PE格式哦。

那么能不能加载btrfs的驱动呢?rEFInd就有好多文件系统的驱动,(没错,EFI启动程序也可以用UEFI”系统”的接口打开文件,rEFInd直接让”系统”加载了文件系统驱动然后再打开文件的,…,嗯rEFInd好像是链式启动,quibble应该就要打开文件了吧)

那么就手动加载它的驱动试试呗

qemu 启动

#!/bin/env zsh
@() { __+=" $@" ; }
@ qemu-system-x86_64
@ -m 16G -object memory-backend-file,id=mem,size=16G,mem-path=/dev/shm,share=on -numa node,memdev=mem
@ -smp cpus=8,sockets=1,cores=8,threads=1
@ -bios /usr/share/edk2/x64/OVMF.4m.fd
@ -cpu host
@ -machine q35
@ -enable-kvm
@ -netdev tap,id=netwan,ifname=qemu-tap-test,script=no,downscript=no -device virtio-net,netdev=netwan,mac=52:55:57:00:00:00
@ -drive file=.qcow2,format=qcow2
@ -boot menu=on
@ -serial stdio
@ -chardev socket,id=char1,path=virtiofs.socket -device vhost-user-fs-pci,queue-size=1024,chardev=char1,tag=virtiofs
/usr/lib/virtiofsd --socket-path=virtiofs.socket -o source=virtiofs -o cache=always &
exec eval $__ $@

windows有cmd,linux下有bash,zsh,UEFI下也有个EFI Internal Shell的程序 启动efishell.1 启动efishell.2

UEFI Interactive Shell v2.2

EDK II

UEFI v2.70 (EDK II, 0x00010000)

Mapping table

FS0: Alias(s):F1:
PciRoot(0x0)/Pci(0x3,0x0)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
BLK1: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)

Press ESC in 1 seconds to skip startup.nsh or any other key to continue.

Shell>

mode 调整分辨率

Shell> mode

Available modes for console output device.

Col 80 Row 25

Col 100 Row 31 *

Shell> mode 100 31

map看盘符

Shell> map

Mapping table

FS0: Alias(s):F1:
PciRoot(0x0)/Pci(0x3,0x0)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
BLK1: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)

dirls命令能看到里面的文件

Shell> ls fs0:

Directory of: fs0:\

01/01/1970 00:00

r 0 .

01/01/1970 00:00 62,840 btrfs_x64.efi

01/01/1970 00:00 12,477 NvVars

2 File(s) 75,317 bytes
1 Dir(s)

load加载驱动

Shell> load fs0:\btrfs_x64.efi

Image ‘FS0:\btrfs_x64.efi’ loaded at 7D7F1000 - Success

drivers查看加载的驱动列表

Shell> drivers

DRVVERSIONTYPECFGDING#D#CDRIVER NAMEIMAGE NAME
5E0000000AB--17PCI Bus DriverPciBusDxe
6000000010?----Virtio PCI DriverVirtioPciDeviceDxe
6100000010D--1-Virtio 1.0 PCI DriverVirtio10
6200000010?----Virtio Block DriverVirtioBlkDxe
6300000010?----Virtio SCSI Host DriverVirtioScsiDxe
6400000010?----Virtio Serial DriverVirtioSerialDxe
650000000AD--2-Platform Console Management DriverConPlatformDxe
660000000AD--2-Platform Console Management DriverConPlatformDxe
670000000AB--22Console Splitter DriverConSplitterDxe
680000000A?----Console Splitter DriverConSplitterDxe
690000000A?----Console Splitter DriverConSplitterDxe
6A0000000AB--22Console Splitter DriverConSplitterDxe
6B0000000AB--11Console Splitter DriverConSplitterDxe
6F0000000AD--1-Graphics Console DriverGraphicsConsoleDxe
700000000AB--11Serial Terminal DriverTerminalDxe
710000000AD--2-Generic Disk I/O DriverDiskIoDxe
720000000B?----Partition Driver(MBR/GPT/El Torito)PartitionDxe
750000000AB--11SCSI Bus DriverScsiBus
760000000AD--1-Scsi Disk DriverScsiDisk
770000000AD--1-Sata Controller Init DriverSataController
7800000010D--1-AtaAtapiPassThru DriverAtaAtapiPassThruDxe
7900000010B--11ATA Bus DriverAtaBusDxe
7A00000010?----NVM Express DriverNvmExpressDxe
7B00000010B--13OVMF Sio Bus DriverSioBusDxe
7C0000000AB--11PCI SIO Serial DriverPciSioSerialDxe
7D0000000AD--1-PS/2 Keyboard DriverPs2KeyboardDxe
800000000A?----FAT File System DriverFat
8100000010?----UDF File System DriverUdfDxe
8200000010D--1-Virtio Filesystem DriverVirtioFsDxe
850000000A?----Simple Network Protocol DriverSnpDxe
860000000AB--11VLAN Configuration DriverVlanConfigDxe
870000000AB--13MNP Network Service DriverMnpDxe
880000000AB--11ARP Network Service DriverArpDxe
890000000AB--12DHCP Protocol DriverDhcp4Dxe
8A0000000AB--212IP4 Network Service DriverIp4Dxe
8B0000000AB--712UDP Network Service DriverUdp4Dxe
8C0000000AB--22MTFTP4 Network ServiceMtftp4Dxe
8D0000000AB--12DHCP6 Protocol DriverDhcp6Dxe
8E0000000AB--212IP6 Network Service DriverIp6Dxe
8F0000000AB--610UDP6 Network Service DriverUdp6Dxe
900000000AB--11MTFTP6 Network Service DriverMtftp6Dxe
910000000AB--81UEFI PXE Base Code DriverUefiPxeBcDxe
920000000AB--71UEFI PXE Base Code DriverUefiPxeBcDxe
9500000000D--1-DNS Network Service DriverDnsDxe
9600000000D--1-DNS Network Service DriverDnsDxe
970000000AD--1-HttpDxeHttpDxe
980000000AD--1-HttpDxeHttpDxe
990000000AB--21UEFI HTTP Boot DriverHttpBootDxe
9A0000000AB--31UEFI HTTP Boot DriverHttpBootDxe
9B0000000AD--1-iSCSI DriverIScsiDxe
9C0000000AD--1-iSCSI DriverIScsiDxe
9E00000010?----Virtio Network DriverVirtioNetDxe
9F00000020?----Usb Uhci DriverUhciDxe
A000000030?----Usb Ehci DriverEhciDxe
A100000030?----Usb Xhci DriverXhciDxe
A20000000A?----Usb Bus DriverUsbBusDxe
A30000000A?----Usb Keyboard DriverUsbKbDxe
A400000011?----Usb Mass Storage DriverUsbMassStorageDxe
A500000010B--11QEMU Video DriverQemuVideoDxe
A600000010?----Virtio GPU DriverVirtioGpuDxe
A700000010?----Virtio Random Number Generator DrivVirtioRngDxe
A80000000AB--34TCP Network Service DriverTcpDxe
A90000000AB--34TCP Network Service DriverTcpDxe
B5017D5C56B--221af41000.efidrvOffset(0x10E00,0x273FF)
FF00000010D--1-rEFInd 0.14.2 btrfs File System Dri\btrfs_x64.efi

map -r重设盘符

Shell> map -r

Mapping table

FS1: Alias(s):F1:
PciRoot(0x0)/Pci(0x3,0x0)
FS0: Alias(s):F0a65535a:;BLK0:
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
BLK1: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF

可以看到文件系统被识别了 (当然盘符也重新分配了)

那么运行一下呢 (没错,这里的程序也可以有命令行参数哦)

Shell> fs0:

FS0:> boot\vmlinuz-linux initrd=boot\initramfs-linux-fallback.img root=UUID=59004200-5900-3100-3300-300036000000 rw splash

启动成功了 启动成功

edk2ovmf的设置里可以设置自动加载驱动哦 edk2自动加载驱动1 edk2自动加载驱动2 edk2自动加载驱动3 edk2自动加载驱动4 edk2自动加载驱动5 edk2自动加载驱动6 edk2自动加载驱动7

既然开机会自动识别btrfs文件系统,那么把btrfs上的EFI启动程序添加到启动列表呢

edk2添加启动项.1 edk2添加启动项.2 edk2添加启动项.3 edk2添加启动项.4 edk2添加启动项.5 edk2添加启动项.6 edk2添加启动项.7

或者进linux后运行 efibootmgr -c -d /dev/sda -L 'Arch Linux' -l '/boot/vmlinuz-linux' --unicode "initrd=/boot/initramfs-linux-fallback.img root=UUID=59004200-5900-3100-3300-300036000000 rw splash" # -p 1

  • -c代表创建
  • -d后面是硬盘
  • -p是分区数,如果没有分区就没有p参数
  • -L名称
  • -l文件路径(对于分区而言),会自动转换斜杠
  • --unicode 给EFI启动程序的参数

正常启动

启动成功

但是这个驱动还是要在别的分区上的才能被加载

那么为什么FAT文件系统就可以直接识别呢?

UEFITool打开固件,发现原来内嵌了FAT的驱动

UEFITool发现原来内嵌了FAT驱动

那么怎么把btrfs驱动也内嵌进入呢?

发现这里相当于结构体,有属性和内容

UEFITool右键菜单

其中这些是操作”结构体”

  • Extract as is… Ctrl+E
  • Insert into… Ctrl+l
  • Insert before… Ctrl+Alt+|
  • Insert after… Ctrl+Shift+|
  • Replace as is… Ctrl+R
  • Remove Ctrl+Del

其中这些是操作”内容”

  • Extract body… Ctrl+Shift+E
  • Replace body… Ctrl+Shift+R

然后这又相当于List与元素的区别 UEFITool_ffs与sct

  • Type显示为File(导出导入时默认为ffs后缀)的为List
  • Type显示为Section(导出导入时默认为sct后缀)的为元素

那就把btrfs驱动也嵌入呗

  1. 先把ffs结构体导出,用16进制编辑器改个GUID(前面的字节),再找个地方插入
  2. 把 PE32 image section 的内容替换成btrfs驱动
  3. User interface section对应右边的Text,还有Version section,好像是给自己看的(嗯好像drivers也会显示,不过那也是给自己看的嘛~),好像改不改都行,(好像直接删掉也行),可以导出内容用16进制编辑器修改再导入
  4. 如果有DXE dependency section的要移除,否则好像不会自动加载,具体的我也不懂

UEFITool修改ffssct.1 UEFITool修改ffssct.2 UEFITool修改ffssct.2 UEFITool修改ffssct.4 UEFITool修改ffssct.5 UEFITool修改ffssct.6 UEFITool修改ffssct.7 UEFITool修改ffssct.8 UEFITool修改ffssct.9 UEFITool修改ffssct.10

然后保存并把qemu的bios参数选择为修改的固件就可以把esp分区删了,btrfs就能当esp分区啦!连分区都不用啦!

注:

  • 这个驱动对于btrfs是只读的,不像FAT那样是可读写的。
  • 如果加载多个同一种格式的文件系统驱动也只会有一个驱动接管分区。rEFInd的btrfs驱动与quibble暂不兼容,导致quibble无法启动btrfs上的windows。quibble的btrfs驱动与Linux内核的UKI暂不兼容,导致Linux内核的UKI功能无法找到initrd参数的initrd。
注:

我在华硕和技嘉的电脑上试了,无法通过校验,无法正常刷入,需要通过BIOS FlashBack 或者用编程器刷入。

我在华硕的电脑上试了,直接开启安全启动后也能识别到btrfs分区。

Simple Guides for Fuwari
https://fuwari.vercel.app/posts/myuefi/
作者
Lorem Ipsum
发布于
2024-04-01
许可协议
CC BY-NC-SA 4.0