diff --git a/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c new file mode 100644 index 0000000000..6ef9facc93 --- /dev/null +++ b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c @@ -0,0 +1,421 @@ +/** @file + Produce Load File Protocol for UEFI Applications in Firmware Volumes + + Copyright (c) 2011 - 2013, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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) + +EFI_EVENT 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 EFI_GUID File GUID. + + @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 occured + @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); + Status = gBS->LocateHandle ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &BufferSize, + Handle + ); + if (EFI_BUFFER_TOO_SMALL == Status) { + FreePool (Handle); + Handle = AllocateZeroPool (BufferSize); + 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; +} + diff --git a/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf new file mode 100644 index 0000000000..a4ded94e7f --- /dev/null +++ b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf @@ -0,0 +1,68 @@ +## @file +# Load File Module +# +# Allows the system to load a file from a FV2 based firmware volume. This +# version of the module only supports loading of files for the purpose of +# booting from the file. +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010018 + BASE_NAME = LoadFileOnFv2 + FILE_GUID = BD712601-082F-4c59-8677-2C8A3C297948 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = LoadFileOnFv2Intialize + MODULE_UNI_FILE = LoadFileOnFv2.uni + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + LoadFileOnFv2.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DebugLib + UefiLib + BaseMemoryLib + UefiDriverEntryPoint + UefiBootServicesTableLib + MemoryAllocationLib + DevicePathLib + +[Guids] + ## SOMETIMES_CONSUMES ## UNDEFINED # Notify gLzmaCustomDecompressGuid SectionExtraction. + gLzmaCustomDecompressGuid + +[Protocols] + ## NOTIFY + ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadFileProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES + +[Depex] + TRUE + +[UserExtensions.TianoCore."ExtraFiles"] + LoadFileOnFv2Extra.uni + diff --git a/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni new file mode 100644 index 0000000000..19e42a2830 --- /dev/null +++ b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni @@ -0,0 +1,24 @@ +// /** @file +// LoadFileOnFv2 Localized Abstract and Description Content +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_MODULE_ABSTRACT +#language en-US +"Allows system to load files from an FV2-based firmware volume" + +#string STR_MODULE_DESCRIPTION +#language en-US +"This module allows the system to load a file from an FV2-based firmware " +"volume. This version of the module only supports loading of files for the " +"purpose of booting from a file." diff --git a/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni new file mode 100644 index 0000000000..aa5eb98400 --- /dev/null +++ b/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni @@ -0,0 +1,18 @@ +// /** @file +// LoadFileOnFv2 Localized Strings and Content +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Firmware Volume Load File Module"