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/DebugLib.h>
21 #include <Library/DevicePathLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/QemuFwCfgLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiRuntimeServicesTableLib.h>
26 #include <Protocol/DevicePath.h>
27 #include <Protocol/LoadFile2.h>
28 #include <Protocol/SimpleFileSystem.h>
31 // Static data that hosts the fw_cfg blobs and serves file requests.
42 FIRMWARE_CONFIG_ITEM CONST SizeKey
;
43 FIRMWARE_CONFIG_ITEM CONST DataKey
;
50 STATIC KERNEL_BLOB mKernelBlob
[KernelBlobTypeMax
] = {
54 { QemuFwCfgItemKernelSetupSize
, QemuFwCfgItemKernelSetupData
, },
55 { QemuFwCfgItemKernelSize
, QemuFwCfgItemKernelData
, },
60 { QemuFwCfgItemInitrdSize
, QemuFwCfgItemInitrdData
, },
65 STATIC UINT64 mTotalBlobBytes
;
68 // Device path for the handle that incorporates our "EFI stub filesystem".
72 VENDOR_DEVICE_PATH VenMediaNode
;
73 EFI_DEVICE_PATH_PROTOCOL EndNode
;
74 } SINGLE_VENMEDIA_NODE_DEVPATH
;
77 STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath
= {
80 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
81 { sizeof (VENDOR_DEVICE_PATH
) }
83 QEMU_KERNEL_LOADER_FS_MEDIA_GUID
85 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
86 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
90 STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath
= {
93 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
94 { sizeof (VENDOR_DEVICE_PATH
) }
96 LINUX_EFI_INITRD_MEDIA_GUID
98 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
99 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
104 // The "file in the EFI stub filesystem" abstraction.
106 STATIC EFI_TIME mInitTime
;
108 #define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
111 UINT64 Signature
; // Carries STUB_FILE_SIG.
113 KERNEL_BLOB_TYPE BlobType
; // Index into mKernelBlob. KernelBlobTypeMax
114 // denotes the root directory of the filesystem.
116 UINT64 Position
; // Byte position for regular files;
117 // next directory entry to return for the root
120 EFI_FILE_PROTOCOL File
; // Standard protocol interface.
123 #define STUB_FILE_FROM_FILE(FilePointer) \
124 CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
127 // Protocol member functions for File.
131 Opens a new file relative to the source file's location.
133 (Forward declaration.)
135 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
136 the file handle to the source location. This would
137 typically be an open handle to a directory.
139 @param[out] NewHandle A pointer to the location to return the opened handle
142 @param[in] FileName The Null-terminated string of the name of the file to
143 be opened. The file name may contain the following
144 path modifiers: "\", ".", and "..".
146 @param[in] OpenMode The mode to open the file. The only valid
147 combinations that the file may be opened with are:
148 Read, Read/Write, or Create/Read/Write.
150 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case
151 these are the attribute bits for the newly created
154 @retval EFI_SUCCESS The file was opened.
155 @retval EFI_NOT_FOUND The specified file could not be found on the
157 @retval EFI_NO_MEDIA The device has no medium.
158 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
159 medium is no longer supported.
160 @retval EFI_DEVICE_ERROR The device reported an error.
161 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
162 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a
163 file for write when the media is
165 @retval EFI_ACCESS_DENIED The service denied access to the file.
166 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
168 @retval EFI_VOLUME_FULL The volume is full.
174 IN EFI_FILE_PROTOCOL
*This
,
175 OUT EFI_FILE_PROTOCOL
**NewHandle
,
182 Closes a specified file handle.
184 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
187 @retval EFI_SUCCESS The file was closed.
193 IN EFI_FILE_PROTOCOL
*This
196 FreePool (STUB_FILE_FROM_FILE (This
));
202 Close and delete the file handle.
204 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
205 handle to the file to delete.
207 @retval EFI_SUCCESS The file was closed and deleted, and the
209 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
217 IN EFI_FILE_PROTOCOL
*This
220 FreePool (STUB_FILE_FROM_FILE (This
));
221 return EFI_WARN_DELETE_FAILURE
;
226 Helper function that formats an EFI_FILE_INFO structure into the
227 user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
228 KernelBlobTypeMax, which stands for the root directory).
230 The interface follows the EFI_FILE_GET_INFO -- and for directories, the
231 EFI_FILE_READ -- interfaces.
233 @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
234 blob backing the STUB_FILE that information is
235 being requested about. If BlobType equals
236 KernelBlobTypeMax, then information will be
237 provided about the root directory of the
240 @param[in,out] BufferSize On input, the size of Buffer. On output, the
241 amount of data returned in Buffer. In both cases,
242 the size is measured in bytes.
244 @param[out] Buffer A pointer to the data buffer to return. The
245 buffer's type is EFI_FILE_INFO.
247 @retval EFI_SUCCESS The information was returned.
248 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
249 EFI_FILE_INFO structure. BufferSize has been
250 updated with the size needed to complete the
255 ConvertKernelBlobTypeToFileInfo (
256 IN KERNEL_BLOB_TYPE BlobType
,
257 IN OUT UINTN
*BufferSize
,
267 EFI_FILE_INFO
*FileInfo
;
268 UINTN OriginalBufferSize
;
270 if (BlobType
== KernelBlobTypeMax
) {
272 // getting file info about the root directory
275 FileSize
= KernelBlobTypeMax
;
276 Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
278 CONST KERNEL_BLOB
*Blob
;
280 Blob
= &mKernelBlob
[BlobType
];
282 FileSize
= Blob
->Size
;
283 Attribute
= EFI_FILE_READ_ONLY
;
286 NameSize
= (StrLen(Name
) + 1) * 2;
287 FileInfoSize
= OFFSET_OF (EFI_FILE_INFO
, FileName
) + NameSize
;
288 ASSERT (FileInfoSize
>= sizeof *FileInfo
);
290 OriginalBufferSize
= *BufferSize
;
291 *BufferSize
= FileInfoSize
;
292 if (OriginalBufferSize
< *BufferSize
) {
293 return EFI_BUFFER_TOO_SMALL
;
296 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
297 FileInfo
->Size
= FileInfoSize
;
298 FileInfo
->FileSize
= FileSize
;
299 FileInfo
->PhysicalSize
= FileSize
;
300 FileInfo
->Attribute
= Attribute
;
302 CopyMem (&FileInfo
->CreateTime
, &mInitTime
, sizeof mInitTime
);
303 CopyMem (&FileInfo
->LastAccessTime
, &mInitTime
, sizeof mInitTime
);
304 CopyMem (&FileInfo
->ModificationTime
, &mInitTime
, sizeof mInitTime
);
305 CopyMem (FileInfo
->FileName
, Name
, NameSize
);
312 Reads data from a file, or continues scanning a directory.
314 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
315 is the file handle to read data from.
317 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
318 amount of data returned in Buffer. In both cases,
319 the size is measured in bytes. If the read goes
320 beyond the end of the file, the read length is
321 truncated to the end of the file.
323 If This is a directory, the function reads the
324 directory entry at the current position and
325 returns the entry (as EFI_FILE_INFO) in Buffer. If
326 there are no more directory entries, the
327 BufferSize is set to zero on output.
329 @param[out] Buffer The buffer into which the data is read.
331 @retval EFI_SUCCESS Data was read.
332 @retval EFI_NO_MEDIA The device has no medium.
333 @retval EFI_DEVICE_ERROR The device reported an error.
334 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
336 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
338 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
339 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
340 current directory entry as a EFI_FILE_INFO
341 structure. BufferSize has been updated with the
342 size needed to complete the request, and the
343 directory position has not been advanced.
349 IN EFI_FILE_PROTOCOL
*This
,
350 IN OUT UINTN
*BufferSize
,
355 CONST KERNEL_BLOB
*Blob
;
358 StubFile
= STUB_FILE_FROM_FILE (This
);
361 // Scanning the root directory?
363 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
366 if (StubFile
->Position
== KernelBlobTypeMax
) {
368 // Scanning complete.
374 Status
= ConvertKernelBlobTypeToFileInfo (
375 (KERNEL_BLOB_TYPE
)StubFile
->Position
,
378 if (EFI_ERROR (Status
)) {
382 ++StubFile
->Position
;
389 Blob
= &mKernelBlob
[StubFile
->BlobType
];
390 if (StubFile
->Position
> Blob
->Size
) {
391 return EFI_DEVICE_ERROR
;
394 Left
= Blob
->Size
- StubFile
->Position
;
395 if (*BufferSize
> Left
) {
396 *BufferSize
= (UINTN
)Left
;
398 if (Blob
->Data
!= NULL
) {
399 CopyMem (Buffer
, Blob
->Data
+ StubFile
->Position
, *BufferSize
);
401 StubFile
->Position
+= *BufferSize
;
407 Writes data to a file.
409 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
410 is the file handle to write data to.
412 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
413 amount of data actually written. In both cases,
414 the size is measured in bytes.
416 @param[in] Buffer The buffer of data to write.
418 @retval EFI_SUCCESS Data was written.
419 @retval EFI_UNSUPPORTED Writes to open directory files are not
421 @retval EFI_NO_MEDIA The device has no medium.
422 @retval EFI_DEVICE_ERROR The device reported an error.
423 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
424 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
425 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
426 @retval EFI_ACCESS_DENIED The file was opened read only.
427 @retval EFI_VOLUME_FULL The volume is full.
433 IN EFI_FILE_PROTOCOL
*This
,
434 IN OUT UINTN
*BufferSize
,
440 StubFile
= STUB_FILE_FROM_FILE (This
);
441 return (StubFile
->BlobType
== KernelBlobTypeMax
) ?
448 Returns a file's current position.
450 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
451 file handle to get the current position on.
453 @param[out] Position The address to return the file's current position
456 @retval EFI_SUCCESS The position was returned.
457 @retval EFI_UNSUPPORTED The request is not valid on open directories.
458 @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
464 StubFileGetPosition (
465 IN EFI_FILE_PROTOCOL
*This
,
471 StubFile
= STUB_FILE_FROM_FILE (This
);
472 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
473 return EFI_UNSUPPORTED
;
476 *Position
= StubFile
->Position
;
482 Sets a file's current position.
484 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
485 file handle to set the requested position on.
487 @param[in] Position The byte position from the start of the file to set. For
488 regular files, MAX_UINT64 means "seek to end". For
489 directories, zero means "rewind directory scan".
491 @retval EFI_SUCCESS The position was set.
492 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
494 @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
500 StubFileSetPosition (
501 IN EFI_FILE_PROTOCOL
*This
,
508 StubFile
= STUB_FILE_FROM_FILE (This
);
510 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
513 // rewinding a directory scan is allowed
515 StubFile
->Position
= 0;
518 return EFI_UNSUPPORTED
;
524 Blob
= &mKernelBlob
[StubFile
->BlobType
];
525 if (Position
== MAX_UINT64
) {
529 StubFile
->Position
= Blob
->Size
;
532 // absolute seek from beginning -- seeking past the end is allowed
534 StubFile
->Position
= Position
;
541 Returns information about a file.
543 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
544 that is the file handle the requested
547 @param[in] InformationType The type identifier GUID for the information
548 being requested. The following information
549 types are supported, storing the
550 corresponding structures in Buffer:
552 - gEfiFileInfoGuid: EFI_FILE_INFO
554 - gEfiFileSystemInfoGuid:
557 - gEfiFileSystemVolumeLabelInfoIdGuid:
558 EFI_FILE_SYSTEM_VOLUME_LABEL
560 @param[in,out] BufferSize On input, the size of Buffer. On output, the
561 amount of data returned in Buffer. In both
562 cases, the size is measured in bytes.
564 @param[out] Buffer A pointer to the data buffer to return. The
565 buffer's type is indicated by
568 @retval EFI_SUCCESS The information was returned.
569 @retval EFI_UNSUPPORTED The InformationType is not known.
570 @retval EFI_NO_MEDIA The device has no medium.
571 @retval EFI_DEVICE_ERROR The device reported an error.
572 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
573 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
574 information structure requested by
575 InformationType. BufferSize has been updated
576 with the size needed to complete the request.
582 IN EFI_FILE_PROTOCOL
*This
,
583 IN EFI_GUID
*InformationType
,
584 IN OUT UINTN
*BufferSize
,
588 CONST STUB_FILE
*StubFile
;
589 UINTN OriginalBufferSize
;
591 StubFile
= STUB_FILE_FROM_FILE (This
);
593 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
594 return ConvertKernelBlobTypeToFileInfo (StubFile
->BlobType
, BufferSize
,
598 OriginalBufferSize
= *BufferSize
;
600 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
601 EFI_FILE_SYSTEM_INFO
*FileSystemInfo
;
603 *BufferSize
= sizeof *FileSystemInfo
;
604 if (OriginalBufferSize
< *BufferSize
) {
605 return EFI_BUFFER_TOO_SMALL
;
608 FileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
609 FileSystemInfo
->Size
= sizeof *FileSystemInfo
;
610 FileSystemInfo
->ReadOnly
= TRUE
;
611 FileSystemInfo
->VolumeSize
= mTotalBlobBytes
;
612 FileSystemInfo
->FreeSpace
= 0;
613 FileSystemInfo
->BlockSize
= 1;
614 FileSystemInfo
->VolumeLabel
[0] = L
'\0';
619 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
620 EFI_FILE_SYSTEM_VOLUME_LABEL
*FileSystemVolumeLabel
;
622 *BufferSize
= sizeof *FileSystemVolumeLabel
;
623 if (OriginalBufferSize
< *BufferSize
) {
624 return EFI_BUFFER_TOO_SMALL
;
627 FileSystemVolumeLabel
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*)Buffer
;
628 FileSystemVolumeLabel
->VolumeLabel
[0] = L
'\0';
633 return EFI_UNSUPPORTED
;
638 Sets information about a file.
640 @param[in] File A pointer to the EFI_FILE_PROTOCOL instance that
641 is the file handle the information is for.
643 @param[in] InformationType The type identifier for the information being
646 @param[in] BufferSize The size, in bytes, of Buffer.
648 @param[in] Buffer A pointer to the data buffer to write. The
649 buffer's type is indicated by InformationType.
651 @retval EFI_SUCCESS The information was set.
652 @retval EFI_UNSUPPORTED The InformationType is not known.
653 @retval EFI_NO_MEDIA The device has no medium.
654 @retval EFI_DEVICE_ERROR The device reported an error.
655 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
656 @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the
658 @retval EFI_WRITE_PROTECTED InformationType is
659 EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
661 @retval EFI_WRITE_PROTECTED InformationType is
662 EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
664 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
665 to a file that is already present.
666 @retval EFI_ACCESS_DENIED An attempt is being made to change the
667 EFI_FILE_DIRECTORY Attribute.
668 @retval EFI_ACCESS_DENIED An attempt is being made to change the size of
670 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the
671 file was opened read-only and an attempt is
672 being made to modify a field other than
674 @retval EFI_VOLUME_FULL The volume is full.
675 @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type
676 indicated by InformationType.
682 IN EFI_FILE_PROTOCOL
*This
,
683 IN EFI_GUID
*InformationType
,
688 return EFI_WRITE_PROTECTED
;
693 Flushes all modified data associated with a file to a device.
695 @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
696 file handle to flush.
698 @retval EFI_SUCCESS The data was flushed.
699 @retval EFI_NO_MEDIA The device has no medium.
700 @retval EFI_DEVICE_ERROR The device reported an error.
701 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
702 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
703 @retval EFI_ACCESS_DENIED The file was opened read-only.
704 @retval EFI_VOLUME_FULL The volume is full.
710 IN EFI_FILE_PROTOCOL
*This
713 return EFI_WRITE_PROTECTED
;
717 // External definition of the file protocol template.
719 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
= {
720 EFI_FILE_PROTOCOL_REVISION
, // revision 1
731 NULL
, // OpenEx, revision 2
732 NULL
, // ReadEx, revision 2
733 NULL
, // WriteEx, revision 2
734 NULL
// FlushEx, revision 2
741 IN EFI_FILE_PROTOCOL
*This
,
742 OUT EFI_FILE_PROTOCOL
**NewHandle
,
748 CONST STUB_FILE
*StubFile
;
750 STUB_FILE
*NewStubFile
;
756 case EFI_FILE_MODE_READ
:
759 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
:
760 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
:
761 return EFI_WRITE_PROTECTED
;
764 return EFI_INVALID_PARAMETER
;
768 // Only the root directory supports opening files in it.
770 StubFile
= STUB_FILE_FROM_FILE (This
);
771 if (StubFile
->BlobType
!= KernelBlobTypeMax
) {
772 return EFI_UNSUPPORTED
;
778 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
779 if (StrCmp (FileName
, mKernelBlob
[BlobType
].Name
) == 0) {
783 if (BlobType
== KernelBlobTypeMax
) {
784 return EFI_NOT_FOUND
;
790 NewStubFile
= AllocatePool (sizeof *NewStubFile
);
791 if (NewStubFile
== NULL
) {
792 return EFI_OUT_OF_RESOURCES
;
795 NewStubFile
->Signature
= STUB_FILE_SIG
;
796 NewStubFile
->BlobType
= (KERNEL_BLOB_TYPE
)BlobType
;
797 NewStubFile
->Position
= 0;
798 CopyMem (&NewStubFile
->File
, &mEfiFileProtocolTemplate
,
799 sizeof mEfiFileProtocolTemplate
);
800 *NewHandle
= &NewStubFile
->File
;
807 // Protocol member functions for SimpleFileSystem.
811 Open the root directory on a volume.
813 @param[in] This A pointer to the volume to open the root directory on.
815 @param[out] Root A pointer to the location to return the opened file handle
816 for the root directory in.
818 @retval EFI_SUCCESS The device was opened.
819 @retval EFI_UNSUPPORTED This volume does not support the requested file
821 @retval EFI_NO_MEDIA The device has no medium.
822 @retval EFI_DEVICE_ERROR The device reported an error.
823 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
824 @retval EFI_ACCESS_DENIED The service denied access to the file.
825 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
827 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
828 medium is no longer supported. Any existing
829 file handles for this volume are no longer
830 valid. To access the files on the new medium,
831 the volume must be reopened with OpenVolume().
836 StubFileSystemOpenVolume (
837 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
838 OUT EFI_FILE_PROTOCOL
**Root
843 StubFile
= AllocatePool (sizeof *StubFile
);
844 if (StubFile
== NULL
) {
845 return EFI_OUT_OF_RESOURCES
;
848 StubFile
->Signature
= STUB_FILE_SIG
;
849 StubFile
->BlobType
= KernelBlobTypeMax
;
850 StubFile
->Position
= 0;
851 CopyMem (&StubFile
->File
, &mEfiFileProtocolTemplate
,
852 sizeof mEfiFileProtocolTemplate
);
853 *Root
= &StubFile
->File
;
858 STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem
= {
859 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
860 StubFileSystemOpenVolume
867 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
868 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
869 IN BOOLEAN BootPolicy
,
870 IN OUT UINTN
*BufferSize
,
871 OUT VOID
*Buffer OPTIONAL
874 CONST KERNEL_BLOB
*InitrdBlob
= &mKernelBlob
[KernelBlobTypeInitrd
];
876 ASSERT (InitrdBlob
->Size
> 0);
879 return EFI_UNSUPPORTED
;
882 if (BufferSize
== NULL
|| !IsDevicePathValid (FilePath
, 0)) {
883 return EFI_INVALID_PARAMETER
;
886 if (FilePath
->Type
!= END_DEVICE_PATH_TYPE
||
887 FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
) {
888 return EFI_NOT_FOUND
;
891 if (Buffer
== NULL
|| *BufferSize
< InitrdBlob
->Size
) {
892 *BufferSize
= InitrdBlob
->Size
;
893 return EFI_BUFFER_TOO_SMALL
;
896 CopyMem (Buffer
, InitrdBlob
->Data
, InitrdBlob
->Size
);
898 *BufferSize
= InitrdBlob
->Size
;
902 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
907 // Utility functions.
911 Populate a blob in mKernelBlob.
913 param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
914 to be filled from fw_cfg.
916 @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
917 size of zero for the blob, then Blob->Data has
920 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
925 IN OUT KERNEL_BLOB
*Blob
936 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
937 if (Blob
->FwCfgItem
[Idx
].SizeKey
== 0) {
940 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].SizeKey
);
941 Blob
->FwCfgItem
[Idx
].Size
= QemuFwCfgRead32 ();
942 Blob
->Size
+= Blob
->FwCfgItem
[Idx
].Size
;
944 if (Blob
->Size
== 0) {
951 Blob
->Data
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)Blob
->Size
));
952 if (Blob
->Data
== NULL
) {
953 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate %Ld bytes for \"%s\"\n",
954 __FUNCTION__
, (INT64
)Blob
->Size
, Blob
->Name
));
955 return EFI_OUT_OF_RESOURCES
;
958 DEBUG ((DEBUG_INFO
, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__
,
959 (INT64
)Blob
->Size
, Blob
->Name
));
961 ChunkData
= Blob
->Data
;
962 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
963 if (Blob
->FwCfgItem
[Idx
].DataKey
== 0) {
966 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].DataKey
);
968 Left
= Blob
->FwCfgItem
[Idx
].Size
;
972 Chunk
= (Left
< SIZE_1MB
) ? Left
: SIZE_1MB
;
973 QemuFwCfgReadBytes (Chunk
, ChunkData
+ Blob
->FwCfgItem
[Idx
].Size
- Left
);
975 DEBUG ((DEBUG_VERBOSE
, "%a: %Ld bytes remaining for \"%s\" (%d)\n",
976 __FUNCTION__
, (INT64
)Left
, Blob
->Name
, (INT32
)Idx
));
979 ChunkData
+= Blob
->FwCfgItem
[Idx
].Size
;
987 // The entry point of the feature.
991 Download the kernel, the initial ramdisk, and the kernel command line from
992 QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
995 @retval EFI_NOT_FOUND Kernel image was not found.
996 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
997 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
999 @return Error codes from any of the underlying
1000 functions. On success, the function doesn't
1005 QemuKernelLoaderFsDxeEntrypoint (
1006 IN EFI_HANDLE ImageHandle
,
1007 IN EFI_SYSTEM_TABLE
*SystemTable
1011 KERNEL_BLOB
*CurrentBlob
;
1012 KERNEL_BLOB
*KernelBlob
;
1014 EFI_HANDLE FileSystemHandle
;
1015 EFI_HANDLE InitrdLoadFile2Handle
;
1017 if (!QemuFwCfgIsAvailable ()) {
1018 return EFI_NOT_FOUND
;
1021 Status
= gRT
->GetTime (&mInitTime
, NULL
/* Capabilities */);
1022 if (EFI_ERROR (Status
)) {
1023 DEBUG ((DEBUG_ERROR
, "%a: GetTime(): %r\n", __FUNCTION__
, Status
));
1030 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
1031 CurrentBlob
= &mKernelBlob
[BlobType
];
1032 Status
= FetchBlob (CurrentBlob
);
1033 if (EFI_ERROR (Status
)) {
1036 mTotalBlobBytes
+= CurrentBlob
->Size
;
1038 KernelBlob
= &mKernelBlob
[KernelBlobTypeKernel
];
1040 if (KernelBlob
->Data
== NULL
) {
1041 Status
= EFI_NOT_FOUND
;
1046 // Create a new handle with a single VenMedia() node device path protocol on
1047 // it, plus a custom SimpleFileSystem protocol on it.
1049 FileSystemHandle
= NULL
;
1050 Status
= gBS
->InstallMultipleProtocolInterfaces (&FileSystemHandle
,
1051 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1052 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1054 if (EFI_ERROR (Status
)) {
1055 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1056 __FUNCTION__
, Status
));
1060 if (KernelBlob
[KernelBlobTypeInitrd
].Size
> 0) {
1061 InitrdLoadFile2Handle
= NULL
;
1062 Status
= gBS
->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle
,
1063 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
1064 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
1066 if (EFI_ERROR (Status
)) {
1067 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1068 __FUNCTION__
, Status
));
1069 goto UninstallFileSystemHandle
;
1075 UninstallFileSystemHandle
:
1076 Status
= gBS
->UninstallMultipleProtocolInterfaces (FileSystemHandle
,
1077 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1078 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1080 ASSERT_EFI_ERROR (Status
);
1083 while (BlobType
> 0) {
1084 CurrentBlob
= &mKernelBlob
[--BlobType
];
1085 if (CurrentBlob
->Data
!= NULL
) {
1086 FreePages (CurrentBlob
->Data
,
1087 EFI_SIZE_TO_PAGES ((UINTN
)CurrentBlob
->Size
));
1088 CurrentBlob
->Size
= 0;
1089 CurrentBlob
->Data
= NULL
;