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 // Tentative definition of the file protocol template. The initializer
128 // (external definition) will be provided later.
130 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
;
134 // Protocol member functions for File.
138 Opens a new file relative to the source file's location.
140 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
141 the file handle to the source location. This would
142 typically be an open handle to a directory.
144 @param[out] NewHandle A pointer to the location to return the opened handle
147 @param[in] FileName The Null-terminated string of the name of the file to
148 be opened. The file name may contain the following
149 path modifiers: "\", ".", and "..".
151 @param[in] OpenMode The mode to open the file. The only valid
152 combinations that the file may be opened with are:
153 Read, Read/Write, or Create/Read/Write.
155 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case
156 these are the attribute bits for the newly created
159 @retval EFI_SUCCESS The file was opened.
160 @retval EFI_NOT_FOUND The specified file could not be found on the
162 @retval EFI_NO_MEDIA The device has no medium.
163 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
164 medium is no longer supported.
165 @retval EFI_DEVICE_ERROR The device reported an error.
166 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
167 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a
168 file for write when the media is
170 @retval EFI_ACCESS_DENIED The service denied access to the file.
171 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
173 @retval EFI_VOLUME_FULL The volume is full.
179 IN EFI_FILE_PROTOCOL
*This
,
180 OUT EFI_FILE_PROTOCOL
**NewHandle
,
186 CONST STUB_FILE
*StubFile
;
188 STUB_FILE
*NewStubFile
;
194 case EFI_FILE_MODE_READ
:
197 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
:
198 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
:
199 return EFI_WRITE_PROTECTED
;
202 return EFI_INVALID_PARAMETER
;
206 // Only the root directory supports opening files in it.
208 StubFile
= STUB_FILE_FROM_FILE (This
);
209 if (StubFile
->BlobType
!= KernelBlobTypeMax
) {
210 return EFI_UNSUPPORTED
;
216 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
217 if (StrCmp (FileName
, mKernelBlob
[BlobType
].Name
) == 0) {
221 if (BlobType
== KernelBlobTypeMax
) {
222 return EFI_NOT_FOUND
;
228 NewStubFile
= AllocatePool (sizeof *NewStubFile
);
229 if (NewStubFile
== NULL
) {
230 return EFI_OUT_OF_RESOURCES
;
233 NewStubFile
->Signature
= STUB_FILE_SIG
;
234 NewStubFile
->BlobType
= (KERNEL_BLOB_TYPE
)BlobType
;
235 NewStubFile
->Position
= 0;
236 CopyMem (&NewStubFile
->File
, &mEfiFileProtocolTemplate
,
237 sizeof mEfiFileProtocolTemplate
);
238 *NewHandle
= &NewStubFile
->File
;
245 Closes a specified file handle.
247 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
250 @retval EFI_SUCCESS The file was closed.
256 IN EFI_FILE_PROTOCOL
*This
259 FreePool (STUB_FILE_FROM_FILE (This
));
265 Close and delete the file handle.
267 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
268 handle to the file to delete.
270 @retval EFI_SUCCESS The file was closed and deleted, and the
272 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
280 IN EFI_FILE_PROTOCOL
*This
283 FreePool (STUB_FILE_FROM_FILE (This
));
284 return EFI_WARN_DELETE_FAILURE
;
289 Helper function that formats an EFI_FILE_INFO structure into the
290 user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
291 KernelBlobTypeMax, which stands for the root directory).
293 The interface follows the EFI_FILE_GET_INFO -- and for directories, the
294 EFI_FILE_READ -- interfaces.
296 @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
297 blob backing the STUB_FILE that information is
298 being requested about. If BlobType equals
299 KernelBlobTypeMax, then information will be
300 provided about the root directory of the
303 @param[in,out] BufferSize On input, the size of Buffer. On output, the
304 amount of data returned in Buffer. In both cases,
305 the size is measured in bytes.
307 @param[out] Buffer A pointer to the data buffer to return. The
308 buffer's type is EFI_FILE_INFO.
310 @retval EFI_SUCCESS The information was returned.
311 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
312 EFI_FILE_INFO structure. BufferSize has been
313 updated with the size needed to complete the
318 ConvertKernelBlobTypeToFileInfo (
319 IN KERNEL_BLOB_TYPE BlobType
,
320 IN OUT UINTN
*BufferSize
,
330 EFI_FILE_INFO
*FileInfo
;
331 UINTN OriginalBufferSize
;
333 if (BlobType
== KernelBlobTypeMax
) {
335 // getting file info about the root directory
338 FileSize
= KernelBlobTypeMax
;
339 Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
341 CONST KERNEL_BLOB
*Blob
;
343 Blob
= &mKernelBlob
[BlobType
];
345 FileSize
= Blob
->Size
;
346 Attribute
= EFI_FILE_READ_ONLY
;
349 NameSize
= (StrLen(Name
) + 1) * 2;
350 FileInfoSize
= OFFSET_OF (EFI_FILE_INFO
, FileName
) + NameSize
;
351 ASSERT (FileInfoSize
>= sizeof *FileInfo
);
353 OriginalBufferSize
= *BufferSize
;
354 *BufferSize
= FileInfoSize
;
355 if (OriginalBufferSize
< *BufferSize
) {
356 return EFI_BUFFER_TOO_SMALL
;
359 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
360 FileInfo
->Size
= FileInfoSize
;
361 FileInfo
->FileSize
= FileSize
;
362 FileInfo
->PhysicalSize
= FileSize
;
363 FileInfo
->Attribute
= Attribute
;
365 CopyMem (&FileInfo
->CreateTime
, &mInitTime
, sizeof mInitTime
);
366 CopyMem (&FileInfo
->LastAccessTime
, &mInitTime
, sizeof mInitTime
);
367 CopyMem (&FileInfo
->ModificationTime
, &mInitTime
, sizeof mInitTime
);
368 CopyMem (FileInfo
->FileName
, Name
, NameSize
);
375 Reads data from a file, or continues scanning a directory.
377 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
378 is the file handle to read data from.
380 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
381 amount of data returned in Buffer. In both cases,
382 the size is measured in bytes. If the read goes
383 beyond the end of the file, the read length is
384 truncated to the end of the file.
386 If This is a directory, the function reads the
387 directory entry at the current position and
388 returns the entry (as EFI_FILE_INFO) in Buffer. If
389 there are no more directory entries, the
390 BufferSize is set to zero on output.
392 @param[out] Buffer The buffer into which the data is read.
394 @retval EFI_SUCCESS Data was read.
395 @retval EFI_NO_MEDIA The device has no medium.
396 @retval EFI_DEVICE_ERROR The device reported an error.
397 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
399 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
401 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
402 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
403 current directory entry as a EFI_FILE_INFO
404 structure. BufferSize has been updated with the
405 size needed to complete the request, and the
406 directory position has not been advanced.
412 IN EFI_FILE_PROTOCOL
*This
,
413 IN OUT UINTN
*BufferSize
,
418 CONST KERNEL_BLOB
*Blob
;
421 StubFile
= STUB_FILE_FROM_FILE (This
);
424 // Scanning the root directory?
426 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
429 if (StubFile
->Position
== KernelBlobTypeMax
) {
431 // Scanning complete.
437 Status
= ConvertKernelBlobTypeToFileInfo (
438 (KERNEL_BLOB_TYPE
)StubFile
->Position
,
441 if (EFI_ERROR (Status
)) {
445 ++StubFile
->Position
;
452 Blob
= &mKernelBlob
[StubFile
->BlobType
];
453 if (StubFile
->Position
> Blob
->Size
) {
454 return EFI_DEVICE_ERROR
;
457 Left
= Blob
->Size
- StubFile
->Position
;
458 if (*BufferSize
> Left
) {
459 *BufferSize
= (UINTN
)Left
;
461 if (Blob
->Data
!= NULL
) {
462 CopyMem (Buffer
, Blob
->Data
+ StubFile
->Position
, *BufferSize
);
464 StubFile
->Position
+= *BufferSize
;
470 Writes data to a file.
472 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
473 is the file handle to write data to.
475 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
476 amount of data actually written. In both cases,
477 the size is measured in bytes.
479 @param[in] Buffer The buffer of data to write.
481 @retval EFI_SUCCESS Data was written.
482 @retval EFI_UNSUPPORTED Writes to open directory files are not
484 @retval EFI_NO_MEDIA The device has no medium.
485 @retval EFI_DEVICE_ERROR The device reported an error.
486 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
487 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
488 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
489 @retval EFI_ACCESS_DENIED The file was opened read only.
490 @retval EFI_VOLUME_FULL The volume is full.
496 IN EFI_FILE_PROTOCOL
*This
,
497 IN OUT UINTN
*BufferSize
,
503 StubFile
= STUB_FILE_FROM_FILE (This
);
504 return (StubFile
->BlobType
== KernelBlobTypeMax
) ?
511 Returns a file's current position.
513 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
514 file handle to get the current position on.
516 @param[out] Position The address to return the file's current position
519 @retval EFI_SUCCESS The position was returned.
520 @retval EFI_UNSUPPORTED The request is not valid on open directories.
521 @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
527 StubFileGetPosition (
528 IN EFI_FILE_PROTOCOL
*This
,
534 StubFile
= STUB_FILE_FROM_FILE (This
);
535 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
536 return EFI_UNSUPPORTED
;
539 *Position
= StubFile
->Position
;
545 Sets a file's current position.
547 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
548 file handle to set the requested position on.
550 @param[in] Position The byte position from the start of the file to set. For
551 regular files, MAX_UINT64 means "seek to end". For
552 directories, zero means "rewind directory scan".
554 @retval EFI_SUCCESS The position was set.
555 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
557 @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
563 StubFileSetPosition (
564 IN EFI_FILE_PROTOCOL
*This
,
571 StubFile
= STUB_FILE_FROM_FILE (This
);
573 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
576 // rewinding a directory scan is allowed
578 StubFile
->Position
= 0;
581 return EFI_UNSUPPORTED
;
587 Blob
= &mKernelBlob
[StubFile
->BlobType
];
588 if (Position
== MAX_UINT64
) {
592 StubFile
->Position
= Blob
->Size
;
595 // absolute seek from beginning -- seeking past the end is allowed
597 StubFile
->Position
= Position
;
604 Returns information about a file.
606 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
607 that is the file handle the requested
610 @param[in] InformationType The type identifier GUID for the information
611 being requested. The following information
612 types are supported, storing the
613 corresponding structures in Buffer:
615 - gEfiFileInfoGuid: EFI_FILE_INFO
617 - gEfiFileSystemInfoGuid:
620 - gEfiFileSystemVolumeLabelInfoIdGuid:
621 EFI_FILE_SYSTEM_VOLUME_LABEL
623 @param[in,out] BufferSize On input, the size of Buffer. On output, the
624 amount of data returned in Buffer. In both
625 cases, the size is measured in bytes.
627 @param[out] Buffer A pointer to the data buffer to return. The
628 buffer's type is indicated by
631 @retval EFI_SUCCESS The information was returned.
632 @retval EFI_UNSUPPORTED The InformationType is not known.
633 @retval EFI_NO_MEDIA The device has no medium.
634 @retval EFI_DEVICE_ERROR The device reported an error.
635 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
636 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
637 information structure requested by
638 InformationType. BufferSize has been updated
639 with the size needed to complete the request.
645 IN EFI_FILE_PROTOCOL
*This
,
646 IN EFI_GUID
*InformationType
,
647 IN OUT UINTN
*BufferSize
,
651 CONST STUB_FILE
*StubFile
;
652 UINTN OriginalBufferSize
;
654 StubFile
= STUB_FILE_FROM_FILE (This
);
656 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
657 return ConvertKernelBlobTypeToFileInfo (StubFile
->BlobType
, BufferSize
,
661 OriginalBufferSize
= *BufferSize
;
663 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
664 EFI_FILE_SYSTEM_INFO
*FileSystemInfo
;
666 *BufferSize
= sizeof *FileSystemInfo
;
667 if (OriginalBufferSize
< *BufferSize
) {
668 return EFI_BUFFER_TOO_SMALL
;
671 FileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
672 FileSystemInfo
->Size
= sizeof *FileSystemInfo
;
673 FileSystemInfo
->ReadOnly
= TRUE
;
674 FileSystemInfo
->VolumeSize
= mTotalBlobBytes
;
675 FileSystemInfo
->FreeSpace
= 0;
676 FileSystemInfo
->BlockSize
= 1;
677 FileSystemInfo
->VolumeLabel
[0] = L
'\0';
682 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
683 EFI_FILE_SYSTEM_VOLUME_LABEL
*FileSystemVolumeLabel
;
685 *BufferSize
= sizeof *FileSystemVolumeLabel
;
686 if (OriginalBufferSize
< *BufferSize
) {
687 return EFI_BUFFER_TOO_SMALL
;
690 FileSystemVolumeLabel
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*)Buffer
;
691 FileSystemVolumeLabel
->VolumeLabel
[0] = L
'\0';
696 return EFI_UNSUPPORTED
;
701 Sets information about a file.
703 @param[in] File A pointer to the EFI_FILE_PROTOCOL instance that
704 is the file handle the information is for.
706 @param[in] InformationType The type identifier for the information being
709 @param[in] BufferSize The size, in bytes, of Buffer.
711 @param[in] Buffer A pointer to the data buffer to write. The
712 buffer's type is indicated by InformationType.
714 @retval EFI_SUCCESS The information was set.
715 @retval EFI_UNSUPPORTED The InformationType is not known.
716 @retval EFI_NO_MEDIA The device has no medium.
717 @retval EFI_DEVICE_ERROR The device reported an error.
718 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
719 @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the
721 @retval EFI_WRITE_PROTECTED InformationType is
722 EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
724 @retval EFI_WRITE_PROTECTED InformationType is
725 EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
727 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
728 to a file that is already present.
729 @retval EFI_ACCESS_DENIED An attempt is being made to change the
730 EFI_FILE_DIRECTORY Attribute.
731 @retval EFI_ACCESS_DENIED An attempt is being made to change the size of
733 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the
734 file was opened read-only and an attempt is
735 being made to modify a field other than
737 @retval EFI_VOLUME_FULL The volume is full.
738 @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type
739 indicated by InformationType.
745 IN EFI_FILE_PROTOCOL
*This
,
746 IN EFI_GUID
*InformationType
,
751 return EFI_WRITE_PROTECTED
;
756 Flushes all modified data associated with a file to a device.
758 @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
759 file handle to flush.
761 @retval EFI_SUCCESS The data was flushed.
762 @retval EFI_NO_MEDIA The device has no medium.
763 @retval EFI_DEVICE_ERROR The device reported an error.
764 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
765 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
766 @retval EFI_ACCESS_DENIED The file was opened read-only.
767 @retval EFI_VOLUME_FULL The volume is full.
773 IN EFI_FILE_PROTOCOL
*This
776 return EFI_WRITE_PROTECTED
;
780 // External definition of the file protocol template.
782 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
= {
783 EFI_FILE_PROTOCOL_REVISION
, // revision 1
794 NULL
, // OpenEx, revision 2
795 NULL
, // ReadEx, revision 2
796 NULL
, // WriteEx, revision 2
797 NULL
// FlushEx, revision 2
802 // Protocol member functions for SimpleFileSystem.
806 Open the root directory on a volume.
808 @param[in] This A pointer to the volume to open the root directory on.
810 @param[out] Root A pointer to the location to return the opened file handle
811 for the root directory in.
813 @retval EFI_SUCCESS The device was opened.
814 @retval EFI_UNSUPPORTED This volume does not support the requested file
816 @retval EFI_NO_MEDIA The device has no medium.
817 @retval EFI_DEVICE_ERROR The device reported an error.
818 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
819 @retval EFI_ACCESS_DENIED The service denied access to the file.
820 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
822 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
823 medium is no longer supported. Any existing
824 file handles for this volume are no longer
825 valid. To access the files on the new medium,
826 the volume must be reopened with OpenVolume().
831 StubFileSystemOpenVolume (
832 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
833 OUT EFI_FILE_PROTOCOL
**Root
838 StubFile
= AllocatePool (sizeof *StubFile
);
839 if (StubFile
== NULL
) {
840 return EFI_OUT_OF_RESOURCES
;
843 StubFile
->Signature
= STUB_FILE_SIG
;
844 StubFile
->BlobType
= KernelBlobTypeMax
;
845 StubFile
->Position
= 0;
846 CopyMem (&StubFile
->File
, &mEfiFileProtocolTemplate
,
847 sizeof mEfiFileProtocolTemplate
);
848 *Root
= &StubFile
->File
;
853 STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem
= {
854 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
855 StubFileSystemOpenVolume
862 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
863 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
864 IN BOOLEAN BootPolicy
,
865 IN OUT UINTN
*BufferSize
,
866 OUT VOID
*Buffer OPTIONAL
869 CONST KERNEL_BLOB
*InitrdBlob
= &mKernelBlob
[KernelBlobTypeInitrd
];
871 ASSERT (InitrdBlob
->Size
> 0);
874 return EFI_UNSUPPORTED
;
877 if (BufferSize
== NULL
|| !IsDevicePathValid (FilePath
, 0)) {
878 return EFI_INVALID_PARAMETER
;
881 if (FilePath
->Type
!= END_DEVICE_PATH_TYPE
||
882 FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
) {
883 return EFI_NOT_FOUND
;
886 if (Buffer
== NULL
|| *BufferSize
< InitrdBlob
->Size
) {
887 *BufferSize
= InitrdBlob
->Size
;
888 return EFI_BUFFER_TOO_SMALL
;
891 CopyMem (Buffer
, InitrdBlob
->Data
, InitrdBlob
->Size
);
893 *BufferSize
= InitrdBlob
->Size
;
897 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
902 // Utility functions.
906 Populate a blob in mKernelBlob.
908 param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
909 to be filled from fw_cfg.
911 @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
912 size of zero for the blob, then Blob->Data has
915 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
920 IN OUT KERNEL_BLOB
*Blob
931 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
932 if (Blob
->FwCfgItem
[Idx
].SizeKey
== 0) {
935 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].SizeKey
);
936 Blob
->FwCfgItem
[Idx
].Size
= QemuFwCfgRead32 ();
937 Blob
->Size
+= Blob
->FwCfgItem
[Idx
].Size
;
939 if (Blob
->Size
== 0) {
946 Blob
->Data
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)Blob
->Size
));
947 if (Blob
->Data
== NULL
) {
948 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate %Ld bytes for \"%s\"\n",
949 __FUNCTION__
, (INT64
)Blob
->Size
, Blob
->Name
));
950 return EFI_OUT_OF_RESOURCES
;
953 DEBUG ((DEBUG_INFO
, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__
,
954 (INT64
)Blob
->Size
, Blob
->Name
));
956 ChunkData
= Blob
->Data
;
957 for (Idx
= 0; Idx
< ARRAY_SIZE (Blob
->FwCfgItem
); Idx
++) {
958 if (Blob
->FwCfgItem
[Idx
].DataKey
== 0) {
961 QemuFwCfgSelectItem (Blob
->FwCfgItem
[Idx
].DataKey
);
963 Left
= Blob
->FwCfgItem
[Idx
].Size
;
967 Chunk
= (Left
< SIZE_1MB
) ? Left
: SIZE_1MB
;
968 QemuFwCfgReadBytes (Chunk
, ChunkData
+ Blob
->FwCfgItem
[Idx
].Size
- Left
);
970 DEBUG ((DEBUG_VERBOSE
, "%a: %Ld bytes remaining for \"%s\" (%d)\n",
971 __FUNCTION__
, (INT64
)Left
, Blob
->Name
, (INT32
)Idx
));
974 ChunkData
+= Blob
->FwCfgItem
[Idx
].Size
;
982 // The entry point of the feature.
986 Download the kernel, the initial ramdisk, and the kernel command line from
987 QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
990 @retval EFI_NOT_FOUND Kernel image was not found.
991 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
992 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
994 @return Error codes from any of the underlying
995 functions. On success, the function doesn't
1000 QemuKernelLoaderFsDxeEntrypoint (
1001 IN EFI_HANDLE ImageHandle
,
1002 IN EFI_SYSTEM_TABLE
*SystemTable
1006 KERNEL_BLOB
*CurrentBlob
;
1007 KERNEL_BLOB
*KernelBlob
;
1009 EFI_HANDLE FileSystemHandle
;
1010 EFI_HANDLE InitrdLoadFile2Handle
;
1012 if (!QemuFwCfgIsAvailable ()) {
1013 return EFI_NOT_FOUND
;
1016 Status
= gRT
->GetTime (&mInitTime
, NULL
/* Capabilities */);
1017 if (EFI_ERROR (Status
)) {
1018 DEBUG ((DEBUG_ERROR
, "%a: GetTime(): %r\n", __FUNCTION__
, Status
));
1025 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
1026 CurrentBlob
= &mKernelBlob
[BlobType
];
1027 Status
= FetchBlob (CurrentBlob
);
1028 if (EFI_ERROR (Status
)) {
1031 mTotalBlobBytes
+= CurrentBlob
->Size
;
1033 KernelBlob
= &mKernelBlob
[KernelBlobTypeKernel
];
1035 if (KernelBlob
->Data
== NULL
) {
1036 Status
= EFI_NOT_FOUND
;
1041 // Create a new handle with a single VenMedia() node device path protocol on
1042 // it, plus a custom SimpleFileSystem protocol on it.
1044 FileSystemHandle
= NULL
;
1045 Status
= gBS
->InstallMultipleProtocolInterfaces (&FileSystemHandle
,
1046 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1047 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1049 if (EFI_ERROR (Status
)) {
1050 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1051 __FUNCTION__
, Status
));
1055 if (KernelBlob
[KernelBlobTypeInitrd
].Size
> 0) {
1056 InitrdLoadFile2Handle
= NULL
;
1057 Status
= gBS
->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle
,
1058 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
1059 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
1061 if (EFI_ERROR (Status
)) {
1062 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
1063 __FUNCTION__
, Status
));
1064 goto UninstallFileSystemHandle
;
1070 UninstallFileSystemHandle
:
1071 Status
= gBS
->UninstallMultipleProtocolInterfaces (FileSystemHandle
,
1072 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
1073 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
1075 ASSERT_EFI_ERROR (Status
);
1078 while (BlobType
> 0) {
1079 CurrentBlob
= &mKernelBlob
[--BlobType
];
1080 if (CurrentBlob
->Data
!= NULL
) {
1081 FreePages (CurrentBlob
->Data
,
1082 EFI_SIZE_TO_PAGES ((UINTN
)CurrentBlob
->Size
));
1083 CurrentBlob
->Size
= 0;
1084 CurrentBlob
->Data
= NULL
;