实现卷标FS03和Fv文件显示
1.显示
在开机进入shell后,我们可以看见卷标FS01和FS02,通过执行FS01:
可进入Fv1 root目录。
再通过ls
可显示添加在Fv1中的各个文件。我们可以对各个文件进行操作。
代码实际上是实现在ShellPkg中的ls/efi.c。
但是当我们新增加一个Fv时,理应会在shell中显式卷标FS03,但是发现没有显式出来,我们无法以文件系统的方式访问Fv3上的文件。这是为什么呢?
2.依赖的协议
要实现按照文件的方式访问Fv, 我们需要实现EFI_SIMPLE_FILE_SYSTEM_PROTOCOL协议。
例如map命令的实现。遍历所有的卷标,就是遍历所有安装了gEfiSimpleFileSystemProtocolGuid协议的Fv。
//ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c
507 SHELL_STATUS
508 PerformMappingDisplay(
509 IN CONST BOOLEAN Verbose,
510 IN CONST BOOLEAN Consist,
511 IN CONST BOOLEAN Normal,
512 IN CONST CHAR16 *TypeString,
513 IN CONST BOOLEAN SFO,
514 IN CONST CHAR16 *Specific OPTIONAL,
515 IN CONST BOOLEAN Header
516 )
562 //
563 // Look up all SimpleFileSystems in the platform
564 //
565 Status = gBS->LocateHandle(
566 ByProtocol,
567 &gEfiSimpleFileSystemProtocolGuid,
568 NULL,
569 &BufferSize,
570 HandleBuffer);
571 if (Status == EFI_BUFFER_TOO_SMALL) {
572 HandleBuffer = AllocateZeroPool(BufferSize);
573 if (HandleBuffer == NULL) {
574 return (SHELL_OUT_OF_RESOURCES);
575 }
576 Status = gBS->LocateHandle(
577 ByProtocol,
578 &gEfiSimpleFileSystemProtocolGuid,
579 NULL,
580 &BufferSize,
581 HandleBuffer);
582 }
....
除此之外还依赖BlockIo协议。
总结:
如果想要某个Fv能按照文件的方式操作,或以目录的方式显示,需要给Fv 的Handle安装gEfiSimpleFileSystemProtocolGuid协议。
3. 如何给Fv安装文件系统协议
通过实现MdeModulePkg/Universal/FvSimpleFileSystemDxe模块。
可以看到该模块就实现了gEfiSimpleFileSystemProtocolGuid协议。
//edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c#464
414 EFI_STATUS
415 EFIAPI
416 FvSimpleFileSystemDriverStart (
417 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
418 IN EFI_HANDLE ControllerHandle,
419 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
420 )
421 {
...
462 Status = gBS->InstallProtocolInterface(
463 &ControllerHandle,
464 &gEfiSimpleFileSystemProtocolGuid,
465 EFI_NATIVE_INTERFACE,
466 &Instance->SimpleFs
467 );
468 ASSERT_EFI_ERROR (Status);
可以看到,上述函数是UEFI驱动模块的Start函数。
什么样的 Handle才能支持上述Start函数的运行呢,看Support函数。
382 EFI_STATUS
383 EFIAPI
384 FvSimpleFileSystemDriverSupported (
385 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
386 IN EFI_HANDLE ControllerHandle,
387 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
388 )
389 {
390 return gBS->OpenProtocol (
391 ControllerHandle,
392 &gEfiFirmwareVolume2ProtocolGuid,
393 NULL,
394 gImageHandle,
395 ControllerHandle,
396 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
397 );
398 }
也就是说,只要这个模块实现了gEfiFirmwareVolume2ProtocolGuid 协议,再添加上FvSimpleFileSystemDxe模块,就能支持EfiSimpleFileSystemProtocolGuid 文件系统协议。
我们继续看下这个文件中 FvSimpleFileSystemDriverStart 函数的实现:
414 EFI_STATUS
415 EFIAPI
416 FvSimpleFileSystemDriverStart (
417 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
418 IN EFI_HANDLE ControllerHandle,
419 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
420 )
421 {
...
434 //
435 // Open FV protocol
436 //
437 Status = gBS->OpenProtocol (
438 ControllerHandle,
439 &gEfiFirmwareVolume2ProtocolGuid,
440 (VOID **) &FvProtocol,
441 gImageHandle,
442 ControllerHandle,
443 EFI_OPEN_PROTOCOL_BY_DRIVER
444 );
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448
462 Status = gBS->InstallProtocolInterface(
463 &ControllerHandle,
464 &gEfiSimpleFileSystemProtocolGuid,
465 EFI_NATIVE_INTERFACE,
466 &Instance->SimpleFs
467 );
468 ASSERT_EFI_ERROR (Status);
所以,支持Fv文件系统协议的条件是:Fv 安装了固件卷协议gEfiFirmwareVolume2ProtocolGuid。
4.给Fv产生固件卷协议gEfiFirmwareVolume2ProtocolGuid
如何实现固件卷协议呢? Dxe Core 的FwVolBlock/ Services已经帮我们实现了。
我们主要看下DxeMain的固件卷服务中的实现。
-
ProcessFirmwareVolume服务安装gEfiFirmwareVolume2ProtocolGuid协议。
这是启动服务表中的一个服务ProcessFirmwareVolume 。
//MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c 681 CoreProcessFirmwareVolume ( 682 IN VOID *FvHeader, 683 IN UINTN Size