__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout OvmfPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
		
			
				
	
	
		
			1156 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1156 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   DXE driver to expose the 'kernel', 'initrd' and 'cmdline' blobs
 | |
|   provided by QEMU as files in an abstract file system
 | |
| 
 | |
|   Copyright (C) 2014-2016, Red Hat, Inc.
 | |
|   Copyright (C) 2020, Arm, Limited.
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| **/
 | |
| 
 | |
| #include <PiDxe.h>
 | |
| 
 | |
| #include <Guid/FileInfo.h>
 | |
| #include <Guid/FileSystemInfo.h>
 | |
| #include <Guid/FileSystemVolumeLabelInfo.h>
 | |
| #include <Guid/LinuxEfiInitrdMedia.h>
 | |
| #include <Guid/QemuKernelLoaderFsMedia.h>
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/BlobVerifierLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/DevicePathLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/QemuFwCfgLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiRuntimeServicesTableLib.h>
 | |
| #include <Protocol/DevicePath.h>
 | |
| #include <Protocol/LoadFile2.h>
 | |
| #include <Protocol/SimpleFileSystem.h>
 | |
| 
 | |
| //
 | |
| // Static data that hosts the fw_cfg blobs and serves file requests.
 | |
| //
 | |
| typedef enum {
 | |
|   KernelBlobTypeKernel,
 | |
|   KernelBlobTypeInitrd,
 | |
|   KernelBlobTypeCommandLine,
 | |
|   KernelBlobTypeMax
 | |
| } KERNEL_BLOB_TYPE;
 | |
| 
 | |
| typedef struct {
 | |
|   CONST CHAR16    Name[8];
 | |
|   struct {
 | |
|     FIRMWARE_CONFIG_ITEM CONST    SizeKey;
 | |
|     FIRMWARE_CONFIG_ITEM CONST    DataKey;
 | |
|     UINT32                        Size;
 | |
|   }                             FwCfgItem[2];
 | |
|   UINT32          Size;
 | |
|   UINT8           *Data;
 | |
| } KERNEL_BLOB;
 | |
| 
 | |
