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/QemuKernelLoaderFsMedia.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/QemuFwCfgLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiRuntimeServicesTableLib.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/SimpleFileSystem.h>
28 // Static data that hosts the fw_cfg blobs and serves file requests.
37 FIRMWARE_CONFIG_ITEM CONST SizeKey
;
38 FIRMWARE_CONFIG_ITEM CONST DataKey
;
39 CONST CHAR16
* CONST Name
;
44 STATIC KERNEL_BLOB mKernelBlob
[KernelBlobTypeMax
] = {
45 { QemuFwCfgItemKernelSize
, QemuFwCfgItemKernelData
, L
"kernel" },
46 { QemuFwCfgItemInitrdSize
, QemuFwCfgItemInitrdData
, L
"initrd" },
49 STATIC UINT64 mTotalBlobBytes
;
52 // Device path for the handle that incorporates our "EFI stub filesystem".
56 VENDOR_DEVICE_PATH VenMediaNode
;
57 EFI_DEVICE_PATH_PROTOCOL EndNode
;
58 } SINGLE_VENMEDIA_NODE_DEVPATH
;
61 STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath
= {
64 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
65 { sizeof (VENDOR_DEVICE_PATH
) }
67 QEMU_KERNEL_LOADER_FS_MEDIA_GUID
69 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
70 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
75 // The "file in the EFI stub filesystem" abstraction.
77 STATIC EFI_TIME mInitTime
;
79 #define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
82 UINT64 Signature
; // Carries STUB_FILE_SIG.
84 KERNEL_BLOB_TYPE BlobType
; // Index into mKernelBlob. KernelBlobTypeMax
85 // denotes the root directory of the filesystem.
87 UINT64 Position
; // Byte position for regular files;
88 // next directory entry to return for the root
91 EFI_FILE_PROTOCOL File
; // Standard protocol interface.
94 #define STUB_FILE_FROM_FILE(FilePointer) \
95 CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
98 // Tentative definition of the file protocol template. The initializer
99 // (external definition) will be provided later.
101 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
;
105 // Protocol member functions for File.
109 Opens a new file relative to the source file's location.
111 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
112 the file handle to the source location. This would
113 typically be an open handle to a directory.
115 @param[out] NewHandle A pointer to the location to return the opened handle
118 @param[in] FileName The Null-terminated string of the name of the file to
119 be opened. The file name may contain the following
120 path modifiers: "\", ".", and "..".
122 @param[in] OpenMode The mode to open the file. The only valid
123 combinations that the file may be opened with are:
124 Read, Read/Write, or Create/Read/Write.
126 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case
127 these are the attribute bits for the newly created
130 @retval EFI_SUCCESS The file was opened.
131 @retval EFI_NOT_FOUND The specified file could not be found on the
133 @retval EFI_NO_MEDIA The device has no medium.
134 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
135 medium is no longer supported.
136 @retval EFI_DEVICE_ERROR The device reported an error.
137 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
138 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a
139 file for write when the media is
141 @retval EFI_ACCESS_DENIED The service denied access to the file.
142 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
144 @retval EFI_VOLUME_FULL The volume is full.
150 IN EFI_FILE_PROTOCOL
*This
,
151 OUT EFI_FILE_PROTOCOL
**NewHandle
,
157 CONST STUB_FILE
*StubFile
;
159 STUB_FILE
*NewStubFile
;
165 case EFI_FILE_MODE_READ
:
168 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
:
169 case EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
:
170 return EFI_WRITE_PROTECTED
;
173 return EFI_INVALID_PARAMETER
;
177 // Only the root directory supports opening files in it.
179 StubFile
= STUB_FILE_FROM_FILE (This
);
180 if (StubFile
->BlobType
!= KernelBlobTypeMax
) {
181 return EFI_UNSUPPORTED
;
187 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
188 if (StrCmp (FileName
, mKernelBlob
[BlobType
].Name
) == 0) {
192 if (BlobType
== KernelBlobTypeMax
) {
193 return EFI_NOT_FOUND
;
199 NewStubFile
= AllocatePool (sizeof *NewStubFile
);
200 if (NewStubFile
== NULL
) {
201 return EFI_OUT_OF_RESOURCES
;
204 NewStubFile
->Signature
= STUB_FILE_SIG
;
205 NewStubFile
->BlobType
= (KERNEL_BLOB_TYPE
)BlobType
;
206 NewStubFile
->Position
= 0;
207 CopyMem (&NewStubFile
->File
, &mEfiFileProtocolTemplate
,
208 sizeof mEfiFileProtocolTemplate
);
209 *NewHandle
= &NewStubFile
->File
;
216 Closes a specified file handle.
218 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
221 @retval EFI_SUCCESS The file was closed.
227 IN EFI_FILE_PROTOCOL
*This
230 FreePool (STUB_FILE_FROM_FILE (This
));
236 Close and delete the file handle.
238 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
239 handle to the file to delete.
241 @retval EFI_SUCCESS The file was closed and deleted, and the
243 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
251 IN EFI_FILE_PROTOCOL
*This
254 FreePool (STUB_FILE_FROM_FILE (This
));
255 return EFI_WARN_DELETE_FAILURE
;
260 Helper function that formats an EFI_FILE_INFO structure into the
261 user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
262 KernelBlobTypeMax, which stands for the root directory).
264 The interface follows the EFI_FILE_GET_INFO -- and for directories, the
265 EFI_FILE_READ -- interfaces.
267 @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
268 blob backing the STUB_FILE that information is
269 being requested about. If BlobType equals
270 KernelBlobTypeMax, then information will be
271 provided about the root directory of the
274 @param[in,out] BufferSize On input, the size of Buffer. On output, the
275 amount of data returned in Buffer. In both cases,
276 the size is measured in bytes.
278 @param[out] Buffer A pointer to the data buffer to return. The
279 buffer's type is EFI_FILE_INFO.
281 @retval EFI_SUCCESS The information was returned.
282 @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
283 EFI_FILE_INFO structure. BufferSize has been
284 updated with the size needed to complete the
289 ConvertKernelBlobTypeToFileInfo (
290 IN KERNEL_BLOB_TYPE BlobType
,
291 IN OUT UINTN
*BufferSize
,
301 EFI_FILE_INFO
*FileInfo
;
302 UINTN OriginalBufferSize
;
304 if (BlobType
== KernelBlobTypeMax
) {
306 // getting file info about the root directory
309 FileSize
= KernelBlobTypeMax
;
310 Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
312 CONST KERNEL_BLOB
*Blob
;
314 Blob
= &mKernelBlob
[BlobType
];
316 FileSize
= Blob
->Size
;
317 Attribute
= EFI_FILE_READ_ONLY
;
320 NameSize
= (StrLen(Name
) + 1) * 2;
321 FileInfoSize
= OFFSET_OF (EFI_FILE_INFO
, FileName
) + NameSize
;
322 ASSERT (FileInfoSize
>= sizeof *FileInfo
);
324 OriginalBufferSize
= *BufferSize
;
325 *BufferSize
= FileInfoSize
;
326 if (OriginalBufferSize
< *BufferSize
) {
327 return EFI_BUFFER_TOO_SMALL
;
330 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
331 FileInfo
->Size
= FileInfoSize
;
332 FileInfo
->FileSize
= FileSize
;
333 FileInfo
->PhysicalSize
= FileSize
;
334 FileInfo
->Attribute
= Attribute
;
336 CopyMem (&FileInfo
->CreateTime
, &mInitTime
, sizeof mInitTime
);
337 CopyMem (&FileInfo
->LastAccessTime
, &mInitTime
, sizeof mInitTime
);
338 CopyMem (&FileInfo
->ModificationTime
, &mInitTime
, sizeof mInitTime
);
339 CopyMem (FileInfo
->FileName
, Name
, NameSize
);
346 Reads data from a file, or continues scanning a directory.
348 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
349 is the file handle to read data from.
351 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
352 amount of data returned in Buffer. In both cases,
353 the size is measured in bytes. If the read goes
354 beyond the end of the file, the read length is
355 truncated to the end of the file.
357 If This is a directory, the function reads the
358 directory entry at the current position and
359 returns the entry (as EFI_FILE_INFO) in Buffer. If
360 there are no more directory entries, the
361 BufferSize is set to zero on output.
363 @param[out] Buffer The buffer into which the data is read.
365 @retval EFI_SUCCESS Data was read.
366 @retval EFI_NO_MEDIA The device has no medium.
367 @retval EFI_DEVICE_ERROR The device reported an error.
368 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
370 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
372 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
373 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
374 current directory entry as a EFI_FILE_INFO
375 structure. BufferSize has been updated with the
376 size needed to complete the request, and the
377 directory position has not been advanced.
383 IN EFI_FILE_PROTOCOL
*This
,
384 IN OUT UINTN
*BufferSize
,
389 CONST KERNEL_BLOB
*Blob
;
392 StubFile
= STUB_FILE_FROM_FILE (This
);
395 // Scanning the root directory?
397 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
400 if (StubFile
->Position
== KernelBlobTypeMax
) {
402 // Scanning complete.
408 Status
= ConvertKernelBlobTypeToFileInfo (
409 (KERNEL_BLOB_TYPE
)StubFile
->Position
,
412 if (EFI_ERROR (Status
)) {
416 ++StubFile
->Position
;
423 Blob
= &mKernelBlob
[StubFile
->BlobType
];
424 if (StubFile
->Position
> Blob
->Size
) {
425 return EFI_DEVICE_ERROR
;
428 Left
= Blob
->Size
- StubFile
->Position
;
429 if (*BufferSize
> Left
) {
430 *BufferSize
= (UINTN
)Left
;
432 if (Blob
->Data
!= NULL
) {
433 CopyMem (Buffer
, Blob
->Data
+ StubFile
->Position
, *BufferSize
);
435 StubFile
->Position
+= *BufferSize
;
441 Writes data to a file.
443 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
444 is the file handle to write data to.
446 @param[in,out] BufferSize On input, the size of the Buffer. On output, the
447 amount of data actually written. In both cases,
448 the size is measured in bytes.
450 @param[in] Buffer The buffer of data to write.
452 @retval EFI_SUCCESS Data was written.
453 @retval EFI_UNSUPPORTED Writes to open directory files are not
455 @retval EFI_NO_MEDIA The device has no medium.
456 @retval EFI_DEVICE_ERROR The device reported an error.
457 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
458 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
459 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
460 @retval EFI_ACCESS_DENIED The file was opened read only.
461 @retval EFI_VOLUME_FULL The volume is full.
467 IN EFI_FILE_PROTOCOL
*This
,
468 IN OUT UINTN
*BufferSize
,
474 StubFile
= STUB_FILE_FROM_FILE (This
);
475 return (StubFile
->BlobType
== KernelBlobTypeMax
) ?
482 Returns a file's current position.
484 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
485 file handle to get the current position on.
487 @param[out] Position The address to return the file's current position
490 @retval EFI_SUCCESS The position was returned.
491 @retval EFI_UNSUPPORTED The request is not valid on open directories.
492 @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
498 StubFileGetPosition (
499 IN EFI_FILE_PROTOCOL
*This
,
505 StubFile
= STUB_FILE_FROM_FILE (This
);
506 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
507 return EFI_UNSUPPORTED
;
510 *Position
= StubFile
->Position
;
516 Sets a file's current position.
518 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
519 file handle to set the requested position on.
521 @param[in] Position The byte position from the start of the file to set. For
522 regular files, MAX_UINT64 means "seek to end". For
523 directories, zero means "rewind directory scan".
525 @retval EFI_SUCCESS The position was set.
526 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
528 @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
534 StubFileSetPosition (
535 IN EFI_FILE_PROTOCOL
*This
,
542 StubFile
= STUB_FILE_FROM_FILE (This
);
544 if (StubFile
->BlobType
== KernelBlobTypeMax
) {
547 // rewinding a directory scan is allowed
549 StubFile
->Position
= 0;
552 return EFI_UNSUPPORTED
;
558 Blob
= &mKernelBlob
[StubFile
->BlobType
];
559 if (Position
== MAX_UINT64
) {
563 StubFile
->Position
= Blob
->Size
;
566 // absolute seek from beginning -- seeking past the end is allowed
568 StubFile
->Position
= Position
;
575 Returns information about a file.
577 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
578 that is the file handle the requested
581 @param[in] InformationType The type identifier GUID for the information
582 being requested. The following information
583 types are supported, storing the
584 corresponding structures in Buffer:
586 - gEfiFileInfoGuid: EFI_FILE_INFO
588 - gEfiFileSystemInfoGuid:
591 - gEfiFileSystemVolumeLabelInfoIdGuid:
592 EFI_FILE_SYSTEM_VOLUME_LABEL
594 @param[in,out] BufferSize On input, the size of Buffer. On output, the
595 amount of data returned in Buffer. In both
596 cases, the size is measured in bytes.
598 @param[out] Buffer A pointer to the data buffer to return. The
599 buffer's type is indicated by
602 @retval EFI_SUCCESS The information was returned.
603 @retval EFI_UNSUPPORTED The InformationType is not known.
604 @retval EFI_NO_MEDIA The device has no medium.
605 @retval EFI_DEVICE_ERROR The device reported an error.
606 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
607 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
608 information structure requested by
609 InformationType. BufferSize has been updated
610 with the size needed to complete the request.
616 IN EFI_FILE_PROTOCOL
*This
,
617 IN EFI_GUID
*InformationType
,
618 IN OUT UINTN
*BufferSize
,
622 CONST STUB_FILE
*StubFile
;
623 UINTN OriginalBufferSize
;
625 StubFile
= STUB_FILE_FROM_FILE (This
);
627 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
628 return ConvertKernelBlobTypeToFileInfo (StubFile
->BlobType
, BufferSize
,
632 OriginalBufferSize
= *BufferSize
;
634 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
635 EFI_FILE_SYSTEM_INFO
*FileSystemInfo
;
637 *BufferSize
= sizeof *FileSystemInfo
;
638 if (OriginalBufferSize
< *BufferSize
) {
639 return EFI_BUFFER_TOO_SMALL
;
642 FileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
643 FileSystemInfo
->Size
= sizeof *FileSystemInfo
;
644 FileSystemInfo
->ReadOnly
= TRUE
;
645 FileSystemInfo
->VolumeSize
= mTotalBlobBytes
;
646 FileSystemInfo
->FreeSpace
= 0;
647 FileSystemInfo
->BlockSize
= 1;
648 FileSystemInfo
->VolumeLabel
[0] = L
'\0';
653 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
654 EFI_FILE_SYSTEM_VOLUME_LABEL
*FileSystemVolumeLabel
;
656 *BufferSize
= sizeof *FileSystemVolumeLabel
;
657 if (OriginalBufferSize
< *BufferSize
) {
658 return EFI_BUFFER_TOO_SMALL
;
661 FileSystemVolumeLabel
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*)Buffer
;
662 FileSystemVolumeLabel
->VolumeLabel
[0] = L
'\0';
667 return EFI_UNSUPPORTED
;
672 Sets information about a file.
674 @param[in] File A pointer to the EFI_FILE_PROTOCOL instance that
675 is the file handle the information is for.
677 @param[in] InformationType The type identifier for the information being
680 @param[in] BufferSize The size, in bytes, of Buffer.
682 @param[in] Buffer A pointer to the data buffer to write. The
683 buffer's type is indicated by InformationType.
685 @retval EFI_SUCCESS The information was set.
686 @retval EFI_UNSUPPORTED The InformationType is not known.
687 @retval EFI_NO_MEDIA The device has no medium.
688 @retval EFI_DEVICE_ERROR The device reported an error.
689 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
690 @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the
692 @retval EFI_WRITE_PROTECTED InformationType is
693 EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
695 @retval EFI_WRITE_PROTECTED InformationType is
696 EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
698 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
699 to a file that is already present.
700 @retval EFI_ACCESS_DENIED An attempt is being made to change the
701 EFI_FILE_DIRECTORY Attribute.
702 @retval EFI_ACCESS_DENIED An attempt is being made to change the size of
704 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the
705 file was opened read-only and an attempt is
706 being made to modify a field other than
708 @retval EFI_VOLUME_FULL The volume is full.
709 @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type
710 indicated by InformationType.
716 IN EFI_FILE_PROTOCOL
*This
,
717 IN EFI_GUID
*InformationType
,
722 return EFI_WRITE_PROTECTED
;
727 Flushes all modified data associated with a file to a device.
729 @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
730 file handle to flush.
732 @retval EFI_SUCCESS The data was flushed.
733 @retval EFI_NO_MEDIA The device has no medium.
734 @retval EFI_DEVICE_ERROR The device reported an error.
735 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
736 @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
737 @retval EFI_ACCESS_DENIED The file was opened read-only.
738 @retval EFI_VOLUME_FULL The volume is full.
744 IN EFI_FILE_PROTOCOL
*This
747 return EFI_WRITE_PROTECTED
;
751 // External definition of the file protocol template.
753 STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate
= {
754 EFI_FILE_PROTOCOL_REVISION
, // revision 1
765 NULL
, // OpenEx, revision 2
766 NULL
, // ReadEx, revision 2
767 NULL
, // WriteEx, revision 2
768 NULL
// FlushEx, revision 2
773 // Protocol member functions for SimpleFileSystem.
777 Open the root directory on a volume.
779 @param[in] This A pointer to the volume to open the root directory on.
781 @param[out] Root A pointer to the location to return the opened file handle
782 for the root directory in.
784 @retval EFI_SUCCESS The device was opened.
785 @retval EFI_UNSUPPORTED This volume does not support the requested file
787 @retval EFI_NO_MEDIA The device has no medium.
788 @retval EFI_DEVICE_ERROR The device reported an error.
789 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
790 @retval EFI_ACCESS_DENIED The service denied access to the file.
791 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
793 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
794 medium is no longer supported. Any existing
795 file handles for this volume are no longer
796 valid. To access the files on the new medium,
797 the volume must be reopened with OpenVolume().
802 StubFileSystemOpenVolume (
803 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
804 OUT EFI_FILE_PROTOCOL
**Root
809 StubFile
= AllocatePool (sizeof *StubFile
);
810 if (StubFile
== NULL
) {
811 return EFI_OUT_OF_RESOURCES
;
814 StubFile
->Signature
= STUB_FILE_SIG
;
815 StubFile
->BlobType
= KernelBlobTypeMax
;
816 StubFile
->Position
= 0;
817 CopyMem (&StubFile
->File
, &mEfiFileProtocolTemplate
,
818 sizeof mEfiFileProtocolTemplate
);
819 *Root
= &StubFile
->File
;
824 STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem
= {
825 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
826 StubFileSystemOpenVolume
831 // Utility functions.
835 Populate a blob in mKernelBlob.
837 param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
838 to be filled from fw_cfg.
840 @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
841 size of zero for the blob, then Blob->Data has
844 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
849 IN OUT KERNEL_BLOB
*Blob
857 QemuFwCfgSelectItem (Blob
->SizeKey
);
858 Blob
->Size
= QemuFwCfgRead32 ();
859 if (Blob
->Size
== 0) {
866 Blob
->Data
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)Blob
->Size
));
867 if (Blob
->Data
== NULL
) {
868 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate %Ld bytes for \"%s\"\n",
869 __FUNCTION__
, (INT64
)Blob
->Size
, Blob
->Name
));
870 return EFI_OUT_OF_RESOURCES
;
873 DEBUG ((DEBUG_INFO
, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__
,
874 (INT64
)Blob
->Size
, Blob
->Name
));
875 QemuFwCfgSelectItem (Blob
->DataKey
);
881 Chunk
= (Left
< SIZE_1MB
) ? Left
: SIZE_1MB
;
882 QemuFwCfgReadBytes (Chunk
, Blob
->Data
+ (Blob
->Size
- Left
));
884 DEBUG ((DEBUG_VERBOSE
, "%a: %Ld bytes remaining for \"%s\"\n",
885 __FUNCTION__
, (INT64
)Left
, Blob
->Name
));
892 // The entry point of the feature.
896 Download the kernel, the initial ramdisk, and the kernel command line from
897 QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
900 @retval EFI_NOT_FOUND Kernel image was not found.
901 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
902 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
904 @return Error codes from any of the underlying
905 functions. On success, the function doesn't
910 QemuKernelLoaderFsDxeEntrypoint (
911 IN EFI_HANDLE ImageHandle
,
912 IN EFI_SYSTEM_TABLE
*SystemTable
916 KERNEL_BLOB
*CurrentBlob
;
917 KERNEL_BLOB
*KernelBlob
;
919 EFI_HANDLE FileSystemHandle
;
921 if (!QemuFwCfgIsAvailable ()) {
922 return EFI_NOT_FOUND
;
925 Status
= gRT
->GetTime (&mInitTime
, NULL
/* Capabilities */);
926 if (EFI_ERROR (Status
)) {
927 DEBUG ((DEBUG_ERROR
, "%a: GetTime(): %r\n", __FUNCTION__
, Status
));
934 for (BlobType
= 0; BlobType
< KernelBlobTypeMax
; ++BlobType
) {
935 CurrentBlob
= &mKernelBlob
[BlobType
];
936 Status
= FetchBlob (CurrentBlob
);
937 if (EFI_ERROR (Status
)) {
940 mTotalBlobBytes
+= CurrentBlob
->Size
;
942 KernelBlob
= &mKernelBlob
[KernelBlobTypeKernel
];
944 if (KernelBlob
->Data
== NULL
) {
945 Status
= EFI_NOT_FOUND
;
950 // Create a new handle with a single VenMedia() node device path protocol on
951 // it, plus a custom SimpleFileSystem protocol on it.
953 FileSystemHandle
= NULL
;
954 Status
= gBS
->InstallMultipleProtocolInterfaces (&FileSystemHandle
,
955 &gEfiDevicePathProtocolGuid
, &mFileSystemDevicePath
,
956 &gEfiSimpleFileSystemProtocolGuid
, &mFileSystem
,
958 if (EFI_ERROR (Status
)) {
959 DEBUG ((DEBUG_ERROR
, "%a: InstallMultipleProtocolInterfaces(): %r\n",
960 __FUNCTION__
, Status
));
967 while (BlobType
> 0) {
968 CurrentBlob
= &mKernelBlob
[--BlobType
];
969 if (CurrentBlob
->Data
!= NULL
) {
970 FreePages (CurrentBlob
->Data
,
971 EFI_SIZE_TO_PAGES ((UINTN
)CurrentBlob
->Size
));
972 CurrentBlob
->Size
= 0;
973 CurrentBlob
->Data
= NULL
;