[edk2-devel] [PATCH 12/13] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path

Laszlo Ersek lersek at redhat.com
Tue Mar 3 11:27:06 UTC 2020


On 03/03/20 11:18, Ard Biesheuvel wrote:
> On Tue, 3 Mar 2020 at 11:10, Laszlo Ersek <lersek at redhat.com> wrote:
>>
>> On 03/02/20 08:29, Ard Biesheuvel wrote:
>>> Linux v5.7 will introduce a new method to load the initial ramdisk
>>> (initrd) from the loader, using the LoadFile2 protocol installed on a
>>> special vendor GUIDed media device path.
>>>
>>> Add support for this to our QEMU command line kernel/initrd loader.
>>>
>>> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
>>> ---
>>>  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c   | 79 ++++++++++++++++++++
>>>  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf |  2 +
>>>  2 files changed, 81 insertions(+)
>>>
>>> diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
>>> index 77d8fedb738a..415946edf22a 100644
>>> --- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
>>> +++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
>>> @@ -13,15 +13,18 @@
>>>  #include <Guid/FileInfo.h>
>>>  #include <Guid/FileSystemInfo.h>
>>>  #include <Guid/FileSystemVolumeLabelInfo.h>
>>> +#include <Guid/LinuxEfiInitrdMedia.h>
>>>  #include <Guid/QemuKernelLoaderFsMedia.h>
>>>  #include <Library/BaseLib.h>
>>>  #include <Library/BaseMemoryLib.h>
>>>  #include <Library/DebugLib.h>
>>> +#include <Library/DevicePathLib.h>
>>>  #include <Library/MemoryAllocationLib.h>
>>>  #include <Library/QemuFwCfgLib.h>
>>>  #include <Library/UefiBootServicesTableLib.h>
>>>  #include <Library/UefiRuntimeServicesTableLib.h>
>>>  #include <Protocol/DevicePath.h>
>>> +#include <Protocol/LoadFile2.h>
>>>  #include <Protocol/SimpleFileSystem.h>
>>>
>>>  //
>>> @@ -84,6 +87,19 @@ STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath = {
>>>    }
>>>  };
>>>
>>> +STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath = {
>>> +  {
>>> +    {
>>> +      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
>>> +      { sizeof (VENDOR_DEVICE_PATH) }
>>> +    },
>>> +    LINUX_EFI_INITRD_MEDIA_GUID
>>> +  }, {
>>> +    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
>>> +    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
>>> +  }
>>> +};
>>> +
>>>  //
>>>  // The "file in the EFI stub filesystem" abstraction.
>>>  //
>>> @@ -839,6 +855,48 @@ STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
>>>    StubFileSystemOpenVolume
>>>  };
>>>
>>> +STATIC
>>> +EFI_STATUS
>>> +EFIAPI
>>> +InitrdLoadFile2 (
>>> +  IN EFI_LOAD_FILE2_PROTOCOL          *This,
>>> +  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
>>> +  IN BOOLEAN                          BootPolicy,
>>> +  IN OUT UINTN                        *BufferSize,
>>> +  IN VOID                             *Buffer OPTIONAL
>>> +  )
>>> +{
>>> +  CONST KERNEL_BLOB   *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
>>> +
>>> +  ASSERT (InitrdBlob->Size > 0);
>>> +
>>> +  if (BootPolicy) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  if (BufferSize == NULL || !IsDevicePathValid (FilePath, 0)) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  if (FilePath->Type != END_DEVICE_PATH_TYPE ||
>>> +      FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE) {
>>> +    return EFI_NOT_FOUND;
>>> +  }
>>> +
>>> +  if (Buffer == NULL || *BufferSize < InitrdBlob->Size) {
>>> +    *BufferSize = InitrdBlob->Size;
>>> +    return EFI_BUFFER_TOO_SMALL;
>>> +  }
>>> +
>>> +  CopyMem (Buffer, InitrdBlob->Data, InitrdBlob->Size);
>>> +
>>> +  *BufferSize = InitrdBlob->Size;
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC CONST EFI_LOAD_FILE2_PROTOCOL     mInitrdLoadFile2 = {
>>> +  InitrdLoadFile2,
>>> +};
>>>
>>>  //
>>>  // Utility functions.
>>> @@ -945,6 +1003,7 @@ QemuKernelLoaderFsDxeEntrypoint (
>>>    KERNEL_BLOB               *KernelBlob;
>>>    EFI_STATUS                Status;
>>>    EFI_HANDLE                FileSystemHandle;
>>> +  EFI_HANDLE                InitrdLoadFile2Handle;
>>>
>>>    if (!QemuFwCfgIsAvailable ()) {
>>>      return EFI_NOT_FOUND;
>>> @@ -989,8 +1048,28 @@ QemuKernelLoaderFsDxeEntrypoint (
>>>      goto FreeBlobs;
>>>    }
>>>
>>> +  if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
>>> +    InitrdLoadFile2Handle = NULL;
>>> +    Status = gBS->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle,
>>> +                    &gEfiDevicePathProtocolGuid,  &mInitrdDevicePath,
>>> +                    &gEfiLoadFile2ProtocolGuid,   &mInitrdLoadFile2,
>>> +                    NULL);
>>> +    if (EFI_ERROR (Status)) {
>>> +      DEBUG ((DEBUG_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
>>> +        __FUNCTION__, Status));
>>> +      goto UninstallFileSystemHandle;
>>> +    }
>>> +  }
>>> +
>>>    return EFI_SUCCESS;
>>>
>>> +UninstallFileSystemHandle:
>>> +  Status = gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,
>>> +                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
>>> +                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
>>> +                  NULL);
>>> +  ASSERT_EFI_ERROR (Status);
>>> +
>>>  FreeBlobs:
>>>    while (BlobType > 0) {
>>>      CurrentBlob = &mKernelBlob[--BlobType];
>>> diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
>>> index f4b50c265027..737f9b87a7c7 100644
>>> --- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
>>> +++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
>>> @@ -28,6 +28,7 @@ [LibraryClasses]
>>>    BaseLib
>>>    BaseMemoryLib
>>>    DebugLib
>>> +  DevicePathLib
>>>    MemoryAllocationLib
>>>    UefiBootServicesTableLib
>>>    QemuFwCfgLib
>>> @@ -42,6 +43,7 @@ [Guids]
>>>
>>>  [Protocols]
>>>    gEfiDevicePathProtocolGuid                ## PRODUCES
>>> +  gEfiLoadFile2ProtocolGuid                 ## PRODUCES
>>>    gEfiSimpleFileSystemProtocolGuid          ## PRODUCES
>>>
>>>  [Depex]
>>>
>>
>> I think this patch conflicts with your other patch:
>>
>>   [edk2-devel] [PATCH v3 2/6] OvmfPkg: add 'initrd' shell command to
>>                               expose Linux initrd via device path
>>
>> There should not be two different handles in the handle database that
>> carry the same device path (I mean "same device path" by contents, not
>> by reference).
>>
>> I believe that it's possible that the command-line specified -kernel /
>> -initrd are attempted first, but the kernel's stub returns for some
>> reason. Then the user can still go to the UEFI shell, and use the new
>> dynamic shell command. In that case I think the device path will cease
>> being unique (by contents).
>>
>> I think you can solve this as follows:
>>
>> - in both modules (this driver, and the dynamic shell command driver),
>> install a NULL protocol interface with GUID = gEfiCallerIdGuid on the
>> same handle that carries the device path and LoadFile2
>>
>> - in both modules, before you touch the handle that carries the device
>> path, try to locate it first. If it exists but doesn't carry the subject
>> module's FILE_GUID as a NULL protocol interface, we know the device path
>> was created by the "other" module, and we can bail.
>>
>> Just an idea.
>>
> 
> Thanks.
> 
> I did wonder about the rules regarding duplicates in the device path
> space. If the DXE core doesn't catch that, this seems like a gross
> oversight to me.
> 
> But it raises an interesting point: the idea is that any boot stage
> could elect to provide this interface, not just UEFI or the shell
> itself, but also shim, grub or whatever executes in between. That
> means that, in general, it should probably be the responsibility of
> the code that installs the protocol to ensure that it doesn't exist
> already.
> 
> For this code, it means it could simply install it, since it
> guarantees to execute first.
> 
> For the initrd implementation, it means we should check whether any
> other implementation exists already, which could simply be done [in
> that particular case] by locating the protocol and checking the
> address against the statically allocated one in the driver.
> 
> I am aware that both are DXE drivers, but since the dynamic shell
> command is not invoked by any driver that is invoked before EndOfDxe,
> I think the above should be sufficient.
> 

Sounds OK to me.

Thanks
Laszlo


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#55315): https://edk2.groups.io/g/devel/message/55315
Mute This Topic: https://groups.io/mt/71669026/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list