From ba529e7e5a78e8f20916e1ead53b47a68ac46118 Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Mon, 23 Nov 2015 05:41:28 +0000 Subject: [PATCH] MdeModulePkg FileExplorerLib: Create file explorer library. This library support select one file from the specified directory or from system root directory. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao Reviewed-by: Samer El-Haj-Mahmoud git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18917 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/FileExplorerLib.h | 60 + .../Library/FileExplorerLib/FileExplorer.c | 1504 +++++++++++++++++ .../Library/FileExplorerLib/FileExplorer.h | 239 +++ .../FileExplorerLib/FileExplorerLib.inf | 60 + .../FileExplorerLib/FileExplorerString.uni | Bin 0 -> 1852 bytes .../FileExplorerLib/FileExplorerVfr.vfr | 32 + .../Library/FileExplorerLib/FormGuid.h | 27 + MdeModulePkg/MdeModulePkg.dec | 4 + MdeModulePkg/MdeModulePkg.dsc | 2 + 9 files changed, 1928 insertions(+) create mode 100644 MdeModulePkg/Include/Library/FileExplorerLib.h create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorer.c create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorer.h create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr create mode 100644 MdeModulePkg/Library/FileExplorerLib/FormGuid.h diff --git a/MdeModulePkg/Include/Library/FileExplorerLib.h b/MdeModulePkg/Include/Library/FileExplorerLib.h new file mode 100644 index 0000000000..fbe1fc205c --- /dev/null +++ b/MdeModulePkg/Include/Library/FileExplorerLib.h @@ -0,0 +1,60 @@ +/** @file + + This library class defines a set of interfaces for how to do file explorer. + +Copyright (c) 2007 - 2015, 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 that 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. + +**/ + +#ifndef __FILE_EXPLORER_LIB_H__ +#define __FILE_EXPLORER_LIB_H__ + +/** + Prototype for the next process after user chosed one file. + + @param[in] FilePath The device path of the find file. + + @retval TRUE Need exit file explorer after do the extra task. + @retval FALSE Not need to exit file explorer after do the extra task. + +**/ +typedef +BOOLEAN +(EFIAPI *CHOOSE_HANDLER)( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ); + +/** + Choose a file in the specified directory. + + If user input NULL for the RootDirectory, will choose file in the system. + + If user input *File != NULL, function will return the allocate device path + info for the choosed file, caller has to free the memory after use it. + + @param RootDirectory Pointer to the root directory. + @param FileType The file type need to choose. + @param ChooseHandler Function pointer to the extra task need to do + after choose one file. + @param File Return the device path for the last time chosed file. + + @retval EFI_SUCESS Choose the file success. + @retval Other errors Choose the file failed. +**/ +EFI_STATUS +EFIAPI +ChooseFile ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + IN CHAR16 *FileType, OPTIONAL + IN CHOOSE_HANDLER ChooseHandler, OPTIONAL + OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL + ); + +#endif diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c new file mode 100644 index 0000000000..4e25efc22b --- /dev/null +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c @@ -0,0 +1,1504 @@ +/** @file + File explorer related functions. + + Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
+ This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + +**/ + +#include "FileExplorer.h" + +EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID; + +/// +/// File system selection menu +/// +MENU_OPTION mFsOptionMenu = { + MENU_OPTION_SIGNATURE, + {NULL}, + 0, + FALSE +}; + +FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = { + FILE_EXPLORER_CALLBACK_DATA_SIGNATURE, + NULL, + NULL, + { + LibExtractConfig, + LibRouteConfig, + LibCallback + }, + NULL, + &mFsOptionMenu, + 0 +}; + +HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath; + +HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + // + // Will be replace with gEfiCallerIdGuid in code. + // + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +VOID *mLibStartOpCodeHandle = NULL; +VOID *mLibEndOpCodeHandle = NULL; +EFI_IFR_GUID_LABEL *mLibStartLabel = NULL; +EFI_IFR_GUID_LABEL *mLibEndLabel = NULL; + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LibExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LibRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + When user select a interactive opcode, this callback will be triggered. + Based on the Question(QuestionId) that triggers the callback, the corresponding + actions is performed. It handles: + + 1) Process the axtra action or exit file explorer when user select one file . + 2) update of file content if a dir is selected. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval other error Error occur when parse one directory. +**/ +EFI_STATUS +EFIAPI +LibCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + BOOLEAN NeedExit; + + NeedExit = TRUE; + + if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) { + // + // Do nothing for other UEFI Action. Only do call back when data is changed. + // + return EFI_UNSUPPORTED; + } + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + + if (Action == EFI_BROWSER_ACTION_CHANGED) { + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (QuestionId >= FILE_OPTION_OFFSET) { + LibGetDevicePath(QuestionId); + + // + // Process the extra action. + // + if (gFileExplorerPrivate.ChooseHandler != NULL) { + NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath); + } + + if (NeedExit) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + } + } else if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (Value == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (QuestionId >= FILE_OPTION_OFFSET) { + Status = LibUpdateFileExplorer (QuestionId); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +/** + Create a menu entry by given menu type. + + @retval NULL If failed to create the menu. + @return the new menu entry. + +**/ +MENU_ENTRY * +LibCreateMenuEntry ( + VOID + ) +{ + MENU_ENTRY *MenuEntry; + + // + // Create new menu entry + // + MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY)); + if (MenuEntry == NULL) { + return NULL; + } + + MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT)); + if (MenuEntry->VariableContext == NULL) { + FreePool (MenuEntry); + return NULL; + } + + MenuEntry->Signature = MENU_ENTRY_SIGNATURE; + return MenuEntry; +} + + +/** + Get the Menu Entry from the list in Menu Entry List. + + If MenuNumber is great or equal to the number of Menu + Entry in the list, then ASSERT. + + @param MenuOption The Menu Entry List to read the menu entry. + @param MenuNumber The index of Menu Entry. + + @return The Menu Entry. + +**/ +MENU_ENTRY * +LibGetMenuEntry ( + MENU_OPTION *MenuOption, + UINTN MenuNumber + ) +{ + MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + ASSERT (MenuNumber < MenuOption->MenuNumber); + + List = MenuOption->Head.ForwardLink; + for (Index = 0; Index < MenuNumber; Index++) { + List = List->ForwardLink; + } + + NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE); + + return NewMenuEntry; +} + +/** + Free up all resource allocated for a BM_MENU_ENTRY. + + @param MenuEntry A pointer to BM_MENU_ENTRY. + +**/ +VOID +LibDestroyMenuEntry ( + MENU_ENTRY *MenuEntry + ) +{ + FILE_CONTEXT *FileContext; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + + if (!FileContext->IsRoot) { + FreePool (FileContext->DevicePath); + } else { + if (FileContext->FileHandle != NULL) { + FileContext->FileHandle->Close (FileContext->FileHandle); + } + } + + if (FileContext->FileName != NULL) { + FreePool (FileContext->FileName); + } + + FreePool (FileContext); + + FreePool (MenuEntry->DisplayString); + if (MenuEntry->HelpString != NULL) { + FreePool (MenuEntry->HelpString); + } + + FreePool (MenuEntry); +} + + +/** + Free resources allocated in Allocate Rountine. + + @param FreeMenu Menu to be freed +**/ +VOID +LibFreeMenu ( + MENU_OPTION *FreeMenu + ) +{ + MENU_ENTRY *MenuEntry; + while (!IsListEmpty (&FreeMenu->Head)) { + MenuEntry = CR ( + FreeMenu->Head.ForwardLink, + MENU_ENTRY, + Link, + MENU_ENTRY_SIGNATURE + ); + RemoveEntryList (&MenuEntry->Link); + LibDestroyMenuEntry (MenuEntry); + } + FreeMenu->MenuNumber = 0; +} + +/** + + Function opens and returns a file handle to the root directory of a volume. + + @param DeviceHandle A handle for a device + + @return A valid file handle or NULL is returned + +**/ +EFI_FILE_HANDLE +LibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE File; + + File = NULL; + + // + // File the file system interface to the device + // + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID *) &Volume + ); + + // + // Open the root directory of the volume + // + if (!EFI_ERROR (Status)) { + Status = Volume->OpenVolume ( + Volume, + &File + ); + } + // + // Done + // + return EFI_ERROR (Status) ? NULL : File; +} + +/** + This function converts an input device structure to a Unicode string. + + @param DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +LibDevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + if (DevPath == NULL) { + return NULL; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + ASSERT_EFI_ERROR (Status); + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + + return ToText; +} + +/** + Duplicate a string. + + @param Src The source. + + @return A new string which is duplicated copy of the source. + @retval NULL If there is not enough memory. + +**/ +CHAR16 * +LibStrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); + Dest = AllocateZeroPool (Size); + ASSERT (Dest != NULL); + if (Dest != NULL) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +/** + + Function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + + @param FHand File Handle. + @param InfoType Info type need to get. + + @retval A pointer to a buffer with file information or NULL is returned + +**/ +VOID * +LibFileInfo ( + IN EFI_FILE_HANDLE FHand, + IN EFI_GUID *InfoType + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + Buffer = NULL; + BufferSize = 0; + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocatePool (BufferSize); + ASSERT (Buffer != NULL); + } + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + + return Buffer; +} + +/** + + Get file type base on the file name. + Just cut the file name, from the ".". eg ".efi" + + @param FileName File need to be checked. + + @retval the file type string. + +**/ +CHAR16* +LibGetTypeFromName ( + IN CHAR16 *FileName + ) +{ + UINTN Index; + + Index = StrLen (FileName) - 1; + while ((FileName[Index] != L'.') && (Index != 0)) { + Index--; + } + + return Index == 0 ? NULL : &FileName[Index]; +} + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +LibToLowerString ( + IN CHAR16 *String + ) +{ + CHAR16 *TmpStr; + + for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) { + if (*TmpStr >= L'A' && *TmpStr <= L'Z') { + *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a'); + } + } +} + +/** + + Check whether current FileName point to a valid + Efi Image File. + + @param FileName File need to be checked. + + @retval TRUE Is Efi Image + @retval FALSE Not a valid Efi Image + +**/ +BOOLEAN +LibIsSupportedFileType ( + IN UINT16 *FileName + ) +{ + CHAR16 *InputFileType; + CHAR16 *TmpStr; + BOOLEAN IsSupported; + + if (gFileExplorerPrivate.FileType == NULL) { + return TRUE; + } + + InputFileType = LibGetTypeFromName (FileName); + // + // If the file not has *.* style, always return TRUE. + // + if (InputFileType == NULL) { + return TRUE; + } + + TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType); + LibToLowerString(TmpStr); + + IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE); + + FreePool (TmpStr); + return IsSupported; +} + +/** + + Append file name to existing file name. + + @param Str1 The existing file name + @param Str2 The file name to be appended + + @return Allocate a new string to hold the appended result. + Caller is responsible to free the returned string. + +**/ +CHAR16 * +LibAppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +{ + UINTN Size1; + UINTN Size2; + CHAR16 *Str; + CHAR16 *TmpStr; + CHAR16 *Ptr; + CHAR16 *LastSlash; + + Size1 = StrSize (Str1); + Size2 = StrSize (Str2); + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (Str != NULL); + + TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (TmpStr != NULL); + + StrCat (Str, Str1); + if (!((*Str == '\\') && (*(Str + 1) == 0))) { + StrCat (Str, L"\\"); + } + + StrCat (Str, Str2); + + Ptr = Str; + LastSlash = Str; + while (*Ptr != 0) { + if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { + // + // Convert "\Name\..\" to "\" + // DO NOT convert the .. if it is at the end of the string. This will + // break the .. behavior in changing directories. + // + + // + // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpy (TmpStr, Ptr + 3); + StrCpy (LastSlash, TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { + // + // Convert a "\.\" to a "\" + // + + // + // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpy (TmpStr, Ptr + 2); + StrCpy (Ptr, TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\') { + LastSlash = Ptr; + } + + Ptr++; + } + + FreePool (TmpStr); + + return Str; +} + +/** + This function build the FsOptionMenu list which records all + available file system in the system. They includes all instances + of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM. + + + @retval EFI_SUCCESS Success find the file system + @retval EFI_OUT_OF_RESOURCES Can not create menu entry + +**/ +EFI_STATUS +LibFindFileSystem ( + VOID + ) +{ + UINTN NoSimpleFsHandles; + UINTN NoLoadFileHandles; + EFI_HANDLE *SimpleFsHandle; + EFI_HANDLE *LoadFileHandle; + UINT16 *VolumeLabel; + UINTN Index; + EFI_STATUS Status; + MENU_ENTRY *MenuEntry; + FILE_CONTEXT *FileContext; + UINTN OptionNumber; + EFI_FILE_SYSTEM_VOLUME_LABEL *Info; + + NoSimpleFsHandles = 0; + NoLoadFileHandles = 0; + OptionNumber = 0; + + // + // Locate Handles that support Simple File System protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoSimpleFsHandles, + &SimpleFsHandle + ); + if (!EFI_ERROR (Status)) { + // + // Find all the instances of the File System prototocol + // + for (Index = 0; Index < NoSimpleFsHandles; Index++) { + // + // Allocate pool for this load option + // + MenuEntry = LibCreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (SimpleFsHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->DeviceHandle = SimpleFsHandle[Index]; + FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle); + if (FileContext->FileHandle == NULL) { + LibDestroyMenuEntry (MenuEntry); + continue; + } + + MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle)); + FileContext->FileName = LibStrDuplicate (L"\\"); + FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName); + FileContext->IsDir = TRUE; + FileContext->IsRoot = TRUE; + + // + // Get current file system's Volume Label + // + Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid); + if (Info == NULL) { + VolumeLabel = L"NO FILE SYSTEM INFO"; + } else { + if (Info->VolumeLabel == NULL) { + VolumeLabel = L"NULL VOLUME LABEL"; + } else { + VolumeLabel = Info->VolumeLabel; + if (*VolumeLabel == 0x0000) { + VolumeLabel = L"NO VOLUME LABEL"; + } + } + } + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"%s, [%s]", + VolumeLabel, + MenuEntry->HelpString + ); + MenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + MenuEntry->DisplayString, + NULL + ); + FreePool (Info); + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); + } + } + + if (NoSimpleFsHandles != 0) { + FreePool (SimpleFsHandle); + } + + // + // Searching for handles that support Load File protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadFileProtocolGuid, + NULL, + &NoLoadFileHandles, + &LoadFileHandle + ); + + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < NoLoadFileHandles; Index++) { + MenuEntry = LibCreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (LoadFileHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->DeviceHandle = LoadFileHandle[Index]; + FileContext->IsRoot = TRUE; + + FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle); + FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath); + + MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath); + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"Load File [%s]", + MenuEntry->HelpString + ); + MenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + MenuEntry->DisplayString, + NULL + ); + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); + } + } + + if (NoLoadFileHandles != 0) { + FreePool (LoadFileHandle); + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input menu info. + + @param MenuEntry Input Menu info. + @param RetFileHandle Return the file handle for the input device path. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromMenu ( + IN MENU_ENTRY *MenuEntry, + OUT EFI_FILE_HANDLE *RetFileHandle + ) +{ + EFI_FILE_HANDLE Dir; + EFI_FILE_HANDLE NewDir; + FILE_CONTEXT *FileContext; + EFI_STATUS Status; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + Dir = FileContext->FileHandle; + + // + // Open current directory to get files from it + // + Status = Dir->Open ( + Dir, + &NewDir, + FileContext->FileName, + EFI_FILE_READ_ONLY, + 0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!FileContext->IsRoot) { + Dir->Close (Dir); + } + + *RetFileHandle = NewDir; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input device path info. + + @param RootDirectory Device path info. + @param RetFileHandle Return the file handle for the input device path. + @param ParentFileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + OUT EFI_FILE_HANDLE *RetFileHandle, + OUT UINT16 **ParentFileName, + OUT EFI_HANDLE *DeviceHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE LastHandle; + CHAR16 *TempPath; + + *ParentFileName = NULL; + + // + // Attempt to access the file via a file system interface + // + DevicePathNode = RootDirectory; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the Volume to get the File System handle + // + Status = Volume->OpenVolume (Volume, &FileHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + *DeviceHandle = Handle; + + if (IsDevicePathEnd(DevicePathNode)) { + *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\"); + *RetFileHandle = FileHandle; + return EFI_SUCCESS; + } + + // + // Duplicate the device path to avoid the access to unaligned device path node. + // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH + // nodes, It assures the fields in device path nodes are 2 byte aligned. + // + TempDevicePathNode = DuplicateDevicePath (DevicePathNode); + if (TempDevicePathNode == NULL) { + + // + // Setting Status to an EFI_ERROR value will cause the rest of + // the file system support below to be skipped. + // + Status = EFI_OUT_OF_RESOURCES; + } + + // + // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the + // directory information and filename can be seperate. The goal is to inch + // our way down each device path node and close the previous node + // + DevicePathNode = TempDevicePathNode; + while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) { + if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH || + DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + LastHandle = FileHandle; + FileHandle = NULL; + + Status = LastHandle->Open ( + LastHandle, + &FileHandle, + ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName, + EFI_FILE_MODE_READ, + 0 + ); + if (*ParentFileName == NULL) { + *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + } else { + TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + FreePool (*ParentFileName); + *ParentFileName = TempPath; + } + + // + // Close the previous node + // + LastHandle->Close (LastHandle); + + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + *RetFileHandle = FileHandle; + + Status = EFI_SUCCESS; + +Done: + if (TempDevicePathNode != NULL) { + FreePool (TempDevicePathNode); + } + + if ((FileHandle != NULL) && (EFI_ERROR (Status))) { + FileHandle->Close (FileHandle); + } + + return Status; +} + +/** + Find files under current directory. + + All files and sub-directories in current directory + will be stored in DirectoryMenu for future use. + + @param FileHandle Parent file handle. + @param FileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCCESS Get files from current dir successfully. + @return Other value if can't get files from current dir. + +**/ +EFI_STATUS +LibFindFiles ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT16 *FileName, + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_FILE_INFO *DirInfo; + UINTN BufferSize; + UINTN DirBufferSize; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + UINTN Pass; + EFI_STATUS Status; + UINTN OptionNumber; + + OptionNumber = 0; + + DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; + DirInfo = AllocateZeroPool (DirBufferSize); + if (DirInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all files in current directory + // Pass 1 to get Directories + // Pass 2 to get files that are EFI images + // + for (Pass = 1; Pass <= 2; Pass++) { + FileHandle->SetPosition (FileHandle, 0); + for (;;) { + BufferSize = DirBufferSize; + Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo); + if (EFI_ERROR (Status) || BufferSize == 0) { + break; + } + + if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || + ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) + ) { + // + // Pass 1 is for Directories + // Pass 2 is for file names + // + continue; + } + + if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) { + // + // Slip file unless it is a directory entry or a .EFI file + // + continue; + } + + NewMenuEntry = LibCreateMenuEntry (); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + NewFileContext->DeviceHandle = DeviceHandle; + NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName); + NewFileContext->FileHandle = FileHandle; + NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName); + NewMenuEntry->HelpString = NULL; + NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); + + if (NewFileContext->IsDir) { + BufferSize = StrLen (DirInfo->FileName) * 2 + 6; + NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); + UnicodeSPrint ( + NewMenuEntry->DisplayString, + BufferSize, + L"<%s>", + DirInfo->FileName + ); + } else { + NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName); + } + + NewMenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + NewMenuEntry->DisplayString, + NULL + ); + + NewFileContext->IsRoot = FALSE; + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link); + } + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + + FreePool (DirInfo); + + return EFI_SUCCESS; +} + +/** + Refresh the global UpdateData structure. + +**/ +VOID +LibRefreshUpdateData ( + VOID + ) +{ + // + // Free current updated date + // + if (mLibStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibStartOpCodeHandle); + } + if (mLibEndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibEndOpCodeHandle); + } + + // + // Create new OpCode Handle + // + mLibStartOpCodeHandle = HiiAllocateOpCodeHandle (); + mLibEndOpCodeHandle = HiiAllocateOpCodeHandle (); + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibStartLabel->Number = FORM_FILE_EXPLORER_ID; + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibEndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibEndLabel->Number = LABEL_END; +} + +/** + + Update the File Explore page. + +**/ +VOID +LibUpdateFileExplorePage ( + VOID + ) +{ + UINTN Index; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + MENU_OPTION *MenuOption; + + NewMenuEntry = NULL; + NewFileContext = NULL; + + LibRefreshUpdateData (); + MenuOption = gFileExplorerPrivate.FsOptionMenu; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = LibGetMenuEntry (MenuOption, Index); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (!NewFileContext->IsDir) { + // + // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. + // + HiiCreateActionOpCode ( + mLibStartOpCodeHandle, + (UINT16) (FILE_OPTION_OFFSET + Index), + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + 0 + ); + } else { + // + // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState. + // + HiiCreateGotoOpCode ( + mLibStartOpCodeHandle, + FORM_FILE_EXPLORER_ID, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (FILE_OPTION_OFFSET + Index) + ); + } + } + + HiiUpdateForm ( + gFileExplorerPrivate.FeHiiHandle, + &FileExplorerGuid, + FORM_FILE_EXPLORER_ID, + mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID + mLibEndOpCodeHandle // LABEL_END + ); +} + +/** + Update the file explower page with the refershed file system. + + @param KeyValue Key value to identify the type of data to expect. + + @retval EFI_SUCCESS Update the file explorer form success. + @retval other errors Error occur when parse one directory. + +**/ +EFI_STATUS +LibUpdateFileExplorer ( + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + + Status = EFI_SUCCESS; + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (NewFileContext->IsDir) { + RemoveEntryList (&NewMenuEntry->Link); + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle); + Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle); + if (!EFI_ERROR (Status)) { + LibUpdateFileExplorePage (); + } else { + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + } + LibDestroyMenuEntry (NewMenuEntry); + } + + return Status; +} + +/** + Get the device path info saved in the menu structure. + + @param KeyValue Key value to identify the type of data to expect. + +**/ +VOID +LibGetDevicePath ( + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath); +} + +/** + Choose a file in the specified directory. + + If user input NULL for the RootDirectory, will choose file in the system. + + If user input *File != NULL, function will return the allocate device path + info for the choosed file, caller has to free the memory after use it. + + @param RootDirectory Pointer to the root directory. + @param FileType The file type need to choose. + @param ChooseHandler Function pointer to the extra task need to do + after choose one file. + @param File Return the device path for the last time chosed file. + + @retval EFI_SUCESS Choose file success. + @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL + One of them must not NULL. + @retval Other errors Choose file failed. +**/ +EFI_STATUS +EFIAPI +ChooseFile ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + IN CHAR16 *FileType, OPTIONAL + IN CHOOSE_HANDLER ChooseHandler, OPTIONAL + OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL + ) +{ + EFI_FILE_HANDLE FileHandle; + EFI_STATUS Status; + UINT16 *FileName; + EFI_HANDLE DeviceHandle; + + if ((ChooseHandler == NULL) && (File == NULL)) { + return EFI_INVALID_PARAMETER; + } + + FileName = NULL; + + gFileExplorerPrivate.RetDevicePath = NULL; + gFileExplorerPrivate.ChooseHandler = ChooseHandler; + if (FileType != NULL) { + gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType); + LibToLowerString(gFileExplorerPrivate.FileType); + } else { + gFileExplorerPrivate.FileType = NULL; + } + + if (RootDirectory == NULL) { + Status = LibFindFileSystem(); + } else { + Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = LibFindFiles (FileHandle, FileName, DeviceHandle); + } + if (EFI_ERROR (Status)) { + goto Done; + } + + LibUpdateFileExplorePage(); + + gFileExplorerPrivate.FormBrowser2->SendForm ( + gFileExplorerPrivate.FormBrowser2, + &gFileExplorerPrivate.FeHiiHandle, + 1, + &FileExplorerGuid, + 0, + NULL, + NULL + ); + +Done: + if ((Status == EFI_SUCCESS) && (File != NULL)) { + *File = gFileExplorerPrivate.RetDevicePath; + } else if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + + if (gFileExplorerPrivate.FileType != NULL) { + FreePool (gFileExplorerPrivate.FileType); + } + + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + + if (FileName != NULL) { + FreePool (FileName); + } + + return Status; +} + +/** + + Install Boot Manager Menu driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCEESS Install File explorer library success. + +**/ +EFI_STATUS +EFIAPI +FileExplorerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); + ASSERT (gHiiVendorDevicePath != NULL); + CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid); + + // + // Install Device Path Protocol and Config Access protocol to driver handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Post our File Explorer VFR binary to the HII database. + // + gFileExplorerPrivate.FeHiiHandle = HiiAddPackages ( + &FileExplorerGuid, + gFileExplorerPrivate.FeDriverHandle, + FileExplorerVfrBin, + FileExplorerLibStrings, + NULL + ); + ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL); + + // + // Locate Formbrowser2 protocol + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2); + ASSERT_EFI_ERROR (Status); + + InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head); + + return EFI_SUCCESS; +} + +/** + Unloads the application and its installed protocol. + + @param[in] ImageHandle Handle that identifies the image to be unloaded. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS The image has been unloaded. +**/ +EFI_STATUS +EFIAPI +FileExplorerLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ASSERT (gHiiVendorDevicePath != NULL); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle); + + FreePool (gHiiVendorDevicePath); + + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h new file mode 100644 index 0000000000..4c27ea1d9d --- /dev/null +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h @@ -0,0 +1,239 @@ +/** @file + File explorer lib. + +Copyright (c) 2015, 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. +**/ + +#ifndef _FILE_EXPLORER_H_ +#define _FILE_EXPLORER_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FormGuid.h" + +#define FILE_EXPLORER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('f', 'e', 'c', 'k') + + +#pragma pack(1) + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_FILE_HANDLE FileHandle; + UINT16 *FileName; + + BOOLEAN IsRoot; + BOOLEAN IsDir; +} FILE_CONTEXT; + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + UINT16 *DisplayString; + UINT16 *HelpString; + EFI_STRING_ID DisplayStringToken; + EFI_STRING_ID HelpStringToken; + VOID *VariableContext; +} MENU_ENTRY; + +typedef struct { + UINTN Signature; + LIST_ENTRY Head; + UINTN MenuNumber; + BOOLEAN Used; +} MENU_OPTION; + +typedef struct { + // + // Shared callback data. + // + UINTN Signature; + + // + // File explorer formset callback data. + // + EFI_HII_HANDLE FeHiiHandle; + EFI_HANDLE FeDriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL FeConfigAccess; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + MENU_OPTION *FsOptionMenu; + CHAR16 *FileType; + CHOOSE_HANDLER ChooseHandler; + EFI_DEVICE_PATH_PROTOCOL *RetDevicePath; + +} FILE_EXPLORER_CALLBACK_DATA; + +#define FILE_EXPLORER_PRIVATE_FROM_THIS(a) CR (a, FILE_EXPLORER_CALLBACK_DATA, FeConfigAccess, FILE_EXPLORER_CALLBACK_DATA_SIGNATURE) + +#pragma pack() + +extern UINT8 FileExplorerVfrBin[]; + +#define MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u') +#define MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r') + +/// +/// Define the maximum characters that will be accepted. +/// +#define MAX_CHAR 480 +#define FILE_OPTION_OFFSET 0x8000 +#define FILE_OPTION_MASK 0x7FFF + + +/** + This function processes the results of changes in configuration. + When user select a interactive opcode, this callback will be triggered. + Based on the Question(QuestionId) that triggers the callback, the corresponding + actions is performed. It handles: + + 1) the addition of boot option. + 2) the addition of driver option. + 3) exit from file browser + 4) update of file content if a dir is selected. + 5) boot the file if a file is selected in "boot from file" + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. + +**/ +EFI_STATUS +EFIAPI +LibCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request - A null-terminated Unicode string in format. + @param Progress - On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results - A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LibExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration - A null-terminated Unicode string in format. + @param Progress - A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LibRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + Update the file explower page with the refershed file system. + + @param KeyValue Key value to identify the type of data to expect. + + @retval EFI_SUCCESS Update the file explorer form success. + @retval other errors Error occur when parse one directory. + +**/ +EFI_STATUS +LibUpdateFileExplorer ( + IN UINT16 KeyValue + ); + + +/** + Get the device path info saved in the menu structure. + + @param KeyValue Key value to identify the type of data to expect. + +**/ +VOID +LibGetDevicePath ( + IN UINT16 KeyValue + ); + +#endif diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf new file mode 100644 index 0000000000..a2be6144bd --- /dev/null +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf @@ -0,0 +1,60 @@ +## @file +# library defines a set of interfaces for how to do file explorer. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FileExplorerLib + FILE_GUID = 4FC9C630-0F90-4053-8F13-264CBD22FC58 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = FileExplorerLib|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = FileExplorerLibConstructor + DESTRUCTOR = FileExplorerLibDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + FileExplorer.h + FileExplorerVfr.vfr + FileExplorerString.uni + FileExplorer.c + FormGuid.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DevicePathLib + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + HiiLib + +[Guids] + gEfiFileSystemVolumeLabelInfoIdGuid ## CONSUMES ## GUID (Indicate the information type is volume) + gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode) + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## PROTOCOL CONSUMES + gEfiLoadFileProtocolGuid ## PROTOCOL CONSUMES + gEfiHiiConfigAccessProtocolGuid ## PROTOCOL CONSUMES + gEfiFormBrowser2ProtocolGuid ## PROTOCOL CONSUMES + gEfiDevicePathToTextProtocolGuid ## PROTOCOL CONSUMES \ No newline at end of file diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni b/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni new file mode 100644 index 0000000000000000000000000000000000000000..4315a368b80f2b78afb2e4e0b93017b379068488 GIT binary patch literal 1852 zcmc(g-EPxB5QXO&iFdG?n}TQy72E;hM-8e}prWb7U6dwq8YyusJ0awWd5gk#W|C%& z5`?%x*4pdcnK@_9%-TQiPE6NhuFT$8ZeyF+&>q?YU(Z-g=X$@gxmDN|HsWo7wY&<( zoH1iovz{}nc)sH~V<)qZ)^oc#9tHEl`ph!BcE5@Huk5&imtwysPH8L09@(wOJS4^= zVw~DjuIJ2-)^E@3g*{<@4vr8f%oU*`hVDH_729KW-m)(XsO%f}0hTYx z=Zn2=aO}Wk>^av&&WXDux_mRwa^TMziy3Ukj;v_XPAdzWVk?$gPMIBInXeQVk-_c$coxjGI}h|(~vIfc^B5? zCi@|p$v4=@N_y9ab+KK~^WI3!<~sy`gK$;BU^J>^EccB|1q~URmq@t%W+`JVH}_b@Vk7%YsvX&37rY z1Nuk%>H(dP1NYtSmy^wrwK>o7Yp>P)0fKzPQ_NbtrC+=&>)_M1PhehfbwSq3IV&HW zQSjP*-*Q=iG=hCI198z1^6m)#y1ENF)gVRQmvfseFVMKl_-dETKa=^H>(ODaz=>_c8hf(BBml literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr new file mode 100644 index 0000000000..ee9755fb5d --- /dev/null +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr @@ -0,0 +1,32 @@ +///** @file +// +// File Explorer Formset +// +// Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
+// This software and associated documentation (if any) is furnished +// under a license and may only be used or copied in accordance +// with the terms of the license. Except as permitted by such +// license, no part of this software or documentation may be +// reproduced, stored in a retrieval system, or transmitted in any +// form or by any means without the express written consent of +// Intel Corporation. + + +//**/ + +#include "FormGuid.h" + +formset + guid = EFI_FILE_EXPLORE_FORMSET_GUID, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE), + help = STRING_TOKEN(STR_NULL_STRING), + classguid = EFI_FILE_EXPLORE_FORMSET_GUID, + + form formid = FORM_FILE_EXPLORER_ID, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + label LABEL_END; + endform; + +endformset; \ No newline at end of file diff --git a/MdeModulePkg/Library/FileExplorerLib/FormGuid.h b/MdeModulePkg/Library/FileExplorerLib/FormGuid.h new file mode 100644 index 0000000000..d8420123c3 --- /dev/null +++ b/MdeModulePkg/Library/FileExplorerLib/FormGuid.h @@ -0,0 +1,27 @@ +/** @file + Formset guids, form id and VarStore data structure for Boot Maintenance Manager. + + Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+ This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + +**/ +#ifndef _FILE_EXPLORER_FORM_GUID_H_ +#define _FILE_EXPLORER_FORM_GUID_H_ + + +#define EFI_FILE_EXPLORE_FORMSET_GUID \ + { \ + 0x1f2d63e1, 0xfebd, 0x4dc7, {0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, 0x5b} \ + } + +#define FORM_FILE_EXPLORER_ID 0x1000 +#define LABEL_END 0xffff + +#endif + diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index f00d6f030a..5d3258d020 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -130,6 +130,10 @@ ## @libraryclass Provides services to get variable error flag and do platform variable cleanup. # PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h + + ## @libraryclass Provides services to get do the file explorer. + # + FileExplorerLib|Include/Library/FileExplorerLib.h ## @libraryclass Provides image decoding service. # diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 5c28fab73d..7447be731e 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -99,6 +99,7 @@ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf [LibraryClasses.EBC.PEIM] IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf @@ -287,6 +288,7 @@ MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf + MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf MdeModulePkg/Universal/BdsDxe/BdsDxe.inf MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf