summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
new file mode 100644
index 00000000..345bf066
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
@@ -0,0 +1,421 @@
+/** @file
+ Produce Load File Protocol for UEFI Applications in Firmware Volumes
+
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/LzmaDecompress.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('l', 'f', 'f', 'v')
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOAD_FILE_PROTOCOL LoadFile;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_GUID NameGuid;
+ LIST_ENTRY Link;
+} LOAD_FILE_ON_FV2_PRIVATE_DATA;
+
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, LoadFile, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, Link, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
+
+VOID *mFvRegistration;
+LIST_ENTRY mPrivateDataList;
+
+/**
+ Causes the driver to load a specified file from firmware volume.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] FilePath The device specific path of the file to load.
+ @param[in] BootPolicy If TRUE, indicates that the request originates from the
+ boot manager is attempting to load FilePath as a boot
+ selection. If FALSE, then FilePath must match an exact file
+ to be loaded.
+ @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to
+ Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
+ then no the size of the requested file is returned in
+ BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_OUT_OF_RESOURCES An allocation failure occurred.
+ @retval EFI_ACCESS_DENIED The firmware volume is configured to
+ disallow reads.
+**/
+EFI_STATUS
+EFIAPI
+LoadFileOnFv2LoadFile (
+ IN EFI_LOAD_FILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;
+ VOID *Pe32Buffer;
+ UINTN Pe32BufferSize;
+ UINT32 AuthenticationStatus;
+
+ if (This == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only support BootPolicy
+ //
+ if (!BootPolicy) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get private context data
+ //
+ Private = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Determine the size of the PE32 section
+ //
+ Pe32Buffer = NULL;
+ Pe32BufferSize = 0;
+ Status = Private->Fv->ReadSection (
+ Private->Fv,
+ &Private->NameGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Pe32Buffer,
+ &Pe32BufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If the buffer passed in is not large enough, return the size of the required
+ // buffer in BufferSize and return EFI_BUFFER_TOO_SMALL
+ //
+ if (*BufferSize < Pe32BufferSize || Buffer == NULL) {
+ *BufferSize = Pe32BufferSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // The buffer passed in is large enough, so read the PE32 section directly into
+ // the buffer, update BufferSize with the actual size read, and return the status
+ // from ReadSection()
+ //
+ return Private->Fv->ReadSection (
+ Private->Fv,
+ &Private->NameGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Buffer,
+ BufferSize,
+ &AuthenticationStatus
+ );
+}
+
+LOAD_FILE_ON_FV2_PRIVATE_DATA mLoadFileOnFv2PrivateDataTemplate = {
+ LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE,
+ {
+ LoadFileOnFv2LoadFile
+ }
+};
+
+/**
+ Check if the FFS has been installed LoadFileProtocol for it.
+
+ @param[in] NameGuid Point to FFS File GUID to be checked.
+
+ @retval TRUE The FFS's FileLoadProtocol is in list.
+ @retval FALSE The FFS's FileLoadProtocol is not in list.
+
+**/
+BOOLEAN
+EFIAPI
+IsInPrivateList (
+ IN EFI_GUID *NameGuid
+)
+{
+ LIST_ENTRY *Entry;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *PrivateData;
+
+ if (IsListEmpty (&mPrivateDataList)) {
+ return FALSE;
+ }
+
+ for(Entry = (&mPrivateDataList)->ForwardLink; Entry != (&mPrivateDataList); Entry = Entry->ForwardLink) {
+ PrivateData = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK (Entry);
+ if (CompareGuid (NameGuid, &PrivateData->NameGuid)) {
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:FileLoadProtocol has been installed in:%g\n", NameGuid));
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Create file device path based on FFS file GUID and UI name.
+
+ @param Device Handle to Firmware Volume.
+ @param NameGuid Point to FFS file GUID.
+ @param FileName Point to FFS UI section name.
+
+ @return the combined device path
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+CreateFileDevicePath (
+ IN EFI_HANDLE Device,
+ IN EFI_GUID *NameGuid,
+ IN CONST CHAR16 *FileName
+ )
+{
+ UINTN Size;
+ FILEPATH_DEVICE_PATH *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, NameGuid);
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (Device),
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+
+ Size = StrSize (FileName);
+ FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
+ if (FileDevicePath != NULL) {
+ FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;
+ FilePath->Header.Type = MEDIA_DEVICE_PATH;
+ FilePath->Header.SubType = MEDIA_FILEPATH_DP;
+ CopyMem (&FilePath->PathName, FileName, Size);
+ SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
+ SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
+
+ DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
+ FreePool (FileDevicePath);
+ }
+
+ return DevicePath;
+}
+
+/**
+ Install LoadFile Protocol for Application FFS.
+
+ @param Handle FV Handle.
+
+**/
+VOID
+EFIAPI
+InstallFileLoadProtocol (
+ EFI_HANDLE Handle
+)
+{
+ EFI_STATUS Status;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_FV_FILETYPE FileType;
+ UINTN Key;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_HANDLE LoadFileHandle;
+ UINT32 AuthenticationStatus;
+ CHAR16 *UiName;
+ UINTN UiNameSize;
+
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Find a FV!\n"));
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ Fvb->GetPhysicalAddress (Fvb, &Address);
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Fvb->Address=%x \n", Address));
+
+ //
+ // Use Firmware Volume 2 Protocol to search for a FFS files of type
+ // EFI_FV_FILETYPE_APPLICATION and produce a LoadFile protocol for
+ // each one found.
+ //
+ FileType = EFI_FV_FILETYPE_APPLICATION;
+ Key = 0;
+ while (TRUE) {
+ Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, &Size);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ UiName = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&UiName,
+ &UiNameSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (!IsInPrivateList (&NameGuid)) {
+ Private = (LOAD_FILE_ON_FV2_PRIVATE_DATA *)AllocateCopyPool (sizeof (mLoadFileOnFv2PrivateDataTemplate), &mLoadFileOnFv2PrivateDataTemplate);
+ ASSERT (Private != NULL);
+ Private->Fv = Fv;
+ Private->DevicePath = CreateFileDevicePath (Handle, &NameGuid, UiName);
+ CopyGuid (&Private->NameGuid, &NameGuid);
+ LoadFileHandle = NULL;
+ DEBUG ((DEBUG_INFO, "Find a APPLICATION in this FV!\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &LoadFileHandle,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ &gEfiLoadFileProtocolGuid, &Private->LoadFile,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ InsertTailList (&mPrivateDataList, &Private->Link);
+ } else {
+ DEBUG ((DEBUG_ERROR, "Application with the same name %s has been installed.!\n", UiName));
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+ }
+ }
+ }
+}
+
+/**
+ This notification function is invoked when an instance of the
+ LzmaCustomDecompressGuid is produced. It installs another instance of the
+ EFI_FIRMWARE_VOLUME_PROTOCOL on the handle of the FFS. This notification function
+ also handles the situation when LZMA decoder driver loaded later than FirmwareVolume driver.
+
+ @param Event The event that occurred
+ @param Context Context of event. Not used in this nofication function.
+
+**/
+VOID
+EFIAPI
+FvNotificationEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE *Handle;
+ UINTN Index;
+ EFI_HANDLE *CurHandle;
+
+
+ Handle = NULL;
+ Index = 0;
+ BufferSize = sizeof (EFI_HANDLE);
+ Handle = AllocateZeroPool (BufferSize);
+ if (Handle == NULL) {
+ return;
+ }
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &BufferSize,
+ Handle
+ );
+ if (EFI_BUFFER_TOO_SMALL == Status) {
+ FreePool (Handle);
+ Handle = AllocateZeroPool (BufferSize);
+ if (Handle == NULL) {
+ return;
+ }
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &BufferSize,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ } else if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ CurHandle = Handle;
+ for (Index=0; Index < BufferSize/sizeof (EFI_HANDLE); Index++) {
+ CurHandle = Handle + Index;
+ //
+ // Install LoadFile Protocol
+ //
+ InstallFileLoadProtocol (*CurHandle);
+ }
+ if (Handle != NULL) {
+ FreePool (Handle);
+ }
+}
+
+/**
+ Entry point function initializes global variables and installs notifications.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+LoadFileOnFv2Intialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ InitializeListHead (&mPrivateDataList);
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ TPL_CALLBACK,
+ FvNotificationEvent,
+ NULL,
+ &mFvRegistration
+ );
+
+ EfiCreateProtocolNotifyEvent (
+ &gLzmaCustomDecompressGuid,
+ TPL_CALLBACK,
+ FvNotificationEvent,
+ NULL,
+ &mFvRegistration
+ );
+
+ return EFI_SUCCESS;
+}
+