diff options
Diffstat (limited to 'MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c')
| -rw-r--r-- | MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c | 1360 |
1 files changed, 680 insertions, 680 deletions
diff --git a/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c b/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c index 3f96407dc7..7479cc25ab 100644 --- a/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c +++ b/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c @@ -1,680 +1,680 @@ -/** @file
- This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
- volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
-
- It will expose a single directory, containing one file for each file in the firmware
- volume. If a file has a UI section, its contents will be used as a filename.
- Otherwise, a string representation of the GUID will be used.
- Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
- will have ".efi" added to their filename.
-
- Its primary intended use is to be able to start EFI applications embedded in FVs
- from the UEFI shell. It is entirely read-only.
-
-Copyright (c) 2014, ARM Limited. All rights reserved.
-Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FvSimpleFileSystemInternal.h"
-
-EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
-
-//
-// A Guid string is 32 hex characters with 4 hyphens and a NULL-terminated char: 37 characters total
-//
-#define GUID_STRING_SIZE (37 * sizeof (CHAR16))
-
-#define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: "
-#define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE - sizeof (CHAR16))
-#define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume"
-
-//
-// Template for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL data structure.
-//
-EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate = {
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
- FvSimpleFileSystemOpenVolume
-};
-
-//
-// Template for EFI_DRIVER_BINDING_PROTOCOL data structure.
-//
-EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
- FvSimpleFileSystemDriverSupported,
- FvSimpleFileSystemDriverStart,
- FvSimpleFileSystemDriverStop,
- 0,
- NULL,
- NULL
-};
-
-/**
- Open the root directory on a volume.
-
- @param This A pointer to the volume to open the root directory.
- @param RootFile A pointer to the location to return the opened file handle for the
- root directory.
-
- @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().
-
-**/
-EFI_STATUS
-EFIAPI
-FvSimpleFileSystemOpenVolume (
- IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
- OUT EFI_FILE_PROTOCOL **RootFile
- )
-{
- EFI_STATUS Status;
- FV_FILESYSTEM_FILE *Root;
- CHAR16 *UiSection;
- EFI_GUID NameGuid;
- EFI_FV_FILE_ATTRIBUTES Attributes;
- UINT32 Authentication;
- UINTN Key;
- EFI_FV_FILETYPE FileType;
- UINTN Size;
- FV_FILESYSTEM_INSTANCE *Instance;
- FV_FILESYSTEM_FILE_INFO *FvFileInfo;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
- CHAR16 *Name;
- UINTN NameLen;
- UINTN NumChars;
- UINTN DestMax;
-
- Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This);
- Status = EFI_SUCCESS;
-
- if (Instance->Root == NULL) {
- //
- // Allocate file structure for root file
- //
- Root = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
- if (Root == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Instance->Root = Root;
- Root->Instance = Instance;
- Root->Signature = FVFS_FILE_SIGNATURE;
- CopyMem (&Root->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
- Root->FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO));
- if (Root->FvFileInfo == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Root->FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO);
- Root->FvFileInfo->FileInfo.Attribute = EFI_FILE_DIRECTORY | EFI_FILE_READ_ONLY;
-
- //
- // Populate the instance's list of files. We consider anything a file that
- // has a UI_SECTION, which we consider to be its filename.
- //
- FvProtocol = Instance->FvProtocol;
- //
- // Allocate Key
- //
- Key = 0;
-
- do {
- FileType = EFI_FV_FILETYPE_ALL;
-
- Status = FvProtocol->GetNextFile (
- FvProtocol,
- &Key,
- &FileType,
- &NameGuid,
- &Attributes,
- &Size
- );
- if (EFI_ERROR (Status)) {
- ASSERT (Status == EFI_NOT_FOUND);
- break;
- }
-
- //
- // Get a file's name: If it has a UI section, use that, otherwise use
- // its NameGuid.
- //
- UiSection = NULL;
- Status = FvProtocol->ReadSection (
- FvProtocol,
- &NameGuid,
- EFI_SECTION_USER_INTERFACE,
- 0,
- (VOID **)&UiSection,
- &Size,
- &Authentication
- );
- if (!EFI_ERROR (Status)) {
- Name = UiSection;
- } else {
- Name = AllocateZeroPool (GUID_STRING_SIZE);
- if (Name == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid);
- ASSERT ((NumChars + 1) * sizeof (CHAR16) == GUID_STRING_SIZE);
- }
-
- //
- // Found a file.
- // Allocate a file structure and populate it.
- //
- NameLen = StrSize (Name);
- if (FV_FILETYPE_IS_EXECUTABLE (FileType)) {
- NameLen += StrSize (L".efi") - sizeof (CHAR16);
- }
-
- FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO) + NameLen - sizeof (CHAR16));
- if (FvFileInfo == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- FvFileInfo->Signature = FVFS_FILE_INFO_SIGNATURE;
- InitializeListHead (&FvFileInfo->Link);
- CopyMem (&FvFileInfo->NameGuid, &NameGuid, sizeof (EFI_GUID));
- FvFileInfo->Type = FileType;
-
- //
- // Add ".efi" to filenames of drivers and applications.
- //
- DestMax = NameLen / sizeof (CHAR16);
- Status = StrnCpyS (&FvFileInfo->FileInfo.FileName[0], DestMax, Name, StrLen (Name));
- ASSERT_EFI_ERROR (Status);
-
- if (FV_FILETYPE_IS_EXECUTABLE (FileType)) {
- Status = StrnCatS (&FvFileInfo->FileInfo.FileName[0], DestMax, L".efi", StrLen (L".efi"));
- ASSERT_EFI_ERROR (Status);
- }
-
- FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO) + NameLen - sizeof (CHAR16);
- Status = FvFsGetFileSize (FvProtocol, FvFileInfo);
- ASSERT_EFI_ERROR (Status);
- FvFileInfo->FileInfo.PhysicalSize = FvFileInfo->FileInfo.FileSize;
- FvFileInfo->FileInfo.Attribute = EFI_FILE_READ_ONLY;
-
- InsertHeadList (&Instance->FileInfoHead, &FvFileInfo->Link);
-
- FreePool (Name);
- } while (TRUE);
-
- if (Status == EFI_NOT_FOUND) {
- Status = EFI_SUCCESS;
- }
- }
-
- Instance->Root->DirReadNext = NULL;
- if (!IsListEmpty (&Instance->FileInfoHead)) {
- Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
- }
-
- *RootFile = &Instance->Root->FileProtocol;
- return Status;
-}
-
-/**
- Worker function to initialize Unicode Collation support.
-
- It tries to locate Unicode Collation (2) protocol and matches it with current
- platform language code.
-
- @param AgentHandle The handle used to open Unicode Collation (2) protocol.
- @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.
- @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
- @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.
-
- @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
- @retval Others The Unicode Collation (2) protocol has not been located.
-
-**/
-EFI_STATUS
-InitializeUnicodeCollationSupportWorker (
- IN EFI_HANDLE AgentHandle,
- IN EFI_GUID *ProtocolGuid,
- IN CONST CHAR16 *VariableName,
- IN CONST CHAR8 *DefaultLanguage
- )
-{
- EFI_STATUS ReturnStatus;
- EFI_STATUS Status;
- UINTN NumHandles;
- UINTN Index;
- EFI_HANDLE *Handles;
- EFI_UNICODE_COLLATION_PROTOCOL *Uci;
- BOOLEAN Iso639Language;
- CHAR8 *Language;
- CHAR8 *BestLanguage;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- ProtocolGuid,
- NULL,
- &NumHandles,
- &Handles
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Iso639Language = (BOOLEAN)(ProtocolGuid == &gEfiUnicodeCollationProtocolGuid);
- GetEfiGlobalVariable2 (VariableName, (VOID **)&Language, NULL);
-
- ReturnStatus = EFI_UNSUPPORTED;
- for (Index = 0; Index < NumHandles; Index++) {
- //
- // Open Unicode Collation Protocol
- //
- Status = gBS->OpenProtocol (
- Handles[Index],
- ProtocolGuid,
- (VOID **)&Uci,
- AgentHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- //
- // Find the best matching matching language from the supported languages
- // of Unicode Collation (2) protocol.
- //
- BestLanguage = GetBestLanguage (
- Uci->SupportedLanguages,
- Iso639Language,
- (Language == NULL) ? "" : Language,
- DefaultLanguage,
- NULL
- );
- if (BestLanguage != NULL) {
- FreePool (BestLanguage);
- mUnicodeCollation = Uci;
- ReturnStatus = EFI_SUCCESS;
- break;
- }
- }
-
- if (Language != NULL) {
- FreePool (Language);
- }
-
- FreePool (Handles);
-
- return ReturnStatus;
-}
-
-/**
- Initialize Unicode Collation support.
-
- It tries to locate Unicode Collation 2 protocol and matches it with current
- platform language code. If for any reason the first attempt fails, it then tries to
- use Unicode Collation Protocol.
-
- @param AgentHandle The handle used to open Unicode Collation (2) protocol.
-
- @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
- @retval Others The Unicode Collation (2) protocol has not been located.
-
-**/
-EFI_STATUS
-InitializeUnicodeCollationSupport (
- IN EFI_HANDLE AgentHandle
- )
-{
- EFI_STATUS Status;
-
- Status = EFI_UNSUPPORTED;
-
- //
- // First try to use RFC 4646 Unicode Collation 2 Protocol.
- //
- Status = InitializeUnicodeCollationSupportWorker (
- AgentHandle,
- &gEfiUnicodeCollation2ProtocolGuid,
- L"PlatformLang",
- (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang)
- );
- //
- // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back
- // on the ISO 639-2 Unicode Collation Protocol.
- //
- if (EFI_ERROR (Status)) {
- Status = InitializeUnicodeCollationSupportWorker (
- AgentHandle,
- &gEfiUnicodeCollationProtocolGuid,
- L"Lang",
- (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang)
- );
- }
-
- return Status;
-}
-
-/**
- Test to see if this driver supports ControllerHandle.
-
- @param DriverBinding Protocol instance pointer.
- @param ControllerHandle Handle of device to test
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver supports this device
- @retval EFI_ALREADY_STARTED This driver is already running on this device
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-FvSimpleFileSystemDriverSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
-{
- return gBS->OpenProtocol (
- ControllerHandle,
- &gEfiFirmwareVolume2ProtocolGuid,
- NULL,
- gImageHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
-}
-
-/**
- Start this driver on ControllerHandle by opening a FV protocol and
- installing a SimpleFileSystem protocol on ControllerHandle.
-
- @param DriverBinding Protocol instance pointer.
- @param ControllerHandle Handle of device to bind driver to
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
-
- @retval EFI_SUCCESS This driver is added to ControllerHandle
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
- @retval other This driver does not support this device
-
-**/
-EFI_STATUS
-EFIAPI
-FvSimpleFileSystemDriverStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
- FV_FILESYSTEM_INSTANCE *Instance;
- EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
- EFI_GUID *FvGuid;
- UINTN NumChars;
-
- Status = InitializeUnicodeCollationSupport (DriverBinding->DriverBindingHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Open FV protocol
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiFirmwareVolume2ProtocolGuid,
- (VOID **)&FvProtocol,
- gImageHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Create an instance
- //
- Instance = AllocateZeroPool (sizeof (FV_FILESYSTEM_INSTANCE));
- ASSERT (Instance != NULL);
-
- Instance->Root = NULL;
- Instance->FvProtocol = FvProtocol;
- Instance->Signature = FVFS_INSTANCE_SIGNATURE;
- InitializeListHead (&Instance->FileInfoHead);
- InitializeListHead (&Instance->FileHead);
- CopyMem (&Instance->SimpleFs, &mSimpleFsTemplate, sizeof (mSimpleFsTemplate));
-
- Status = gBS->InstallProtocolInterface (
- &ControllerHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Instance->SimpleFs
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Decide on a filesystem volume label, which will include the FV's guid.
- // Get the device path to find the FV's GUID
- //
- Instance->VolumeLabel = NULL;
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&FvDevicePath,
- gImageHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- //
- // Iterate over device path until we find a firmware volume node
- //
- while (!IsDevicePathEndType (FvDevicePath)) {
- if ((DevicePathType (FvDevicePath) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (FvDevicePath) == MEDIA_PIWG_FW_VOL_DP))
- {
- //
- // Allocate the volume label
- //
- Instance->VolumeLabel = AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE);
- //
- // Check the allocation was successful
- //
- if (Instance->VolumeLabel != NULL) {
- //
- // Extract the FV's guid
- //
- FvGuid = &((MEDIA_FW_VOL_DEVICE_PATH *)FvDevicePath)->FvName;
- //
- // Build the volume label string
- //
- NumChars = UnicodeSPrint (
- Instance->VolumeLabel,
- FVFS_VOLUME_LABEL_SIZE,
- FVFS_VOLUME_LABEL_PREFIX L"%g",
- FvGuid
- );
- ASSERT ((NumChars + 1) * sizeof (CHAR16) == FVFS_VOLUME_LABEL_SIZE);
- }
-
- break;
- }
-
- FvDevicePath = NextDevicePathNode (FvDevicePath);
- }
- }
-
- //
- // If we didn't decide on a volume label, set a fallback one
- //
- if (Instance->VolumeLabel == NULL) {
- Instance->VolumeLabel = AllocateCopyPool (
- sizeof (FVFS_FALLBACK_VOLUME_LABEL),
- FVFS_FALLBACK_VOLUME_LABEL
- );
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing
- the FV protocol on ControllerHandle.
-
- @param DriverBinding Protocol instance pointer.
- @param ControllerHandle Handle of device to stop driver on
- @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
- children is zero stop the entire bus driver.
- @param ChildHandleBuffer List of Child Handles to Stop.
-
- @retval EFI_SUCCESS This driver is removed ControllerHandle
- @retval other This driver was not removed from this device
-
-**/
-EFI_STATUS
-EFIAPI
-FvSimpleFileSystemDriverStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
- )
-{
- EFI_STATUS Status;
- FV_FILESYSTEM_INSTANCE *Instance;
- FV_FILESYSTEM_FILE_INFO *FvFileInfo;
- LIST_ENTRY *Entry;
- LIST_ENTRY *DelEntry;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFile;
-
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- (VOID **)&SimpleFile,
- DriverBinding->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile);
-
- if (IsListEmpty (&Instance->FileHead) == FALSE) {
- //
- // Not all opened files are closed
- //
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Close and uninstall protocols.
- //
- Status = gBS->CloseProtocol (
- ControllerHandle,
- &gEfiFirmwareVolume2ProtocolGuid,
- gImageHandle,
- ControllerHandle
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->UninstallProtocolInterface (
- ControllerHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- &Instance->SimpleFs
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Free file structures
- //
- if (!IsListEmpty (&Instance->FileInfoHead)) {
- //
- // Free the Subtask list.
- //
- for (Entry = Instance->FileInfoHead.ForwardLink;
- Entry != (&Instance->FileInfoHead);
- )
- {
- DelEntry = Entry;
- Entry = Entry->ForwardLink;
- FvFileInfo = FVFS_FILE_INFO_FROM_LINK (DelEntry);
-
- RemoveEntryList (DelEntry);
- FreePool (FvFileInfo);
- }
- }
-
- if (Instance->Root != NULL) {
- //
- // Root->Name is statically allocated, no need to free.
- //
- if (Instance->Root->FvFileInfo != NULL) {
- FreePool (Instance->Root->FvFileInfo);
- }
-
- FreePool (Instance->Root);
- }
-
- //
- // Free Instance
- //
- if (Instance->VolumeLabel != NULL) {
- FreePool (Instance->VolumeLabel);
- }
-
- FreePool (Instance);
-
- return EFI_SUCCESS;
-}
-
-/**
- The user Entry Point for module FvSimpleFileSystem. The user code starts with this function.
-
- @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
-FvSimpleFileSystemEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &mDriverBinding,
- ImageHandle,
- &gFvSimpleFileSystemComponentName,
- &gFvSimpleFileSystemComponentName2
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file + This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware + volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL. + + It will expose a single directory, containing one file for each file in the firmware + volume. If a file has a UI section, its contents will be used as a filename. + Otherwise, a string representation of the GUID will be used. + Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION) + will have ".efi" added to their filename. + + Its primary intended use is to be able to start EFI applications embedded in FVs + from the UEFI shell. It is entirely read-only. + +Copyright (c) 2014, ARM Limited. All rights reserved. +Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FvSimpleFileSystemInternal.h" + +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + +// +// A Guid string is 32 hex characters with 4 hyphens and a NULL-terminated char: 37 characters total +// +#define GUID_STRING_SIZE (37 * sizeof (CHAR16)) + +#define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: " +#define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE - sizeof (CHAR16)) +#define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume" + +// +// Template for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL data structure. +// +EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate = { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + FvSimpleFileSystemOpenVolume +}; + +// +// Template for EFI_DRIVER_BINDING_PROTOCOL data structure. +// +EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = { + FvSimpleFileSystemDriverSupported, + FvSimpleFileSystemDriverStart, + FvSimpleFileSystemDriverStop, + 0, + NULL, + NULL +}; + +/** + Open the root directory on a volume. + + @param This A pointer to the volume to open the root directory. + @param RootFile A pointer to the location to return the opened file handle for the + root directory. + + @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(). + +**/ +EFI_STATUS +EFIAPI +FvSimpleFileSystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **RootFile + ) +{ + EFI_STATUS Status; + FV_FILESYSTEM_FILE *Root; + CHAR16 *UiSection; + EFI_GUID NameGuid; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINT32 Authentication; + UINTN Key; + EFI_FV_FILETYPE FileType; + UINTN Size; + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE_INFO *FvFileInfo; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + CHAR16 *Name; + UINTN NameLen; + UINTN NumChars; + UINTN DestMax; + + Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This); + Status = EFI_SUCCESS; + + if (Instance->Root == NULL) { + // + // Allocate file structure for root file + // + Root = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); + if (Root == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->Root = Root; + Root->Instance = Instance; + Root->Signature = FVFS_FILE_SIGNATURE; + CopyMem (&Root->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); + Root->FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO)); + if (Root->FvFileInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Root->FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO); + Root->FvFileInfo->FileInfo.Attribute = EFI_FILE_DIRECTORY | EFI_FILE_READ_ONLY; + + // + // Populate the instance's list of files. We consider anything a file that + // has a UI_SECTION, which we consider to be its filename. + // + FvProtocol = Instance->FvProtocol; + // + // Allocate Key + // + Key = 0; + + do { + FileType = EFI_FV_FILETYPE_ALL; + + Status = FvProtocol->GetNextFile ( + FvProtocol, + &Key, + &FileType, + &NameGuid, + &Attributes, + &Size + ); + if (EFI_ERROR (Status)) { + ASSERT (Status == EFI_NOT_FOUND); + break; + } + + // + // Get a file's name: If it has a UI section, use that, otherwise use + // its NameGuid. + // + UiSection = NULL; + Status = FvProtocol->ReadSection ( + FvProtocol, + &NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&UiSection, + &Size, + &Authentication + ); + if (!EFI_ERROR (Status)) { + Name = UiSection; + } else { + Name = AllocateZeroPool (GUID_STRING_SIZE); + if (Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid); + ASSERT ((NumChars + 1) * sizeof (CHAR16) == GUID_STRING_SIZE); + } + + // + // Found a file. + // Allocate a file structure and populate it. + // + NameLen = StrSize (Name); + if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { + NameLen += StrSize (L".efi") - sizeof (CHAR16); + } + + FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO) + NameLen - sizeof (CHAR16)); + if (FvFileInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FvFileInfo->Signature = FVFS_FILE_INFO_SIGNATURE; + InitializeListHead (&FvFileInfo->Link); + CopyMem (&FvFileInfo->NameGuid, &NameGuid, sizeof (EFI_GUID)); + FvFileInfo->Type = FileType; + + // + // Add ".efi" to filenames of drivers and applications. + // + DestMax = NameLen / sizeof (CHAR16); + Status = StrnCpyS (&FvFileInfo->FileInfo.FileName[0], DestMax, Name, StrLen (Name)); + ASSERT_EFI_ERROR (Status); + + if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { + Status = StrnCatS (&FvFileInfo->FileInfo.FileName[0], DestMax, L".efi", StrLen (L".efi")); + ASSERT_EFI_ERROR (Status); + } + + FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO) + NameLen - sizeof (CHAR16); + Status = FvFsGetFileSize (FvProtocol, FvFileInfo); + ASSERT_EFI_ERROR (Status); + FvFileInfo->FileInfo.PhysicalSize = FvFileInfo->FileInfo.FileSize; + FvFileInfo->FileInfo.Attribute = EFI_FILE_READ_ONLY; + + InsertHeadList (&Instance->FileInfoHead, &FvFileInfo->Link); + + FreePool (Name); + } while (TRUE); + + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + } + + Instance->Root->DirReadNext = NULL; + if (!IsListEmpty (&Instance->FileInfoHead)) { + Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); + } + + *RootFile = &Instance->Root->FileProtocol; + return Status; +} + +/** + Worker function to initialize Unicode Collation support. + + It tries to locate Unicode Collation (2) protocol and matches it with current + platform language code. + + @param AgentHandle The handle used to open Unicode Collation (2) protocol. + @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID. + @param VariableName The name of the RFC 4646 or ISO 639-2 language variable. + @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent. + + @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. + @retval Others The Unicode Collation (2) protocol has not been located. + +**/ +EFI_STATUS +InitializeUnicodeCollationSupportWorker ( + IN EFI_HANDLE AgentHandle, + IN EFI_GUID *ProtocolGuid, + IN CONST CHAR16 *VariableName, + IN CONST CHAR8 *DefaultLanguage + ) +{ + EFI_STATUS ReturnStatus; + EFI_STATUS Status; + UINTN NumHandles; + UINTN Index; + EFI_HANDLE *Handles; + EFI_UNICODE_COLLATION_PROTOCOL *Uci; + BOOLEAN Iso639Language; + CHAR8 *Language; + CHAR8 *BestLanguage; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + ProtocolGuid, + NULL, + &NumHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Iso639Language = (BOOLEAN)(ProtocolGuid == &gEfiUnicodeCollationProtocolGuid); + GetEfiGlobalVariable2 (VariableName, (VOID **)&Language, NULL); + + ReturnStatus = EFI_UNSUPPORTED; + for (Index = 0; Index < NumHandles; Index++) { + // + // Open Unicode Collation Protocol + // + Status = gBS->OpenProtocol ( + Handles[Index], + ProtocolGuid, + (VOID **)&Uci, + AgentHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Find the best matching matching language from the supported languages + // of Unicode Collation (2) protocol. + // + BestLanguage = GetBestLanguage ( + Uci->SupportedLanguages, + Iso639Language, + (Language == NULL) ? "" : Language, + DefaultLanguage, + NULL + ); + if (BestLanguage != NULL) { + FreePool (BestLanguage); + mUnicodeCollation = Uci; + ReturnStatus = EFI_SUCCESS; + break; + } + } + + if (Language != NULL) { + FreePool (Language); + } + + FreePool (Handles); + + return ReturnStatus; +} + +/** + Initialize Unicode Collation support. + + It tries to locate Unicode Collation 2 protocol and matches it with current + platform language code. If for any reason the first attempt fails, it then tries to + use Unicode Collation Protocol. + + @param AgentHandle The handle used to open Unicode Collation (2) protocol. + + @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located. + @retval Others The Unicode Collation (2) protocol has not been located. + +**/ +EFI_STATUS +InitializeUnicodeCollationSupport ( + IN EFI_HANDLE AgentHandle + ) +{ + EFI_STATUS Status; + + Status = EFI_UNSUPPORTED; + + // + // First try to use RFC 4646 Unicode Collation 2 Protocol. + // + Status = InitializeUnicodeCollationSupportWorker ( + AgentHandle, + &gEfiUnicodeCollation2ProtocolGuid, + L"PlatformLang", + (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang) + ); + // + // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back + // on the ISO 639-2 Unicode Collation Protocol. + // + if (EFI_ERROR (Status)) { + Status = InitializeUnicodeCollationSupportWorker ( + AgentHandle, + &gEfiUnicodeCollationProtocolGuid, + L"Lang", + (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang) + ); + } + + return Status; +} + +/** + Test to see if this driver supports ControllerHandle. + + @param DriverBinding Protocol instance pointer. + @param ControllerHandle Handle of device to test + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +FvSimpleFileSystemDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return gBS->OpenProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); +} + +/** + Start this driver on ControllerHandle by opening a FV protocol and + installing a SimpleFileSystem protocol on ControllerHandle. + + @param DriverBinding Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +FvSimpleFileSystemDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + FV_FILESYSTEM_INSTANCE *Instance; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_GUID *FvGuid; + UINTN NumChars; + + Status = InitializeUnicodeCollationSupport (DriverBinding->DriverBindingHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open FV protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **)&FvProtocol, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create an instance + // + Instance = AllocateZeroPool (sizeof (FV_FILESYSTEM_INSTANCE)); + ASSERT (Instance != NULL); + + Instance->Root = NULL; + Instance->FvProtocol = FvProtocol; + Instance->Signature = FVFS_INSTANCE_SIGNATURE; + InitializeListHead (&Instance->FileInfoHead); + InitializeListHead (&Instance->FileHead); + CopyMem (&Instance->SimpleFs, &mSimpleFsTemplate, sizeof (mSimpleFsTemplate)); + + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + EFI_NATIVE_INTERFACE, + &Instance->SimpleFs + ); + ASSERT_EFI_ERROR (Status); + + // + // Decide on a filesystem volume label, which will include the FV's guid. + // Get the device path to find the FV's GUID + // + Instance->VolumeLabel = NULL; + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&FvDevicePath, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Iterate over device path until we find a firmware volume node + // + while (!IsDevicePathEndType (FvDevicePath)) { + if ((DevicePathType (FvDevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (FvDevicePath) == MEDIA_PIWG_FW_VOL_DP)) + { + // + // Allocate the volume label + // + Instance->VolumeLabel = AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE); + // + // Check the allocation was successful + // + if (Instance->VolumeLabel != NULL) { + // + // Extract the FV's guid + // + FvGuid = &((MEDIA_FW_VOL_DEVICE_PATH *)FvDevicePath)->FvName; + // + // Build the volume label string + // + NumChars = UnicodeSPrint ( + Instance->VolumeLabel, + FVFS_VOLUME_LABEL_SIZE, + FVFS_VOLUME_LABEL_PREFIX L"%g", + FvGuid + ); + ASSERT ((NumChars + 1) * sizeof (CHAR16) == FVFS_VOLUME_LABEL_SIZE); + } + + break; + } + + FvDevicePath = NextDevicePathNode (FvDevicePath); + } + } + + // + // If we didn't decide on a volume label, set a fallback one + // + if (Instance->VolumeLabel == NULL) { + Instance->VolumeLabel = AllocateCopyPool ( + sizeof (FVFS_FALLBACK_VOLUME_LABEL), + FVFS_FALLBACK_VOLUME_LABEL + ); + } + + return EFI_SUCCESS; +} + +/** + Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing + the FV protocol on ControllerHandle. + + @param DriverBinding Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +FvSimpleFileSystemDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + FV_FILESYSTEM_INSTANCE *Instance; + FV_FILESYSTEM_FILE_INFO *FvFileInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *DelEntry; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFile; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&SimpleFile, + DriverBinding->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile); + + if (IsListEmpty (&Instance->FileHead) == FALSE) { + // + // Not all opened files are closed + // + return EFI_DEVICE_ERROR; + } + + // + // Close and uninstall protocols. + // + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiFirmwareVolume2ProtocolGuid, + gImageHandle, + ControllerHandle + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &Instance->SimpleFs + ); + ASSERT_EFI_ERROR (Status); + + // + // Free file structures + // + if (!IsListEmpty (&Instance->FileInfoHead)) { + // + // Free the Subtask list. + // + for (Entry = Instance->FileInfoHead.ForwardLink; + Entry != (&Instance->FileInfoHead); + ) + { + DelEntry = Entry; + Entry = Entry->ForwardLink; + FvFileInfo = FVFS_FILE_INFO_FROM_LINK (DelEntry); + + RemoveEntryList (DelEntry); + FreePool (FvFileInfo); + } + } + + if (Instance->Root != NULL) { + // + // Root->Name is statically allocated, no need to free. + // + if (Instance->Root->FvFileInfo != NULL) { + FreePool (Instance->Root->FvFileInfo); + } + + FreePool (Instance->Root); + } + + // + // Free Instance + // + if (Instance->VolumeLabel != NULL) { + FreePool (Instance->VolumeLabel); + } + + FreePool (Instance); + + return EFI_SUCCESS; +} + +/** + The user Entry Point for module FvSimpleFileSystem. The user code starts with this function. + + @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 +FvSimpleFileSystemEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &mDriverBinding, + ImageHandle, + &gFvSimpleFileSystemComponentName, + &gFvSimpleFileSystemComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} |