| STATIC KERNEL_BLOB  mKernelBlob[KernelBlobTypeMax] = {
 | |
|   {
 | |
|     L"kernel",
 | |
|     {
 | |
|       { QemuFwCfgItemKernelSetupSize, QemuFwCfgItemKernelSetupData, },
 | |
|       { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      },
 | |
|     }
 | |
|   },  {
 | |
|     L"initrd",
 | |
|     {
 | |
|       { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      },
 | |
|     }
 | |
|   },  {
 | |
|     L"cmdline",
 | |
|     {
 | |
|       { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, },
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| STATIC UINT64  mTotalBlobBytes;
 | |
| 
 | |
| //
 | |
| // Device path for the handle that incorporates our "EFI stub filesystem".
 | |
| //
 | |
| #pragma pack (1)
 | |
| typedef struct {
 | |
|   VENDOR_DEVICE_PATH          VenMediaNode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL    EndNode;
 | |
| } SINGLE_VENMEDIA_NODE_DEVPATH;
 | |
| #pragma pack ()
 | |
| 
 | |
| STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH  mFileSystemDevicePath = {
 | |
|   {
 | |
|     {
 | |
|       MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
 | |
|       { sizeof (VENDOR_DEVICE_PATH)       }
 | |
|     },
 | |
|     QEMU_KERNEL_LOADER_FS_MEDIA_GUID
 | |
|   },  {
 | |
|     END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | |
|     { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
 | |
|   }
 | |
| };
 | |
| 
 | |
| STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH  mInitrdDevicePath = {
 | |
|   {
 | |
|     {
 | |
|       MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
 | |
|       { sizeof (VENDOR_DEVICE_PATH)       }
 | |
|     },
 | |
|     LINUX_EFI_INITRD_MEDIA_GUID
 | |
|   },  {
 | |
|     END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | |
|     { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
 | |
|   }
 | |
| };
 | |
| 
 | |
| //
 | |
| // The "file in the EFI stub filesystem" abstraction.
 | |
| //
 | |
| STATIC EFI_TIME  mInitTime;
 | |
| 
 | |
| #define STUB_FILE_SIG  SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
 | |
| 
 | |
| typedef struct {
 | |
|   UINT64               Signature; // Carries STUB_FILE_SIG.
 | |
| 
 | |
|   KERNEL_BLOB_TYPE     BlobType; // Index into mKernelBlob. KernelBlobTypeMax
 | |
|                                  // denotes the root directory of the filesystem.
 | |
| 
 | |
|   UINT64               Position; // Byte position for regular files;
 | |
|                                  // next directory entry to return for the root
 | |
|                                  // directory.
 | |
| 
 | |
|   EFI_FILE_PROTOCOL    File;   // Standard protocol interface.
 | |
| } STUB_FILE;
 | |
| 
 | |
| #define STUB_FILE_FROM_FILE(FilePointer) \
 | |
|         CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
 | |
| 
 | |
| //
 | |
| // Protocol member functions for File.
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Opens a new file relative to the source file's location.
 | |
| 
 | |
|   (Forward declaration.)
 | |
| 
 | |
|   @param[in]  This        A pointer to the EFI_FILE_PROTOCOL instance that is
 | |
|                           the file handle to the source location. This would
 | |
|                           typically be an open handle to a directory.
 | |
| 
 | |
|   @param[out] NewHandle   A pointer to the location to return the opened handle
 | |
|                           for the new file.
 | |
| 
 | |
|   @param[in]  FileName    The Null-terminated string of the name of the file to
 | |
|                           be opened. The file name may contain the following
 | |
|                           path modifiers: "\", ".", and "..".
 | |
| 
 | |
|   @param[in]  OpenMode    The mode to open the file. The only valid
 | |
|                           combinations that the file may be opened with are:
 | |
|                           Read, Read/Write, or Create/Read/Write.
 | |
| 
 | |
|   @param[in]  Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case
 | |
|                           these are the attribute bits for the newly created
 | |
|                           file.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file was opened.
 | |
|   @retval EFI_NOT_FOUND         The specified file could not be found on the
 | |
|                                 device.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
 | |
|                                 medium is no longer supported.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a
 | |
|                                 file for write when the media is
 | |
|                                 write-protected.
 | |
|   @retval EFI_ACCESS_DENIED     The service denied access to the file.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
 | |
|                                 file.
 | |
|   @retval EFI_VOLUME_FULL       The volume is full.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileOpen (
 | |
|   IN EFI_FILE_PROTOCOL   *This,
 | |
|   OUT EFI_FILE_PROTOCOL  **NewHandle,
 | |
|   IN CHAR16              *FileName,
 | |
|   IN UINT64              OpenMode,
 | |
|   IN UINT64              Attributes
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Closes a specified file handle.
 | |
| 
 | |
|   @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
 | |
|                    handle to close.
 | |
| 
 | |
|   @retval EFI_SUCCESS  The file was closed.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileClose (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   FreePool (STUB_FILE_FROM_FILE (This));
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Close and delete the file handle.
 | |
| 
 | |
|   @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
 | |
|                    handle to the file to delete.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The file was closed and deleted, and the
 | |
|                                    handle was closed.
 | |
|   @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not
 | |
|                                    deleted.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileDelete (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   FreePool (STUB_FILE_FROM_FILE (This));
 | |
|   return EFI_WARN_DELETE_FAILURE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Helper function that formats an EFI_FILE_INFO structure into the
 | |
|   user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
 | |
|   KernelBlobTypeMax, which stands for the root directory).
 | |
| 
 | |
|   The interface follows the EFI_FILE_GET_INFO -- and for directories, the
 | |
|   EFI_FILE_READ -- interfaces.
 | |
| 
 | |
|   @param[in]     BlobType     The KERNEL_BLOB_TYPE value identifying the fw_cfg
 | |
|                               blob backing the STUB_FILE that information is
 | |
|                               being requested about. If BlobType equals
 | |
|                               KernelBlobTypeMax, then information will be
 | |
|                               provided about the root directory of the
 | |
|                               filesystem.
 | |
| 
 | |
|   @param[in,out] BufferSize  On input, the size of Buffer. On output, the
 | |
|                              amount of data returned in Buffer. In both cases,
 | |
|                              the size is measured in bytes.
 | |
| 
 | |
|   @param[out]    Buffer      A pointer to the data buffer to return. The
 | |
|                              buffer's type is EFI_FILE_INFO.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The information was returned.
 | |
|   @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small to store the
 | |
|                                 EFI_FILE_INFO structure. BufferSize has been
 | |
|                                 updated with the size needed to complete the
 | |
|                                 request.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| ConvertKernelBlobTypeToFileInfo (
 | |
|   IN KERNEL_BLOB_TYPE  BlobType,
 | |
|   IN OUT UINTN         *BufferSize,
 | |
|   OUT VOID             *Buffer
 | |
|   )
 | |
| {
 | |
|   CONST CHAR16  *Name;
 | |
|   UINT64        FileSize;
 | |
|   UINT64        Attribute;
 | |
| 
 | |
|   UINTN          NameSize;
 | |
|   UINTN          FileInfoSize;
 | |
|   EFI_FILE_INFO  *FileInfo;
 | |
|   UINTN          OriginalBufferSize;
 | |
| 
 | |
|   if (BlobType == KernelBlobTypeMax) {
 | |
|     //
 | |
|     // getting file info about the root directory
 | |
|     //
 | |
|     Name      = L"\\";
 | |
|     FileSize  = KernelBlobTypeMax;
 | |
|     Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
 | |
|   } else {
 | |
|     CONST KERNEL_BLOB  *Blob;
 | |
| 
 | |
|     Blob      = &mKernelBlob[BlobType];
 | |
|     Name      = Blob->Name;
 | |
|     FileSize  = Blob->Size;
 | |
|     Attribute = EFI_FILE_READ_ONLY;
 | |
|   }
 | |
| 
 | |
|   NameSize     = (StrLen (Name) + 1) * 2;
 | |
|   FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;
 | |
|   ASSERT (FileInfoSize >= sizeof *FileInfo);
 | |
| 
 | |
|   OriginalBufferSize = *BufferSize;
 | |
|   *BufferSize        = FileInfoSize;
 | |
|   if (OriginalBufferSize < *BufferSize) {
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   FileInfo               = (EFI_FILE_INFO *)Buffer;
 | |
|   FileInfo->Size         = FileInfoSize;
 | |
|   FileInfo->FileSize     = FileSize;
 | |
|   FileInfo->PhysicalSize = FileSize;
 | |
|   FileInfo->Attribute    = Attribute;
 | |
| 
 | |
|   CopyMem (&FileInfo->CreateTime, &mInitTime, sizeof mInitTime);
 | |
|   CopyMem (&FileInfo->LastAccessTime, &mInitTime, sizeof mInitTime);
 | |
|   CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);
 | |
|   CopyMem (FileInfo->FileName, Name, NameSize);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads data from a file, or continues scanning a directory.
 | |
| 
 | |
|   @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
 | |
|                              is the file handle to read data from.
 | |
| 
 | |
|   @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
 | |
|                              amount of data returned in Buffer. In both cases,
 | |
|                              the size is measured in bytes. If the read goes
 | |
|                              beyond the end of the file, the read length is
 | |
|                              truncated to the end of the file.
 | |
| 
 | |
|                              If This is a directory, the function reads the
 | |
|                              directory entry at the current position and
 | |
|                              returns the entry (as EFI_FILE_INFO) in Buffer. If
 | |
|                              there are no more directory entries, the
 | |
|                              BufferSize is set to zero on output.
 | |
| 
 | |
|   @param[out]    Buffer      The buffer into which the data is read.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Data was read.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted
 | |
|                                 file.
 | |
|   @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond
 | |
|                                 the end of the file.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
 | |
|                                 current directory entry as a EFI_FILE_INFO
 | |
|                                 structure. BufferSize has been updated with the
 | |
|                                 size needed to complete the request, and the
 | |
|                                 directory position has not been advanced.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileRead (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT VOID              *Buffer
 | |
|   )
 | |
| {
 | |
|   STUB_FILE          *StubFile;
 | |
|   CONST KERNEL_BLOB  *Blob;
 | |
|   UINT64             Left;
 | |
| 
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
| 
 | |
|   //
 | |
|   // Scanning the root directory?
 | |
|   //
 | |
|   if (StubFile->BlobType == KernelBlobTypeMax) {
 | |
|     EFI_STATUS  Status;
 | |
| 
 | |
|     if (StubFile->Position == KernelBlobTypeMax) {
 | |
|       //
 | |
|       // Scanning complete.
 | |
|       //
 | |
|       *BufferSize = 0;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Status = ConvertKernelBlobTypeToFileInfo (
 | |
|                (KERNEL_BLOB_TYPE)StubFile->Position,
 | |
|                BufferSize,
 | |
|                Buffer
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     ++StubFile->Position;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reading a file.
 | |
|   //
 | |
|   Blob = &mKernelBlob[StubFile->BlobType];
 | |
|   if (StubFile->Position > Blob->Size) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Left = Blob->Size - StubFile->Position;
 | |
|   if (*BufferSize > Left) {
 | |
|     *BufferSize = (UINTN)Left;
 | |
|   }
 | |
| 
 | |
|   if (Blob->Data != NULL) {
 | |
|     CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
 | |
|   }
 | |
| 
 | |
|   StubFile->Position += *BufferSize;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes data to a file.
 | |
| 
 | |
|   @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
 | |
|                              is the file handle to write data to.
 | |
| 
 | |
|   @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
 | |
|                              amount of data actually written. In both cases,
 | |
|                              the size is measured in bytes.
 | |
| 
 | |
|   @param[in]     Buffer      The buffer of data to write.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Data was written.
 | |
|   @retval EFI_UNSUPPORTED       Writes to open directory files are not
 | |
|                                 supported.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_DEVICE_ERROR      An attempt was made to write to a deleted file.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
 | |
|   @retval EFI_ACCESS_DENIED     The file was opened read only.
 | |
|   @retval EFI_VOLUME_FULL       The volume is full.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileWrite (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   IN VOID               *Buffer
 | |
|   )
 | |
| {
 | |
|   STUB_FILE  *StubFile;
 | |
| 
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
|   return (StubFile->BlobType == KernelBlobTypeMax) ?
 | |
|          EFI_UNSUPPORTED :
 | |
|          EFI_WRITE_PROTECTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns a file's current position.
 | |
| 
 | |
|   @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is the
 | |
|                         file handle to get the current position on.
 | |
| 
 | |
|   @param[out] Position  The address to return the file's current position
 | |
|                         value.
 | |
| 
 | |
|   @retval EFI_SUCCESS      The position was returned.
 | |
|   @retval EFI_UNSUPPORTED  The request is not valid on open directories.
 | |
|   @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
 | |
|                            deleted file.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileGetPosition (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   OUT UINT64            *Position
 | |
|   )
 | |
| {
 | |
|   STUB_FILE  *StubFile;
 | |
| 
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
|   if (StubFile->BlobType == KernelBlobTypeMax) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   *Position = StubFile->Position;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Sets a file's current position.
 | |
| 
 | |
|   @param[in] This      A pointer to the EFI_FILE_PROTOCOL instance that is the
 | |
|                        file handle to set the requested position on.
 | |
| 
 | |
|   @param[in] Position  The byte position from the start of the file to set. For
 | |
|                        regular files, MAX_UINT64 means "seek to end". For
 | |
|                        directories, zero means "rewind directory scan".
 | |
| 
 | |
|   @retval EFI_SUCCESS       The position was set.
 | |
|   @retval EFI_UNSUPPORTED   The seek request for nonzero is not valid on open
 | |
|                             directories.
 | |
|   @retval EFI_DEVICE_ERROR  An attempt was made to set the position of a
 | |
|                             deleted file.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileSetPosition (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN UINT64             Position
 | |
|   )
 | |
| {
 | |
|   STUB_FILE    *StubFile;
 | |
|   KERNEL_BLOB  *Blob;
 | |
| 
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
| 
 | |
|   if (StubFile->BlobType == KernelBlobTypeMax) {
 | |
|     if (Position == 0) {
 | |
|       //
 | |
|       // rewinding a directory scan is allowed
 | |
|       //
 | |
|       StubFile->Position = 0;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // regular file seek
 | |
|   //
 | |
|   Blob = &mKernelBlob[StubFile->BlobType];
 | |
|   if (Position == MAX_UINT64) {
 | |
|     //
 | |
|     // seek to end
 | |
|     //
 | |
|     StubFile->Position = Blob->Size;
 | |
|   } else {
 | |
|     //
 | |
|     // absolute seek from beginning -- seeking past the end is allowed
 | |
|     //
 | |
|     StubFile->Position = Position;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns information about a file.
 | |
| 
 | |
|   @param[in]     This             A pointer to the EFI_FILE_PROTOCOL instance
 | |
|                                   that is the file handle the requested
 | |
|                                   information is for.
 | |
| 
 | |
|   @param[in]     InformationType  The type identifier GUID for the information
 | |
|                                   being requested. The following information
 | |
|                                   types are supported, storing the
 | |
|                                   corresponding structures in Buffer:
 | |
| 
 | |
|                                   - gEfiFileInfoGuid: EFI_FILE_INFO
 | |
| 
 | |
|                                   - gEfiFileSystemInfoGuid:
 | |
|                                     EFI_FILE_SYSTEM_INFO
 | |
| 
 | |
|                                   - gEfiFileSystemVolumeLabelInfoIdGuid:
 | |
|                                     EFI_FILE_SYSTEM_VOLUME_LABEL
 | |
| 
 | |
|   @param[in,out] BufferSize       On input, the size of Buffer. On output, the
 | |
|                                   amount of data returned in Buffer. In both
 | |
|                                   cases, the size is measured in bytes.
 | |
| 
 | |
|   @param[out]    Buffer           A pointer to the data buffer to return. The
 | |
|                                   buffer's type is indicated by
 | |
|                                   InformationType.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The information was returned.
 | |
|   @retval EFI_UNSUPPORTED       The InformationType is not known.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
 | |
|                                 information structure requested by
 | |
|                                 InformationType. BufferSize has been updated
 | |
|                                 with the size needed to complete the request.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileGetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN OUT UINTN          *BufferSize,
 | |
|   OUT VOID              *Buffer
 | |
|   )
 | |
| {
 | |
|   CONST STUB_FILE  *StubFile;
 | |
|   UINTN            OriginalBufferSize;
 | |
| 
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
| 
 | |
|   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
 | |
|     return ConvertKernelBlobTypeToFileInfo (
 | |
|              StubFile->BlobType,
 | |
|              BufferSize,
 | |
|              Buffer
 | |
|              );
 | |
|   }
 | |
| 
 | |
|   OriginalBufferSize = *BufferSize;
 | |
| 
 | |
|   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
 | |
|     EFI_FILE_SYSTEM_INFO  *FileSystemInfo;
 | |
| 
 | |
|     *BufferSize = sizeof *FileSystemInfo;
 | |
|     if (OriginalBufferSize < *BufferSize) {
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     FileSystemInfo                 = (EFI_FILE_SYSTEM_INFO *)Buffer;
 | |
|     FileSystemInfo->Size           = sizeof *FileSystemInfo;
 | |
|     FileSystemInfo->ReadOnly       = TRUE;
 | |
|     FileSystemInfo->VolumeSize     = mTotalBlobBytes;
 | |
|     FileSystemInfo->FreeSpace      = 0;
 | |
|     FileSystemInfo->BlockSize      = 1;
 | |
|     FileSystemInfo->VolumeLabel[0] = L'\0';
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
 | |
|     EFI_FILE_SYSTEM_VOLUME_LABEL  *FileSystemVolumeLabel;
 | |
| 
 | |
|     *BufferSize = sizeof *FileSystemVolumeLabel;
 | |
|     if (OriginalBufferSize < *BufferSize) {
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     FileSystemVolumeLabel                 = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
 | |
|     FileSystemVolumeLabel->VolumeLabel[0] = L'\0';
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Sets information about a file.
 | |
| 
 | |
|   @param[in] File             A pointer to the EFI_FILE_PROTOCOL instance that
 | |
|                               is the file handle the information is for.
 | |
| 
 | |
|   @param[in] InformationType  The type identifier for the information being
 | |
|                               set.
 | |
| 
 | |
|   @param[in] BufferSize       The size, in bytes, of Buffer.
 | |
| 
 | |
|   @param[in] Buffer           A pointer to the data buffer to write. The
 | |
|                               buffer's type is indicated by InformationType.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The information was set.
 | |
|   @retval EFI_UNSUPPORTED       The InformationType is not known.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED   InformationType is EFI_FILE_INFO_ID and the
 | |
|                                 media is read-only.
 | |
|   @retval EFI_WRITE_PROTECTED   InformationType is
 | |
|                                 EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
 | |
|                                 is read only.
 | |
|   @retval EFI_WRITE_PROTECTED   InformationType is
 | |
|                                 EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
 | |
|                                 is read-only.
 | |
|   @retval EFI_ACCESS_DENIED     An attempt is made to change the name of a file
 | |
|                                 to a file that is already present.
 | |
|   @retval EFI_ACCESS_DENIED     An attempt is being made to change the
 | |
|                                 EFI_FILE_DIRECTORY Attribute.
 | |
|   @retval EFI_ACCESS_DENIED     An attempt is being made to change the size of
 | |
|                                 a directory.
 | |
|   @retval EFI_ACCESS_DENIED     InformationType is EFI_FILE_INFO_ID and the
 | |
|                                 file was opened read-only and an attempt is
 | |
|                                 being made to modify a field other than
 | |
|                                 Attribute.
 | |
|   @retval EFI_VOLUME_FULL       The volume is full.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   BufferSize is smaller than the size of the type
 | |
|                                 indicated by InformationType.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileSetInfo (
 | |
|   IN EFI_FILE_PROTOCOL  *This,
 | |
|   IN EFI_GUID           *InformationType,
 | |
|   IN UINTN              BufferSize,
 | |
|   IN VOID               *Buffer
 | |
|   )
 | |
| {
 | |
|   return EFI_WRITE_PROTECTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flushes all modified data associated with a file to a device.
 | |
| 
 | |
|   @param [in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
 | |
|                     file handle to flush.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was flushed.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
 | |
|   @retval EFI_ACCESS_DENIED     The file was opened read-only.
 | |
|   @retval EFI_VOLUME_FULL       The volume is full.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileFlush (
 | |
|   IN EFI_FILE_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   return EFI_WRITE_PROTECTED;
 | |
| }
 | |
| 
 | |
| //
 | |
| // External definition of the file protocol template.
 | |
| //
 | |
| STATIC CONST EFI_FILE_PROTOCOL  mEfiFileProtocolTemplate = {
 | |
|   EFI_FILE_PROTOCOL_REVISION, // revision 1
 | |
|   StubFileOpen,
 | |
|   StubFileClose,
 | |
|   StubFileDelete,
 | |
|   StubFileRead,
 | |
|   StubFileWrite,
 | |
|   StubFileGetPosition,
 | |
|   StubFileSetPosition,
 | |
|   StubFileGetInfo,
 | |
|   StubFileSetInfo,
 | |
|   StubFileFlush,
 | |
|   NULL,                       // OpenEx, revision 2
 | |
|   NULL,                       // ReadEx, revision 2
 | |
|   NULL,                       // WriteEx, revision 2
 | |
|   NULL                        // FlushEx, revision 2
 | |
| };
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileOpen (
 | |
|   IN EFI_FILE_PROTOCOL   *This,
 | |
|   OUT EFI_FILE_PROTOCOL  **NewHandle,
 | |
|   IN CHAR16              *FileName,
 | |
|   IN UINT64              OpenMode,
 | |
|   IN UINT64              Attributes
 | |
|   )
 | |
| {
 | |
|   CONST STUB_FILE  *StubFile;
 | |
|   UINTN            BlobType;
 | |
|   STUB_FILE        *NewStubFile;
 | |
| 
 | |
|   //
 | |
|   // We're read-only.
 | |
|   //
 | |
|   switch (OpenMode) {
 | |
|     case EFI_FILE_MODE_READ:
 | |
|       break;
 | |
| 
 | |
|     case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
 | |
|     case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
 | |
|       return EFI_WRITE_PROTECTED;
 | |
| 
 | |
|     default:
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Only the root directory supports opening files in it.
 | |
|   //
 | |
|   StubFile = STUB_FILE_FROM_FILE (This);
 | |
|   if (StubFile->BlobType != KernelBlobTypeMax) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Locate the file.
 | |
|   //
 | |
|   for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
 | |
|     if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (BlobType == KernelBlobTypeMax) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Found it.
 | |
|   //
 | |
|   NewStubFile = AllocatePool (sizeof *NewStubFile);
 | |
|   if (NewStubFile == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   NewStubFile->Signature = STUB_FILE_SIG;
 | |
|   NewStubFile->BlobType  = (KERNEL_BLOB_TYPE)BlobType;
 | |
|   NewStubFile->Position  = 0;
 | |
|   CopyMem (
 | |
|     &NewStubFile->File,
 | |
|     &mEfiFileProtocolTemplate,
 | |
|     sizeof mEfiFileProtocolTemplate
 | |
|     );
 | |
|   *NewHandle = &NewStubFile->File;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // Protocol member functions for SimpleFileSystem.
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Open the root directory on a volume.
 | |
| 
 | |
|   @param[in]  This  A pointer to the volume to open the root directory on.
 | |
| 
 | |
|   @param[out] Root  A pointer to the location to return the opened file handle
 | |
|                     for the root directory in.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The device was opened.
 | |
|   @retval EFI_UNSUPPORTED       This volume does not support the requested file
 | |
|                                 system type.
 | |
|   @retval EFI_NO_MEDIA          The device has no medium.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error.
 | |
|   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | |
|   @retval EFI_ACCESS_DENIED     The service denied access to the file.
 | |
|   @retval EFI_OUT_OF_RESOURCES  The volume was not opened due to lack of
 | |
|                                 resources.
 | |
|   @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
 | |
|                                 medium is no longer supported. Any existing
 | |
|                                 file handles for this volume are no longer
 | |
|                                 valid. To access the files on the new medium,
 | |
|                                 the volume must be reopened with OpenVolume().
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| StubFileSystemOpenVolume (
 | |
|   IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
 | |
|   OUT EFI_FILE_PROTOCOL               **Root
 | |
|   )
 | |
| {
 | |
|   STUB_FILE  *StubFile;
 | |
| 
 | |
|   StubFile = AllocatePool (sizeof *StubFile);
 | |
|   if (StubFile == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   StubFile->Signature = STUB_FILE_SIG;
 | |
|   StubFile->BlobType  = KernelBlobTypeMax;
 | |
|   StubFile->Position  = 0;
 | |
|   CopyMem (
 | |
|     &StubFile->File,
 | |
|     &mEfiFileProtocolTemplate,
 | |
|     sizeof mEfiFileProtocolTemplate
 | |
|     );
 | |
|   *Root = &StubFile->File;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  mFileSystem = {
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
 | |
|   StubFileSystemOpenVolume
 | |
| };
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitrdLoadFile2 (
 | |
|   IN      EFI_LOAD_FILE2_PROTOCOL   *This,
 | |
|   IN      EFI_DEVICE_PATH_PROTOCOL  *FilePath,
 | |
|   IN      BOOLEAN                   BootPolicy,
 | |
|   IN  OUT UINTN                     *BufferSize,
 | |
|   OUT     VOID                      *Buffer     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   CONST KERNEL_BLOB  *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
 | |
| 
 | |
|   ASSERT (InitrdBlob->Size > 0);
 | |
| 
 | |
|   if (BootPolicy) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if ((BufferSize == NULL) || !IsDevicePathValid (FilePath, 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((FilePath->Type != END_DEVICE_PATH_TYPE) ||
 | |
|       (FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE))
 | |
|   {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if ((Buffer == NULL) || (*BufferSize < InitrdBlob->Size)) {
 | |
|     *BufferSize = InitrdBlob->Size;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   CopyMem (Buffer, InitrdBlob->Data, InitrdBlob->Size);
 | |
| 
 | |
|   *BufferSize = InitrdBlob->Size;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC CONST EFI_LOAD_FILE2_PROTOCOL  mInitrdLoadFile2 = {
 | |
|   InitrdLoadFile2,
 | |
| };
 | |
| 
 | |
| //
 | |
| // Utility functions.
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Populate a blob in mKernelBlob.
 | |
| 
 | |
|   param[in,out] Blob  Pointer to the KERNEL_BLOB element in mKernelBlob that is
 | |
|                       to be filled from fw_cfg.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Blob has been populated. If fw_cfg reported a
 | |
|                                 size of zero for the blob, then Blob->Data has
 | |
|                                 been left unchanged.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Blob->Data.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| FetchBlob (
 | |
|   IN OUT KERNEL_BLOB  *Blob
 | |
|   )
 | |
| {
 | |
|   UINT32  Left;
 | |
|   UINTN   Idx;
 | |
|   UINT8   *ChunkData;
 | |
| 
 | |
|   //
 | |
|   // Read blob size.
 | |
|   //
 | |
|   Blob->Size = 0;
 | |
|   for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
 | |
|     if (Blob->FwCfgItem[Idx].SizeKey == 0) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey);
 | |
|     Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
 | |
|     Blob->Size               += Blob->FwCfgItem[Idx].Size;
 | |
|   }
 | |
| 
 | |
|   if (Blob->Size == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Read blob.
 | |
|   //
 | |
|   Blob->Data = AllocatePool (Blob->Size);
 | |
|   if (Blob->Data == NULL) {
 | |
|     DEBUG ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: failed to allocate %Ld bytes for \"%s\"\n",
 | |
|       __func__,
 | |
|       (INT64)Blob->Size,
 | |
|       Blob->Name
 | |
|       ));
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "%a: loading %Ld bytes for \"%s\"\n",
 | |
|     __func__,
 | |
|     (INT64)Blob->Size,
 | |
|     Blob->Name
 | |
|     ));
 | |
| 
 | |
|   ChunkData = Blob->Data;
 | |
|   for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
 | |
|     if (Blob->FwCfgItem[Idx].DataKey == 0) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey);
 | |
| 
 | |
|     Left = Blob->FwCfgItem[Idx].Size;
 | |
|     while (Left > 0) {
 | |
|       UINT32  Chunk;
 | |
| 
 | |
|       Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
 | |
|       QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left);
 | |
|       Left -= Chunk;
 | |
|       DEBUG ((
 | |
|         DEBUG_VERBOSE,
 | |
|         "%a: %Ld bytes remaining for \"%s\" (%d)\n",
 | |
|         __func__,
 | |
|         (INT64)Left,
 | |
|         Blob->Name,
 | |
|         (INT32)Idx
 | |
|         ));
 | |
|     }
 | |
| 
 | |
|     ChunkData += Blob->FwCfgItem[Idx].Size;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // The entry point of the feature.
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Download the kernel, the initial ramdisk, and the kernel command line from
 | |
|   QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
 | |
|   image files.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND         Kernel image was not found.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
 | |
|   @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
 | |
| 
 | |
|   @return                       Error codes from any of the underlying
 | |
|                                 functions. On success, the function doesn't
 | |
|                                 return.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuKernelLoaderFsDxeEntrypoint (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   UINTN        BlobType;
 | |
|   KERNEL_BLOB  *CurrentBlob;
 | |
|   KERNEL_BLOB  *KernelBlob;
 | |
|   EFI_STATUS   Status;
 | |
|   EFI_HANDLE   FileSystemHandle;
 | |
|   EFI_HANDLE   InitrdLoadFile2Handle;
 | |
| 
 | |
|   if (!QemuFwCfgIsAvailable ()) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "%a: GetTime(): %r\n", __func__, Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fetch all blobs.
 | |
|   //
 | |
|   for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
 | |
|     CurrentBlob = &mKernelBlob[BlobType];
 | |
|     Status      = FetchBlob (CurrentBlob);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto FreeBlobs;
 | |
|     }
 | |
| 
 | |
|     Status = VerifyBlob (
 | |
|                CurrentBlob->Name,
 | |
|                CurrentBlob->Data,
 | |
|                CurrentBlob->Size
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto FreeBlobs;
 | |
|     }
 | |
| 
 | |
|     mTotalBlobBytes += CurrentBlob->Size;
 | |
|   }
 | |
| 
 | |
|   KernelBlob = &mKernelBlob[KernelBlobTypeKernel];
 | |
| 
 | |
|   if (KernelBlob->Data == NULL) {
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     goto FreeBlobs;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create a new handle with a single VenMedia() node device path protocol on
 | |
|   // it, plus a custom SimpleFileSystem protocol on it.
 | |
|   //
 | |
|   FileSystemHandle = NULL;
 | |
|   Status           = gBS->InstallMultipleProtocolInterfaces (
 | |
|                             &FileSystemHandle,
 | |
|                             &gEfiDevicePathProtocolGuid,
 | |
|                             &mFileSystemDevicePath,
 | |
|                             &gEfiSimpleFileSystemProtocolGuid,
 | |
|                             &mFileSystem,
 | |
|                             NULL
 | |
|                             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: InstallMultipleProtocolInterfaces(): %r\n",
 | |
|       __func__,
 | |
|       Status
 | |
|       ));
 | |
|     goto FreeBlobs;
 | |
|   }
 | |
| 
 | |
|   if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
 | |
|     InitrdLoadFile2Handle = NULL;
 | |
|     Status                = gBS->InstallMultipleProtocolInterfaces (
 | |
|                                    &InitrdLoadFile2Handle,
 | |
|                                    &gEfiDevicePathProtocolGuid,
 | |
|                                    &mInitrdDevicePath,
 | |
|                                    &gEfiLoadFile2ProtocolGuid,
 | |
|                                    &mInitrdLoadFile2,
 | |
|                                    NULL
 | |
|                                    );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((
 | |
|         DEBUG_ERROR,
 | |
|         "%a: InstallMultipleProtocolInterfaces(): %r\n",
 | |
|         __func__,
 | |
|         Status
 | |
|         ));
 | |
|       goto UninstallFileSystemHandle;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| UninstallFileSystemHandle:
 | |
|   Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                   FileSystemHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   &mFileSystemDevicePath,
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   &mFileSystem,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
| FreeBlobs:
 | |
|   while (BlobType > 0) {
 | |
|     CurrentBlob = &mKernelBlob[--BlobType];
 | |
|     if (CurrentBlob->Data != NULL) {
 | |
|       FreePool (CurrentBlob->Data);
 | |
|       CurrentBlob->Size = 0;
 | |
|       CurrentBlob->Data = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |