【UEFI实战】BIOS下支持更多的文件系统

综述

开源的EDK代码中,仅支持FAT32文件系统,包括读和写操作。

而实际的使用当中,需要支持的文件系统有很多,比如NTFS、EXT4等,通常BIOS不需要去支持写操作,但是一般的读操作最好还是能够支持一下。

GRUB是BIOS会调用的一个BootLoader,它实际上支持很多的文件系统读操作,如下图所示:

在这里插入图片描述

所以通过对GRUB进行包装,使EDK支持这些文件系统成为一种可能。事实上也已经有开源的项目支持该操作,对应代码路径是GitHub - pbatard/EfiFs: EFI FileSystem drivers

本文介绍如何将上述的项目放到EDK代码中进行编译。

编译

使用的EDK代码仓库是edk2-beni: 用于学习和验证UEFI BIOS。,对应EfiFsPkg,它依赖的GRUB代码也已经包含。

在这里插入图片描述

EfiFsPkg有独立的dsc文件可以进行编译,它包含了需要支持的库和模块:

[LibraryClasses]
  #
  # Entry Point Libraries
  #
  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
  #
  # Common Libraries
  #
  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
  # 中间略

[Components]
  EfiFsPkg/EfiFsPkg/Afs.inf
  EfiFsPkg/EfiFsPkg/Affs.inf
  # 后面略

由于编译需要一些特定的语法,所以对Visual Studio的版本有要求,这里直接使用最新的VS2022 Community版本。

编译直接使用Build.cmd脚本即可进行:

Build.cmd efifs

最终生成EFI二进制:

在这里插入图片描述

使用

这里测试ext2.efi文件,将它包含在BIOS二进制中:

FILE DRIVER = 7DDA7772-B8F5-4859-9DBA-0D6F2DBA4AF1 {
  SECTION PE32 = Build/EfiFs/$(COMPILE_DIR)/X64/ext2.efi
}

然后创建一个disk.img文件,然后将它格式化成ext4格式,执行如下的脚本:

Build.cmd start disk

执行QEMU,可以看到ext4格式的disk.img可以被识别:

在这里插入图片描述

实现原理

BIOS下文件系统的实现主要依赖于两个重要的结构体,一个是EFI_SIMPLE_FILE_SYSTEM_PROTOCOL

struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
  ///
  /// The version of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. The version
  /// specified by this specification is 0x00010000. All future revisions
  /// must be backwards compatible.
  ///
  UINT64                                         Revision;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME    OpenVolume;
};

OpenVolume()用来打开一个文件系统的根目录,得到另一个重要的结构体:

struct _EFI_FILE_PROTOCOL {
  ///
  /// The version of the EFI_FILE_PROTOCOL interface. The version specified
  /// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION.
  /// Future versions are required to be backward compatible to version 1.0.
  ///
  UINT64                   Revision;
  EFI_FILE_OPEN            Open;
  EFI_FILE_CLOSE           Close;
  EFI_FILE_DELETE          Delete;
  EFI_FILE_READ            Read;
  EFI_FILE_WRITE           Write;
  EFI_FILE_GET_POSITION    GetPosition;
  EFI_FILE_SET_POSITION    SetPosition;
  EFI_FILE_GET_INFO        GetInfo;
  EFI_FILE_SET_INFO        SetInfo;
  EFI_FILE_FLUSH           Flush;
  EFI_FILE_OPEN_EX         OpenEx;
  EFI_FILE_READ_EX         ReadEx;
  EFI_FILE_WRITE_EX        WriteEx;
  EFI_FILE_FLUSH_EX        FlushEx;
};

这里就包含了文件的相关操作,所以它是需要实现的重点,而其中就包含了GRUB的文件操作代码。

	This->RootFile->EfiFile.Open = FileOpen;
	This->RootFile->EfiFile.Close = FileClose;
	This->RootFile->EfiFile.Delete = FileDelete;
	This->RootFile->EfiFile.Read = FileRead;
	This->RootFile->EfiFile.Write = FileWrite;
	This->RootFile->EfiFile.GetPosition = FileGetPosition;
	This->RootFile->EfiFile.SetPosition = FileSetPosition;
	This->RootFile->EfiFile.GetInfo = FileGetInfo;
	This->RootFile->EfiFile.SetInfo = FileSetInfo;
	This->RootFile->EfiFile.Flush = FileFlush;
	This->RootFile->EfiFile.OpenEx = FileOpenEx;
	This->RootFile->EfiFile.ReadEx = FileReadEx;
	This->RootFile->EfiFile.WriteEx = FileWriteEx;
	This->RootFile->EfiFile.FlushEx = FileFlushEx;

FileOpen()为例:

static EFI_STATUS EFIAPI
FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
		CHAR16 *Name, UINT64 Mode, UINT64 Attributes)
{
  // 其它略

	/* Finally we can call on GRUB open() if it's a regular file */
	if (!NewFile->IsDir) {
		Status = GrubOpen(NewFile);
	}
}

可以看到其中包含了很多Grub开头的代码,它们都位于EfiFsPkg\src\grub_file.c,这里面就会调用到GRUB的代码:

EFI_STATUS
GrubOpen(EFI_GRUB_FILE *File)
{
	grub_fs_t p = grub_fs_list;
	grub_file_t f = (grub_file_t) File->GrubFile;
	grub_err_t rc;

	grub_errno = 0;
	rc = p->fs_open(f, File->path);
	return GrubErrToEFIStatus(rc);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值