123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155 |
- /** @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",
- __FUNCTION__,
- (INT64)Blob->Size,
- Blob->Name
- ));
- return EFI_OUT_OF_RESOURCES;
- }
- DEBUG ((
- DEBUG_INFO,
- "%a: loading %Ld bytes for \"%s\"\n",
- __FUNCTION__,
- (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",
- __FUNCTION__,
- (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", __FUNCTION__, 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",
- __FUNCTION__,
- 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",
- __FUNCTION__,
- 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;
- }
|