2200 字
11 分钟
折腾日记:把Btrfs作为ESP分区
2025-11-11

让UEFI支持btrfs

装系统的时候如果要efi启动的话,启动程序文件要放在ESP分区里,通常是FAT格式的(当然大部分电脑也支持NTFS格式的)所以如果系统分区不是这个格式的话还要专门划一个esp分区来存放EFI启动文件。显然我们Linux玩家就必须要再开一个esp分区,那么有没有办法把我们Linux的系统分区也直接作为ESP分区,一个分区搞定呢?

本文弄的是Btrfs,其它格式同理。

本文在Qemu虚拟机中折腾,使用Edk2 OVMF UEFI固件。对于真正电脑,只要胆子够大也行(手持烧录器我不怕)


我搜了一下,UEFI类似于一个操作系统,也有文件系统驱动,也能操作文件,并且Linux的引导程序对于UEFI来说就是“可执行程序”。只要UEFI能识别的都能作为ESP分区

rEFInd就有好多文件系统的驱动,去sourceforge下载refind-bin的那个就行了,找到drivers_x64文件夹里面就是文件系统驱动了

那么以下是研究过程

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
# 为了方便测试,这里把这个virtiofs文件夹通过virtiofs共享给虚拟机当ESP
mkdir -p virtiofs
/usr/lib/virtiofsd --socket-path=virtiofs.socket -o source=virtiofs -o cache=always &
@ -chardev socket,id=char1,path=virtiofs.socket -device vhost-user-fs-pci,queue-size=1024,chardev=char1,tag=virtiofs
exec eval $__ $@

那么就先加载它的驱动试试能不能用呗#

方法一:rEFInd的使命:加载UEFI驱动,然后把vmlinuz当EFI启动文件带参数启动。然后就是vmlinuz自己加载initrd自己启动了。#

方法二:手动用EFI Internal Shell加载驱动#

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看盘符(不过这盘符不是C盘D盘而是FS0)
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 <DIR> 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重新分配盘符(不过注意是重新分配:假如原来FS0是一个分区,map -r之后FS0可能是另一个分区)
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

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

那么启动ArchLinux的vmlinuz试一试呢 (是的你没看错,vmlinuz-linux也是一个EFI启动文件,它可以自己加载initrd,不过要传入参数。)

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

启动成功了 启动成功

方法三:edk2 ovmf的设置里可以设置自动加载驱动哦#

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 添加启动项#

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启动程序的参数

嘿嘿,发现这么弄确实可以启动诶~

启动成功

现在可以把启动文件放Btrfs上了,但是前提是要把Btrfs驱动放ESP分区上,那不还是要ESP分区吗

那么为什么FAT文件系统就可以直接识别呢?应该就是它固件里内置了FAT驱动。那么想办法把Btrfs驱动也给内置一下。

把驱动内置#

以前我看过别人的教程改过开机LOGO,所以我用过用UEFITool,所以现在自然想起UEFITool啦~

对了,GitHub LongSoft UEFITool Releases里面的Axx的版本好像只能看不能改,请下载0.28.0版

用UEFITool打开固件,Ctrl+F果然发现内嵌了FAT的驱动

UEFITool发现原来内嵌了FAT驱动.1CtrlF UEFITool发现原来内嵌了FAT驱动.2搜索结果

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

先研究一会,然后我发现大概是这个结构(实在不知道该怎么说这个)#

一个大东西.ffs{
类型:驱动,
XXX:XXX,
body:[
备注驱动程序名.sct{size:XXX,body:[name.text.hex]},
备注驱动版本名.sct{size:XXX,body:[version.text.hex]},
驱动程序.sct{size:XXX,body:[DXE.efi]},
其他的一些小东西.sct{size:XXX,body:[xxx.bin]},
]
}

UEFITool_ffs与sct

  • Type显示为File的就是大东西
  • Type显示为Section为小东西

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

其中这些是操作”body”

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

那就把btrfs驱动也嵌入呗#

  1. 先把一整个“大东西”导出,用16进制编辑器改个GUID(前面的字节),再找个地方把编辑后的“大东西”导入进来 UEFITool修改ffssct.1_ffs.1_导出 UEFITool修改ffssct.1_ffs.2_修改 UEFITool修改ffssct.1_ffs.3_导入

  2. 把 PE32 image section 这“小东西”的body替换成btrfs驱动(btrfs_x64.efi) UEFITool修改ffssct.2_替换DXE_EFI_PE

  3. User interface section对应右边的Text,还有Version section,好像是给自己看的(嗯好像drivers也会显示,不过那也是给自己看的嘛~),好像改不改都行,(甚至直接删掉也行),也可以导出body用16进制编辑器修改再导入

  • 改备注驱动程序名 UEFITool修改ffssct.3_修改备注_1_改备注驱动程序名.1_导出 UEFITool修改ffssct.3_修改备注_1_改备注驱动程序名.2_修改 UEFITool修改ffssct.3_修改备注_1_改备注驱动程序名.3_导入
  • 改备注驱动版本名 UEFITool修改ffssct.3_修改备注_2_改备注驱动版本名.1_导出 UEFITool修改ffssct.3_修改备注_2_改备注驱动版本名.2_修改 UEFITool修改ffssct.3_修改备注_2_改备注驱动版本名.3_导入
  1. 如果导入时导入了DXE dependency section的话要移除它,否则好像不会自动加载这个驱动了,具体这个是干嘛用的我也还没去了解

  2. 然后保存并使用修改的固件就好啦。

现在可以把btrfs就能当esp分区啦! 作为选择困难强迫症的我终于不用再纠结于系统分区的起始扇区位置哩(btrfs创建后无法移动分区起始位置), 嘻嘻我直接不分区了哈哈!

注:#

  • 这个btrfs驱动是只读的,不像FAT驱动那样是可读写的。

  • 如果加载多个同一种格式的文件系统驱动也只会有一个驱动接管分区。 rEFInd的btrfs驱动与quibble暂不兼容,会导致quibble无法启动btrfs上的windows。 quibble的btrfs驱动与Linux内核的UKI暂不兼容,会导致Linux内核的UKI功能无法按照initrd参数找到initrd。 所以假如两个都要用的话就别内置这个驱动了。

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

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

折腾日记:把Btrfs作为ESP分区
https://blog.yby1306.xyz/posts/uefi-edit-add-dxe/
作者
拨开乌云便有阳光
发布于
2025-11-11
许可协议
CC BY-NC-SA 4.0