[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