2 DXE driver to expose the 'kernel', 'initrd' and 'cmdline' blobs
3 provided by QEMU as files in an abstract file system
5 Copyright (C) 2014-2016, Red Hat, Inc.
6 Copyright (C) 2020, Arm, Limited.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Guid/FileInfo.h>
14 #include <Guid/FileSystemInfo.h>
15 #include <Guid/FileSystemVolumeLabelInfo.h>
16 #include <Guid/LinuxEfiInitrdMedia.h>
17 #include <Guid/QemuKernelLoaderFsMedia.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/BlobVerifierLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/DevicePathLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/QemuFwCfgLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
27 #include <Protocol/DevicePath.h>
28 #include <Protocol/LoadFile2.h>
29 #include <Protocol/SimpleFileSystem.h>
32 // Static data that hosts the fw_cfg blobs and serves file requests.
37 KernelBlobTypeCommandLine
,
44 FIRMWARE_CONFIG_ITEM CONST SizeKey
;
45 FIRMWARE_CONFIG_ITEM CONST DataKey
;
52 STATIC KERNEL_BLOB mKernelBlob
[KernelBlobTypeMax
] = {
56 { QemuFwCfgItemKernelSetupSize
, QemuFwCfgItemKernelSetupData
, },
57 { QemuFwCfgItemKernelSize
, QemuFwCfgItemKernelData
, },
62 { QemuFwCfgItemInitrdSize
, QemuFwCfgItemInitrdData
, },
67 { QemuFwCfgItemCommandLineSize
, QemuFwCfgItemCommandLineData
, },
72 STATIC UINT64 mTotalBlobBytes
;
75 // Device path for the handle that incorporates our "EFI stub filesystem".
79 VENDOR_DEVICE_PATH VenMediaNode
;
80 EFI_DEVICE_PATH_PROTOCOL EndNode
;
81 } SINGLE_VENMEDIA_NODE_DEVPATH
;
84 STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath
= {
87 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
88 { sizeof (VENDOR_DEVICE_PATH
) }
90 QEMU_KERNEL_LOADER_FS_MEDIA_GUID
92 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
93 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
97 STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath
= {
100 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
101 { sizeof (VENDOR_DEVICE_PATH
) }
103 LINUX_EFI_INITRD_MEDIA_GUID
105 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
106 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
111 // The "file in the EFI stub filesystem" abstraction.
113 STATIC EFI_TIME mInitTime
;
115 #define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
118 UINT64 Signature
; // Carries STUB_FILE_SIG.
120 KERNEL_BLOB_TYPE BlobType
; // Index into mKernelBlob. KernelBlobTypeMax
121 // denotes the root directory of the filesystem.
123 UINT64 Position
; // Byte position for regular files;
124 // next directory entry to return for the root
127 EFI_FILE_PROTOCOL File
; // Standard protocol interface.
130 #define STUB_FILE_FROM_FILE(FilePointer) \
131 CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
134 // Protocol member functions for File.
138 Opens a new file relative to the source file's location.
140 (Forward declaration.)
142 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
143 the file handle to the source location. This would
144 typically be an open handle to a directory.
146 @param[out] NewHandle A pointer to the location to return the opened handle
149 @param[in] FileName The Null-terminated string of the name of the file to
150 be opened. The file name may contain the following
151 path modifiers: "\", ".", and "..".
153 @param[in] OpenMode The mode to open the file. The only valid
154 combinations that the file may be opened with are:
155 Read, Read/Write, or Create/Read/Write.
157 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case
158 these are the attribute bits for the newly created
161 @retval EFI_SUCCESS The file was opened.
162 @retval EFI_NOT_FOUND The specified file could not be found on the
164 @retval EFI_NO_MEDIA The device has no medium.
165 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
166 medium is no longer supported.
167 @retval EFI_DEVICE_ERROR The device reported an error.
168 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
169 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a
170 file for write when the media is
172 @retval EFI_ACCESS_DENIED The service denied access to the file.
173 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
175 @retval EFI_VOLUME_FULL The volume is full.
181 IN EFI_FILE_PROTOCOL
*This
,
182 OUT EFI_FILE_PROTOCOL
**NewHandle
,
189 Closes a specified file handle.
191 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
194 @retval EFI_SUCCESS The file was closed.
200 IN EFI_FILE_PROTOCOL
*This
203 FreePool (STUB_FILE_FROM_FILE (This
));
209 Close and delete the file handle.
211 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
212 handle to the file to delete.
214 @retval EFI_SUCCESS The file was closed and deleted, and the
216 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
224 IN EFI_FILE_PROTOCOL
*This
227 FreePool (STUB_FILE_FROM_FILE (This
));
228 return EFI_WARN_DELETE_FAILURE
;
233 Helper function that formats an EFI_FILE_INFO structure into the
234 user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
235 KernelBlobTypeMax, which stands for the root directory).
237 The interface follows the EFI_FILE_GET_INFO -- and for directories, the
238 EFI_FILE_READ -- interfaces.
240 @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
241 blob backing the STUB_FILE that information is
242 being requested about. If BlobType equals
243 KernelBlobTypeMax, then information will be
244 provided about the root directory of the
247 @param[in,out] BufferSize On input, the size of Buffer. On output, the
248 amount of data returned in Buffer. In both cases,
249 the size is measured in bytes.
251 @param[out] Buffer A pointer to the data buffer to return. The
252 buffer's type is EFI_FILE_INFO.
254 @retval EFI_SUCCESS The information was returned.
255 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
256 EFI_FILE_INFO structure. BufferSize has been
257 updated with the size needed to complete the
262 ConvertKernelBlobTypeToFileInfo (
263 IN KERNEL_BLOB_TYPE BlobType
,
264 IN OUT UINTN
*BufferSize
,
274 EFI_FILE_INFO
*FileInfo
;
275 UINTN OriginalBufferSize
;
277 if (BlobType
== KernelBlobTypeMax
) {
279 // getting file info about the root directory
282 FileSize
= KernelBlobTypeMax
;
283 Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
285 CONST KERNEL_BLOB
*Blob
;
287 Blob
= &mKernelBlob
[BlobType
];
289 FileSize
= Blob
->Size
;
290 Attribute
= EFI_FILE_READ_ONLY
;
293 NameSize
= (StrLen(Name
) + 1) * 2;
294 FileInfoSize
= OFFSET_OF (EFI_FILE_INFO
, FileName
) + NameSize
;
295 ASSERT (FileInfoSize
>= sizeof *FileInfo
);
297 OriginalBufferSize
= *BufferSize
;
298 *BufferSize
= FileInfoSize
;
299 if (OriginalBufferSize
< *BufferSize
) {
300 return EFI_BUFFER_TOO_SMALL
;
303 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
304 FileInfo
->Size
= FileInfoSize
;
305 FileInfo
->FileSize
= FileSize
;
306 FileInfo
->PhysicalSize
= FileSize
;
307 FileInfo
->Attribute
= Attribute
;
309 CopyMem (&FileInfo
->CreateTime
, &mInitTime
, sizeof mInitTime
);
310 CopyMem (&FileInfo
->LastAccessTime
, &mInitTime
, sizeof mInitTime
);
311 CopyMem (&FileInfo
->ModificationTime
, &mInitTime
, sizeof mInitTime
);
312 CopyMem (FileInfo
->FileName
, Name
, NameSize
);
319 Reads data from a file, or continues scanning a directory.
321 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
322 is the file handle to read data from.
324 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
325 amount of data returned in Buffer. In both cases,
326 the size is measured in bytes. If the read goes
327 beyond the end of the file, the read length is
328 truncated to the end of the file.
330 If This is a directory, the function reads the
331 directory entry at the current position and
332 returns the entry (as EFI_FILE_INFO) in Buffer. If
333 there are no more directory entries, the
334 BufferSize is set to zero on output.
336 @param[out] Buffer The buffer into which the data is read.
338 @retval EFI_SUCCESS Data was read.
339 @retval EFI_NO_MEDIA The device has no medium.
340 @retval EFI_DEVICE_ERROR The device reported an error.
341 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
343 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
345 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
346 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
347 current directory entry as a EFI_FILE_INFO
348 structure. BufferSize has been updated with the
349 size needed to complete the request, and the
350 directory position has not been advanced.
356 IN EFI_FILE_PROTOCOL
*This
,
357 IN OUT UINTN
*BufferSize
,
362 CONST KERNEL_BLOB
*Blob
;
365 StubFile
= STUB_FILE_FROM_FILE (This
);
368 // Scanning the root directory?
370 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
373 if (StubFile
->Position
== KernelBlobTypeMax
) {
375 // Scanning complete.
381 Status
= ConvertKernelBlobTypeToFileInfo (
382 (KERNEL_BLOB_TYPE
)StubFile
->Position
,
385 if (EFI_ERROR (Status
)) {
389 ++StubFile
->Position
;
396 Blob
= &mKernelBlob
[StubFile
->BlobType
];
397 if (StubFile
->Position
> Blob
->Size
) {
398 return EFI_DEVICE_ERROR
;
401 Left
= Blob
->Size
- StubFile
->Position
;
402 if (*BufferSize
> Left
) {
403 *BufferSize
= (UINTN
)Left
;
405 if (Blob
->Data
!= NULL
) {
406 CopyMem (Buffer
, Blob
->Data
+ StubFile
->Position
, *BufferSize
);
408 StubFile
->Position
+= *BufferSize
;
414 Writes data to a file.
416 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
417 is the file handle to write data to.
419 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
420 amount of data actually written. In both cases,
421 the size is measured in bytes.
423 @param[in] Buffer The buffer of data to write.
425 @retval EFI_SUCCESS Data was written.
426 @retval EFI_UNSUPPORTED Writes to open directory files are not
428 @retval EFI_NO_MEDIA The device has no medium.
429 @retval EFI_DEVICE_ERROR The device reported an error.
430 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
431 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
432 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
433 @retval EFI_ACCESS_DENIED The file was opened read only.
434 @retval EFI_VOLUME_FULL The volume is full.
440 IN EFI_FILE_PROTOCOL
*This
,
441 IN OUT UINTN
*BufferSize
,
447 StubFile
= STUB_FILE_FROM_FILE (This
);
448 return (StubFile
->BlobType
== KernelBlobTypeMax
) ?
455 Returns a file's current position.
457 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
458 file handle to get the current position on.
460 @param[out] Position The address to return the file's current position
463 @retval EFI_SUCCESS The position was returned.
464 @retval EFI_UNSUPPORTED The request is not valid on open directories.
465 @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
471 StubFileGetPosition (
472 IN EFI_FILE_PROTOCOL
*This
,
478 StubFile
= STUB_FILE_FROM_FILE (This
);
479 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
480 return EFI_UNSUPPORTED
;
483 *Position
= StubFile
->Position
;
489 Sets a file's current position.
491 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
492 file handle to set the requested position on.
494 @param[in] Position The byte position from the start of the file to set. For
495 regular files, MAX_UINT64 means "seek to end". For
496 directories, zero means "rewind directory scan".
498 @retval EFI_SUCCESS The position was set.
499 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
501 @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
507 StubFileSetPosition (
508 IN EFI_FILE_PROTOCOL
*This
,
515 StubFile
= STUB_FILE_FROM_FILE (This
);
517 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
520 // rewinding a directory scan is allowed
522 StubFile
->Position
= 0;
525 return EFI_UNSUPPORTED
;
531 Blob
= &mKernelBlob
[StubFile
->BlobType
];
532 if (Position
== MAX_UINT64
) {
536 StubFile
->Position
= Blob
->Size
;
539 // absolute seek from beginning -- seeking past the end is allowed
541 StubFile
->Position
= Position
;
548 Returns information about a file.
550 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
551 that is the file handle the requested
554 @param[in] InformationType The type identifier GUID for the information
555 being requested. The following information
556 types are supported, storing the
557 corresponding structures in Buffer:
559 - gEfiFileInfoGuid: EFI_FILE_INFO
561 - gEfiFileSystemInfoGuid:
564 - gEfiFileSystemVolumeLabelInfoIdGuid:
565 EFI_FILE_SYSTEM_VOLUME_LABEL
567 @param[in,out] BufferSize On input, the size of Buffer. On output, the
568 amount of data returned in Buffer. In both
569 cases, the size is measured in bytes.
571 @param[out] Buffer A pointer to the data buffer to return. The
572 buffer's type is indicated by
575 @retval EFI_SUCCESS The information was returned.
576 @retval EFI_UNSUPPORTED The InformationType is not known.
577 @retval EFI_NO_MEDIA The device has no medium.
578 @retval EFI_DEVICE_ERROR The device reported an error.
579 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
580 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
581 information structure requested by
582 InformationType. BufferSize has been updated
583 with the size needed to complete the request.
589 IN EFI_FILE_PROTOCOL
*This
,
590 IN EFI_GUID
*InformationType
,
591 IN OUT UINTN
*BufferSize
,
595 CONST STUB_FILE
*StubFile
;
596 UINTN OriginalBufferSize
;
598 StubFile
= STUB_FILE_FROM_FILE (This
);
600 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
601 return ConvertKernelBlobTypeToFileInfo (StubFile
->BlobType
, BufferSize
,
605 OriginalBufferSize
= *BufferSize
;
607 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
608 EFI_FILE_SYSTEM_INFO
*FileSystemInfo
;
610 *BufferSize
= sizeof *FileSystemInfo
;
611 if (OriginalBufferSize
< *BufferSize
) {
612 return EFI_BUFFER_TOO_SMALL
;
615 FileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
616 FileSystemInfo
->Size
= sizeof *FileSystemInfo
;
617 FileSystemInfo
->ReadOnly
= TRUE
;
618 FileSystemInfo
->VolumeSize
= mTotalBlobBytes
;
619 FileSystemInfo
->FreeSpace
= 0;
620 FileSystemInfo
->BlockSize
= 1;
621 FileSystemInfo
->VolumeLabel
[0] = L
'\0';
626 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
627 EFI_FILE_SYSTEM_VOLUME_LABEL
*FileSystemVolumeLabel
;
629 *BufferSize
= sizeof *FileSystemVolumeLabel
;
630 if (OriginalBufferSize
< *BufferSize
) {
631 return EFI_BUFFER_TOO_SMALL
;
634 FileSystemVolumeLabel
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*)Buffer
;
635 FileSystemVolumeLabel
->VolumeLabel
[0] = L
'\0';
640 return EFI_UNSUPPORTED
;
645 Sets information about a file.
647 @param[in] File A pointer to the EFI_FILE_PROTOCOL instance that
648 is the file handle the information is for.
650 @param[in] InformationType The type identifier for the information being
653 @param[in] BufferSize The size, in bytes, of Buffer.
655 @param[in] Buffer A pointer to the data buffer to write. The
656 buffer's type is indicated by InformationType.
658 @retval EFI_SUCCESS The information was set.
659 @retval EFI_UNSUPPORTED The InformationType is not known.
660 @retval EFI_NO_MEDIA The device has no medium.
661 @retval EFI_DEVICE_ERROR The device reported an error.
662 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
663 @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the
665 @retval EFI_WRITE_PROTECTED InformationType is
666 EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
668 @retval EFI_WRITE_PROTECTED InformationType is
669 EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
671 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
672 to a file that is already present.
673 @retval EFI_ACCESS_DENIED An attempt is being made to change the
674 EFI_FILE_DIRECTORY Attribute.
675 @retval EFI_ACCESS_DENIED An attempt is being made to change the size of
677 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the
678 file was opened read-only and an attempt is
679 being made to modify a field other than
681 @retval EFI_VOLUME_FULL The volume is full.
682 @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type
683 indicated by InformationType.
689 IN EFI_FILE_PROTOCOL
*This
,
690 IN EFI_GUID
*InformationType
,
695 return EFI_WRITE_PROTECTED
;
700 Flushes all modified data associated with a file to a device.
702 @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
703 file handle to flush.
705 @retval EFI_SUCCESS The data was flushed.
706 @retval EFI_NO_MEDIA The device has no medium.
707 @retval EFI_DEVICE_ERROR The device reported an error.
708 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
709 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
710 @retval EFI_ACCESS_DENIED The file was opened read-only.
711 @retval EFI_VOLUME_FULL The volume is full.
717 IN EFI_FILE_PROTOCOL
*This
720 return EFI_WRITE_PROTECTED
;
724 // External definition of the file protocol template.
726 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
= {
727 EFI_FILE_PROTOCOL_REVISION
, // revision 1
738 NULL
, // OpenEx, revision 2
739 NULL
, // ReadEx, revision 2
740 NULL
, // WriteEx, revision 2
741 NULL
// FlushEx, revision 2
748 IN EFI_FILE_PROTOCOL
*This
,
749 OUT EFI_FILE_PROTOCOL
**NewHandle
,
755 CONST STUB_FILE
*StubFile
;
757 STUB_FILE
*NewStubFile
;
763 case EFI_FILE_MODE_READ
:
766 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
:
767 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
:
768 return EFI_WRITE_PROTECTED
;
771 return EFI_INVALID_PARAMETER
;
775 // Only the root directory supports opening files in it.
777 StubFile
= STUB_FILE_FROM_FILE (This
);
778 if (StubFile
->BlobType
!= KernelBlobTypeMax
) {
779 return EFI_UNSUPPORTED
;
785 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
786 if (StrCmp (FileName
, mKernelBlob
[BlobType
].Name
) == 0) {
790 if (BlobType
== KernelBlobTypeMax
) {
791 return EFI_NOT_FOUND
;
797 NewStubFile
= AllocatePool (sizeof *NewStubFile
);
798 if (NewStubFile
== NULL
) {
799 return EFI_OUT_OF_RESOURCES
;
802 NewStubFile
->Signature
= STUB_FILE_SIG
;
803 NewStubFile
->BlobType
= (KERNEL_BLOB_TYPE
)BlobType
;
804 NewStubFile
->Position
= 0;
805 CopyMem (&NewStubFile
->File
, &mEfiFileProtocolTemplate
,
806 sizeof mEfiFileProtocolTemplate
);
807 *NewHandle
= &NewStubFile
->File
;
814 // Protocol member functions for SimpleFileSystem.
818 Open the root directory on a volume.
820 @param[in] This A pointer to the volume to open the root directory on.
822 @param[out] Root A pointer to the location to return the opened file handle
823 for the root directory in.
825 @retval EFI_SUCCESS The device was opened.
826 @retval EFI_UNSUPPORTED This volume does not support the requested file
828 @retval EFI_NO_MEDIA The device has no medium.
829 @retval EFI_DEVICE_ERROR The device reported an error.
830 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
831 @retval EFI_ACCESS_DENIED The service denied access to the file.
832 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
834 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
835 medium is no longer supported. Any existing
836 file handles for this volume are no longer
837 valid. To access the files on the new medium,
838 the volume must be reopened with OpenVolume().
843 StubFileSystemOpenVolume (
844 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
845 OUT EFI_FILE_PROTOCOL
**Root
850 StubFile
= AllocatePool (sizeof *StubFile
);
851 if (StubFile
== NULL
) {
852 return EFI_OUT_OF_RESOURCES
;
855 StubFile
->Signature
= STUB_FILE_SIG
;
856 StubFile
->BlobType
= KernelBlobTypeMax
;
857 StubFile
->Position
= 0;
858 CopyMem (&StubFile
->File
, &mEfiFileProtocolTemplate
,
859 sizeof mEfiFileProtocolTemplate
);
860 *Root
= &StubFile
->File
;
865 STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem
= {
866 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
867 StubFileSystemOpenVolume
874 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
875 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
876 IN BOOLEAN BootPolicy
,
877 IN OUT UINTN
*BufferSize
,
878 OUT VOID
*Buffer OPTIONAL
881 CONST KERNEL_BLOB
*InitrdBlob
= &mKernelBlob
[KernelBlobTypeInitrd
];
883 ASSERT (InitrdBlob
->Size
> 0);
886 return EFI_UNSUPPORTED
;
889 if (BufferSize
== NULL
|| !IsDevicePathValid (FilePath
, 0)) {
890 return EFI_INVALID_PARAMETER
;
893 if (FilePath
->Type
!= END_DEVICE_PATH_TYPE
||
894 FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
) {
895 return EFI_NOT_FOUND
;
898 if (Buffer
== NULL
|| *BufferSize
< InitrdBlob
->Size
) {
899 *BufferSize
= InitrdBlob
->Size
;
900 return EFI_BUFFER_TOO_SMALL
;
903 CopyMem (Buffer
, InitrdBlob
->Data
, InitrdBlob
->Size
);
905 *BufferSize
= InitrdBlob
->Size
;
909 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
914 // Utility functions.
918 Populate a blob in mKernelBlob.
920 param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
921 to be filled from fw_cfg.
923 @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
924 size of zero for the blob, then Blob->Data has
927 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
932 IN OUT KERNEL_BLOB
*Blob
943 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
944 if (Blob
->FwCfgItem
[Idx
].SizeKey
== 0) {
947 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].SizeKey
);
948 Blob
->FwCfgItem
[Idx
].Size
= QemuFwCfgRead32 ();
949 Blob
->Size
+= Blob
->FwCfgItem
[Idx
].Size
;
951 if (Blob
->Size
== 0) {
958 Blob
->Data
= AllocatePool (Blob
->Size
);
959 if (Blob
->Data
== NULL
) {
960 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate %Ld bytes for \"%s\"\n",
961 __FUNCTION__
, (INT64
)Blob
->Size
, Blob
->Name
));
962 return EFI_OUT_OF_RESOURCES
;
965 DEBUG ((DEBUG_INFO
, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__
,
966 (INT64
)Blob
->Size
, Blob
->Name
));
968 ChunkData
= Blob
->Data
;
969 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
970 if (Blob
->FwCfgItem
[Idx
].DataKey
== 0) {
973 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].DataKey
);
975 Left
= Blob
->FwCfgItem
[Idx
].Size
;
979 Chunk
= (Left
< SIZE_1MB
) ? Left
: SIZE_1MB
;
980 QemuFwCfgReadBytes (Chunk
, ChunkData
+ Blob
->FwCfgItem
[Idx
].Size
- Left
);
982 DEBUG ((DEBUG_VERBOSE
, "%a: %Ld bytes remaining for \"%s\" (%d)\n",
983 __FUNCTION__
, (INT64
)Left
, Blob
->Name
, (INT32
)Idx
));
986 ChunkData
+= Blob
->FwCfgItem
[Idx
].Size
;
994 // The entry point of the feature.
998 Download the kernel, the initial ramdisk, and the kernel command line from
999 QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
1002 @retval EFI_NOT_FOUND Kernel image was not found.
1003 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1004 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
1006 @return Error codes from any of the underlying
1007 functions. On success, the function doesn't
1012 QemuKernelLoaderFsDxeEntrypoint (
1013 IN EFI_HANDLE ImageHandle
,
1014 IN EFI_SYSTEM_TABLE
*SystemTable
1018 KERNEL_BLOB
*CurrentBlob
;
1019 KERNEL_BLOB
*KernelBlob
;
1021 EFI_HANDLE FileSystemHandle
;
1022 EFI_HANDLE InitrdLoadFile2Handle
;
1024 if (!QemuFwCfgIsAvailable ()) {
1025 return EFI_NOT_FOUND
;
1028 Status
= gRT
->GetTime (&mInitTime
, NULL
/* Capabilities */);
1029 if (EFI_ERROR (Status
)) {
1030 DEBUG ((DEBUG_ERROR
, "%a: GetTime(): %r\n", __FUNCTION__
, Status
));
1037 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
1038 CurrentBlob
= &mKernelBlob
[BlobType
];
1039 Status
= FetchBlob (CurrentBlob
);
1040 if (EFI_ERROR (Status
)) {
1043 Status
= VerifyBlob (
1048 if (EFI_ERROR (Status
)) {
1051 mTotalBlobBytes
+= CurrentBlob
->Size
;
1053 KernelBlob
= &mKernelBlob
[KernelBlobTypeKernel
];
1055 if (KernelBlob
->Data
== NULL
) {
1056 Status
= EFI_NOT_FOUND
;
1061 // Create a new handle with a single VenMedia() node device path protocol on
1062 // it, plus a custom SimpleFileSystem protocol on it.
1064 FileSystemHandle
= NULL
;
1065 Status
= gBS
->InstallMultipleProtocolInterfaces (&FileSystemHandle
,
1066 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1067 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1069 if (EFI_ERROR (Status
)) {
1070 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1071 __FUNCTION__
, Status
));
1075 if (KernelBlob
[KernelBlobTypeInitrd
].Size
> 0) {
1076 InitrdLoadFile2Handle
= NULL
;
1077 Status
= gBS
->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle
,
1078 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
1079 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
1081 if (EFI_ERROR (Status
)) {
1082 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1083 __FUNCTION__
, Status
));
1084 goto UninstallFileSystemHandle
;
1090 UninstallFileSystemHandle
:
1091 Status
= gBS
->UninstallMultipleProtocolInterfaces (FileSystemHandle
,
1092 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1093 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1095 ASSERT_EFI_ERROR (Status
);
1098 while (BlobType
> 0) {
1099 CurrentBlob
= &mKernelBlob
[--BlobType
];
1100 if (CurrentBlob
->Data
!= NULL
) {
1101 FreePool (CurrentBlob
->Data
);
1102 CurrentBlob
->Size
= 0;
1103 CurrentBlob
->Data
= NULL
;