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
));
208 Close and delete the file handle.
210 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
211 handle to the file to delete.
213 @retval EFI_SUCCESS The file was closed and deleted, and the
215 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
223 IN EFI_FILE_PROTOCOL
*This
226 FreePool (STUB_FILE_FROM_FILE (This
));
227 return EFI_WARN_DELETE_FAILURE
;
231 Helper function that formats an EFI_FILE_INFO structure into the
232 user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
233 KernelBlobTypeMax, which stands for the root directory).
235 The interface follows the EFI_FILE_GET_INFO -- and for directories, the
236 EFI_FILE_READ -- interfaces.
238 @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
239 blob backing the STUB_FILE that information is
240 being requested about. If BlobType equals
241 KernelBlobTypeMax, then information will be
242 provided about the root directory of the
245 @param[in,out] BufferSize On input, the size of Buffer. On output, the
246 amount of data returned in Buffer. In both cases,
247 the size is measured in bytes.
249 @param[out] Buffer A pointer to the data buffer to return. The
250 buffer's type is EFI_FILE_INFO.
252 @retval EFI_SUCCESS The information was returned.
253 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
254 EFI_FILE_INFO structure. BufferSize has been
255 updated with the size needed to complete the
260 ConvertKernelBlobTypeToFileInfo (
261 IN KERNEL_BLOB_TYPE BlobType
,
262 IN OUT UINTN
*BufferSize
,
272 EFI_FILE_INFO
*FileInfo
;
273 UINTN OriginalBufferSize
;
275 if (BlobType
== KernelBlobTypeMax
) {
277 // getting file info about the root directory
280 FileSize
= KernelBlobTypeMax
;
281 Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
283 CONST KERNEL_BLOB
*Blob
;
285 Blob
= &mKernelBlob
[BlobType
];
287 FileSize
= Blob
->Size
;
288 Attribute
= EFI_FILE_READ_ONLY
;
291 NameSize
= (StrLen (Name
) + 1) * 2;
292 FileInfoSize
= OFFSET_OF (EFI_FILE_INFO
, FileName
) + NameSize
;
293 ASSERT (FileInfoSize
>= sizeof *FileInfo
);
295 OriginalBufferSize
= *BufferSize
;
296 *BufferSize
= FileInfoSize
;
297 if (OriginalBufferSize
< *BufferSize
) {
298 return EFI_BUFFER_TOO_SMALL
;
301 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
302 FileInfo
->Size
= FileInfoSize
;
303 FileInfo
->FileSize
= FileSize
;
304 FileInfo
->PhysicalSize
= FileSize
;
305 FileInfo
->Attribute
= Attribute
;
307 CopyMem (&FileInfo
->CreateTime
, &mInitTime
, sizeof mInitTime
);
308 CopyMem (&FileInfo
->LastAccessTime
, &mInitTime
, sizeof mInitTime
);
309 CopyMem (&FileInfo
->ModificationTime
, &mInitTime
, sizeof mInitTime
);
310 CopyMem (FileInfo
->FileName
, Name
, NameSize
);
316 Reads data from a file, or continues scanning a directory.
318 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
319 is the file handle to read data from.
321 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
322 amount of data returned in Buffer. In both cases,
323 the size is measured in bytes. If the read goes
324 beyond the end of the file, the read length is
325 truncated to the end of the file.
327 If This is a directory, the function reads the
328 directory entry at the current position and
329 returns the entry (as EFI_FILE_INFO) in Buffer. If
330 there are no more directory entries, the
331 BufferSize is set to zero on output.
333 @param[out] Buffer The buffer into which the data is read.
335 @retval EFI_SUCCESS Data was read.
336 @retval EFI_NO_MEDIA The device has no medium.
337 @retval EFI_DEVICE_ERROR The device reported an error.
338 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
340 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
342 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
343 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
344 current directory entry as a EFI_FILE_INFO
345 structure. BufferSize has been updated with the
346 size needed to complete the request, and the
347 directory position has not been advanced.
353 IN EFI_FILE_PROTOCOL
*This
,
354 IN OUT UINTN
*BufferSize
,
359 CONST KERNEL_BLOB
*Blob
;
362 StubFile
= STUB_FILE_FROM_FILE (This
);
365 // Scanning the root directory?
367 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
370 if (StubFile
->Position
== KernelBlobTypeMax
) {
372 // Scanning complete.
378 Status
= ConvertKernelBlobTypeToFileInfo (
379 (KERNEL_BLOB_TYPE
)StubFile
->Position
,
383 if (EFI_ERROR (Status
)) {
387 ++StubFile
->Position
;
394 Blob
= &mKernelBlob
[StubFile
->BlobType
];
395 if (StubFile
->Position
> Blob
->Size
) {
396 return EFI_DEVICE_ERROR
;
399 Left
= Blob
->Size
- StubFile
->Position
;
400 if (*BufferSize
> Left
) {
401 *BufferSize
= (UINTN
)Left
;
404 if (Blob
->Data
!= NULL
) {
405 CopyMem (Buffer
, Blob
->Data
+ StubFile
->Position
, *BufferSize
);
408 StubFile
->Position
+= *BufferSize
;
413 Writes data to a file.
415 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
416 is the file handle to write data to.
418 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
419 amount of data actually written. In both cases,
420 the size is measured in bytes.
422 @param[in] Buffer The buffer of data to write.
424 @retval EFI_SUCCESS Data was written.
425 @retval EFI_UNSUPPORTED Writes to open directory files are not
427 @retval EFI_NO_MEDIA The device has no medium.
428 @retval EFI_DEVICE_ERROR The device reported an error.
429 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
430 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
431 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
432 @retval EFI_ACCESS_DENIED The file was opened read only.
433 @retval EFI_VOLUME_FULL The volume is full.
439 IN EFI_FILE_PROTOCOL
*This
,
440 IN OUT UINTN
*BufferSize
,
446 StubFile
= STUB_FILE_FROM_FILE (This
);
447 return (StubFile
->BlobType
== KernelBlobTypeMax
) ?
453 Returns a file's current position.
455 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
456 file handle to get the current position on.
458 @param[out] Position The address to return the file's current position
461 @retval EFI_SUCCESS The position was returned.
462 @retval EFI_UNSUPPORTED The request is not valid on open directories.
463 @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
469 StubFileGetPosition (
470 IN EFI_FILE_PROTOCOL
*This
,
476 StubFile
= STUB_FILE_FROM_FILE (This
);
477 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
478 return EFI_UNSUPPORTED
;
481 *Position
= StubFile
->Position
;
486 Sets a file's current position.
488 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
489 file handle to set the requested position on.
491 @param[in] Position The byte position from the start of the file to set. For
492 regular files, MAX_UINT64 means "seek to end". For
493 directories, zero means "rewind directory scan".
495 @retval EFI_SUCCESS The position was set.
496 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
498 @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
504 StubFileSetPosition (
505 IN EFI_FILE_PROTOCOL
*This
,
512 StubFile
= STUB_FILE_FROM_FILE (This
);
514 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
517 // rewinding a directory scan is allowed
519 StubFile
->Position
= 0;
523 return EFI_UNSUPPORTED
;
529 Blob
= &mKernelBlob
[StubFile
->BlobType
];
530 if (Position
== MAX_UINT64
) {
534 StubFile
->Position
= Blob
->Size
;
537 // absolute seek from beginning -- seeking past the end is allowed
539 StubFile
->Position
= Position
;
546 Returns information about a file.
548 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
549 that is the file handle the requested
552 @param[in] InformationType The type identifier GUID for the information
553 being requested. The following information
554 types are supported, storing the
555 corresponding structures in Buffer:
557 - gEfiFileInfoGuid: EFI_FILE_INFO
559 - gEfiFileSystemInfoGuid:
562 - gEfiFileSystemVolumeLabelInfoIdGuid:
563 EFI_FILE_SYSTEM_VOLUME_LABEL
565 @param[in,out] BufferSize On input, the size of Buffer. On output, the
566 amount of data returned in Buffer. In both
567 cases, the size is measured in bytes.
569 @param[out] Buffer A pointer to the data buffer to return. The
570 buffer's type is indicated by
573 @retval EFI_SUCCESS The information was returned.
574 @retval EFI_UNSUPPORTED The InformationType is not known.
575 @retval EFI_NO_MEDIA The device has no medium.
576 @retval EFI_DEVICE_ERROR The device reported an error.
577 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
578 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
579 information structure requested by
580 InformationType. BufferSize has been updated
581 with the size needed to complete the request.
587 IN EFI_FILE_PROTOCOL
*This
,
588 IN EFI_GUID
*InformationType
,
589 IN OUT UINTN
*BufferSize
,
593 CONST STUB_FILE
*StubFile
;
594 UINTN OriginalBufferSize
;
596 StubFile
= STUB_FILE_FROM_FILE (This
);
598 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
599 return ConvertKernelBlobTypeToFileInfo (
606 OriginalBufferSize
= *BufferSize
;
608 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
609 EFI_FILE_SYSTEM_INFO
*FileSystemInfo
;
611 *BufferSize
= sizeof *FileSystemInfo
;
612 if (OriginalBufferSize
< *BufferSize
) {
613 return EFI_BUFFER_TOO_SMALL
;
616 FileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
617 FileSystemInfo
->Size
= sizeof *FileSystemInfo
;
618 FileSystemInfo
->ReadOnly
= TRUE
;
619 FileSystemInfo
->VolumeSize
= mTotalBlobBytes
;
620 FileSystemInfo
->FreeSpace
= 0;
621 FileSystemInfo
->BlockSize
= 1;
622 FileSystemInfo
->VolumeLabel
[0] = L
'\0';
627 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
628 EFI_FILE_SYSTEM_VOLUME_LABEL
*FileSystemVolumeLabel
;
630 *BufferSize
= sizeof *FileSystemVolumeLabel
;
631 if (OriginalBufferSize
< *BufferSize
) {
632 return EFI_BUFFER_TOO_SMALL
;
635 FileSystemVolumeLabel
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*)Buffer
;
636 FileSystemVolumeLabel
->VolumeLabel
[0] = L
'\0';
641 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
;
699 Flushes all modified data associated with a file to a device.
701 @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
702 file handle to flush.
704 @retval EFI_SUCCESS The data was flushed.
705 @retval EFI_NO_MEDIA The device has no medium.
706 @retval EFI_DEVICE_ERROR The device reported an error.
707 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
708 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
709 @retval EFI_ACCESS_DENIED The file was opened read-only.
710 @retval EFI_VOLUME_FULL The volume is full.
716 IN EFI_FILE_PROTOCOL
*This
719 return EFI_WRITE_PROTECTED
;
723 // External definition of the file protocol template.
725 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
= {
726 EFI_FILE_PROTOCOL_REVISION
, // revision 1
737 NULL
, // OpenEx, revision 2
738 NULL
, // ReadEx, revision 2
739 NULL
, // WriteEx, revision 2
740 NULL
// FlushEx, revision 2
747 IN EFI_FILE_PROTOCOL
*This
,
748 OUT EFI_FILE_PROTOCOL
**NewHandle
,
754 CONST STUB_FILE
*StubFile
;
756 STUB_FILE
*NewStubFile
;
762 case EFI_FILE_MODE_READ
:
765 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
:
766 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
:
767 return EFI_WRITE_PROTECTED
;
770 return EFI_INVALID_PARAMETER
;
774 // Only the root directory supports opening files in it.
776 StubFile
= STUB_FILE_FROM_FILE (This
);
777 if (StubFile
->BlobType
!= KernelBlobTypeMax
) {
778 return EFI_UNSUPPORTED
;
784 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
785 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;
807 &mEfiFileProtocolTemplate
,
808 sizeof mEfiFileProtocolTemplate
810 *NewHandle
= &NewStubFile
->File
;
816 // Protocol member functions for SimpleFileSystem.
820 Open the root directory on a volume.
822 @param[in] This A pointer to the volume to open the root directory on.
824 @param[out] Root A pointer to the location to return the opened file handle
825 for the root directory in.
827 @retval EFI_SUCCESS The device was opened.
828 @retval EFI_UNSUPPORTED This volume does not support the requested file
830 @retval EFI_NO_MEDIA The device has no medium.
831 @retval EFI_DEVICE_ERROR The device reported an error.
832 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
833 @retval EFI_ACCESS_DENIED The service denied access to the file.
834 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
836 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
837 medium is no longer supported. Any existing
838 file handles for this volume are no longer
839 valid. To access the files on the new medium,
840 the volume must be reopened with OpenVolume().
845 StubFileSystemOpenVolume (
846 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
847 OUT EFI_FILE_PROTOCOL
**Root
852 StubFile
= AllocatePool (sizeof *StubFile
);
853 if (StubFile
== NULL
) {
854 return EFI_OUT_OF_RESOURCES
;
857 StubFile
->Signature
= STUB_FILE_SIG
;
858 StubFile
->BlobType
= KernelBlobTypeMax
;
859 StubFile
->Position
= 0;
862 &mEfiFileProtocolTemplate
,
863 sizeof mEfiFileProtocolTemplate
865 *Root
= &StubFile
->File
;
870 STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem
= {
871 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
872 StubFileSystemOpenVolume
879 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
880 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
881 IN BOOLEAN BootPolicy
,
882 IN OUT UINTN
*BufferSize
,
883 OUT VOID
*Buffer OPTIONAL
886 CONST KERNEL_BLOB
*InitrdBlob
= &mKernelBlob
[KernelBlobTypeInitrd
];
888 ASSERT (InitrdBlob
->Size
> 0);
891 return EFI_UNSUPPORTED
;
894 if ((BufferSize
== NULL
) || !IsDevicePathValid (FilePath
, 0)) {
895 return EFI_INVALID_PARAMETER
;
898 if ((FilePath
->Type
!= END_DEVICE_PATH_TYPE
) ||
899 (FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
))
901 return EFI_NOT_FOUND
;
904 if ((Buffer
== NULL
) || (*BufferSize
< InitrdBlob
->Size
)) {
905 *BufferSize
= InitrdBlob
->Size
;
906 return EFI_BUFFER_TOO_SMALL
;
909 CopyMem (Buffer
, InitrdBlob
->Data
, InitrdBlob
->Size
);
911 *BufferSize
= InitrdBlob
->Size
;
915 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
920 // Utility functions.
924 Populate a blob in mKernelBlob.
926 param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
927 to be filled from fw_cfg.
929 @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
930 size of zero for the blob, then Blob->Data has
933 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
938 IN OUT KERNEL_BLOB
*Blob
949 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
950 if (Blob
->FwCfgItem
[Idx
].SizeKey
== 0) {
954 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].SizeKey
);
955 Blob
->FwCfgItem
[Idx
].Size
= QemuFwCfgRead32 ();
956 Blob
->Size
+= Blob
->FwCfgItem
[Idx
].Size
;
959 if (Blob
->Size
== 0) {
966 Blob
->Data
= AllocatePool (Blob
->Size
);
967 if (Blob
->Data
== NULL
) {
970 "%a: failed to allocate %Ld bytes for \"%s\"\n",
975 return EFI_OUT_OF_RESOURCES
;
980 "%a: loading %Ld bytes for \"%s\"\n",
986 ChunkData
= Blob
->Data
;
987 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
988 if (Blob
->FwCfgItem
[Idx
].DataKey
== 0) {
992 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].DataKey
);
994 Left
= Blob
->FwCfgItem
[Idx
].Size
;
998 Chunk
= (Left
< SIZE_1MB
) ? Left
: SIZE_1MB
;
999 QemuFwCfgReadBytes (Chunk
, ChunkData
+ Blob
->FwCfgItem
[Idx
].Size
- Left
);
1003 "%a: %Ld bytes remaining for \"%s\" (%d)\n",
1011 ChunkData
+= Blob
->FwCfgItem
[Idx
].Size
;
1018 // The entry point of the feature.
1022 Download the kernel, the initial ramdisk, and the kernel command line from
1023 QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
1026 @retval EFI_NOT_FOUND Kernel image was not found.
1027 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1028 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
1030 @return Error codes from any of the underlying
1031 functions. On success, the function doesn't
1036 QemuKernelLoaderFsDxeEntrypoint (
1037 IN EFI_HANDLE ImageHandle
,
1038 IN EFI_SYSTEM_TABLE
*SystemTable
1042 KERNEL_BLOB
*CurrentBlob
;
1043 KERNEL_BLOB
*KernelBlob
;
1045 EFI_HANDLE FileSystemHandle
;
1046 EFI_HANDLE InitrdLoadFile2Handle
;
1048 if (!QemuFwCfgIsAvailable ()) {
1049 return EFI_NOT_FOUND
;
1052 Status
= gRT
->GetTime (&mInitTime
, NULL
/* Capabilities */);
1053 if (EFI_ERROR (Status
)) {
1054 DEBUG ((DEBUG_ERROR
, "%a: GetTime(): %r\n", __FUNCTION__
, Status
));
1061 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
1062 CurrentBlob
= &mKernelBlob
[BlobType
];
1063 Status
= FetchBlob (CurrentBlob
);
1064 if (EFI_ERROR (Status
)) {
1068 Status
= VerifyBlob (
1073 if (EFI_ERROR (Status
)) {
1077 mTotalBlobBytes
+= CurrentBlob
->Size
;
1080 KernelBlob
= &mKernelBlob
[KernelBlobTypeKernel
];
1082 if (KernelBlob
->Data
== NULL
) {
1083 Status
= EFI_NOT_FOUND
;
1088 // Create a new handle with a single VenMedia() node device path protocol on
1089 // it, plus a custom SimpleFileSystem protocol on it.
1091 FileSystemHandle
= NULL
;
1092 Status
= gBS
->InstallMultipleProtocolInterfaces (
1094 &gEfiDevicePathProtocolGuid
,
1095 &mFileSystemDevicePath
,
1096 &gEfiSimpleFileSystemProtocolGuid
,
1100 if (EFI_ERROR (Status
)) {
1103 "%a: InstallMultipleProtocolInterfaces(): %r\n",
1110 if (KernelBlob
[KernelBlobTypeInitrd
].Size
> 0) {
1111 InitrdLoadFile2Handle
= NULL
;
1112 Status
= gBS
->InstallMultipleProtocolInterfaces (
1113 &InitrdLoadFile2Handle
,
1114 &gEfiDevicePathProtocolGuid
,
1116 &gEfiLoadFile2ProtocolGuid
,
1120 if (EFI_ERROR (Status
)) {
1123 "%a: InstallMultipleProtocolInterfaces(): %r\n",
1127 goto UninstallFileSystemHandle
;
1133 UninstallFileSystemHandle
:
1134 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1136 &gEfiDevicePathProtocolGuid
,
1137 &mFileSystemDevicePath
,
1138 &gEfiSimpleFileSystemProtocolGuid
,
1142 ASSERT_EFI_ERROR (Status
);
1145 while (BlobType
> 0) {
1146 CurrentBlob
= &mKernelBlob
[--BlobType
];
1147 if (CurrentBlob
->Data
!= NULL
) {
1148 FreePool (CurrentBlob
->Data
);
1149 CurrentBlob
->Size
= 0;
1150 CurrentBlob
->Data
= NULL
;