]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg FileExplorerLib: Create file explorer library.
authorEric Dong <eric.dong@intel.com>
Mon, 23 Nov 2015 05:41:28 +0000 (05:41 +0000)
committerydong10 <ydong10@Edk2>
Mon, 23 Nov 2015 05:41:28 +0000 (05:41 +0000)
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 <eric.dong@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Samer El-Haj-Mahmoud <elhaj@hpe.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18917 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Include/Library/FileExplorerLib.h [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FileExplorer.c [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FileExplorer.h [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr [new file with mode: 0644]
MdeModulePkg/Library/FileExplorerLib/FormGuid.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Include/Library/FileExplorerLib.h b/MdeModulePkg/Include/Library/FileExplorerLib.h
new file mode 100644 (file)
index 0000000..fbe1fc2
--- /dev/null
@@ -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.<BR>
+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 (file)
index 0000000..4e25efc
--- /dev/null
@@ -0,0 +1,1504 @@
+/** @file
+  File explorer related functions.
+
+  Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+  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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 (file)
index 0000000..4c27ea1
--- /dev/null
@@ -0,0 +1,239 @@
+/** @file
+   File explorer lib.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+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 <PiDxe.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/FileInfo.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/FormBrowser2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+
+#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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 (file)
index 0000000..a2be614
--- /dev/null
@@ -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.<BR>
+#  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 (file)
index 0000000..4315a36
Binary files /dev/null and b/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni differ
diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr
new file mode 100644 (file)
index 0000000..ee9755f
--- /dev/null
@@ -0,0 +1,32 @@
+///** @file
+//  
+//    File Explorer Formset
+//  
+//  Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+//  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 (file)
index 0000000..d842012
--- /dev/null
@@ -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.<BR>
+  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
+
index f00d6f030ad57459fb7514add43457f3f83c97a8..5d3258d02041ecbd71648cfae6c19807496c15c7 100644 (file)
   ## @libraryclass  Provides services to get variable error flag and do platform variable cleanup.\r
   #\r
   PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h\r
+  \r
+  ## @libraryclass  Provides services to get do the file explorer.\r
+  #\r
+  FileExplorerLib|Include/Library/FileExplorerLib.h\r
 \r
   ## @libraryclass  Provides image decoding service.\r
   #\r
index 5c28fab73dccbbcb19326c887f193e3a3615fab4..7447be731ef46e95f2986b8c18bd9df54f4b456e 100644 (file)
@@ -99,6 +99,7 @@
   TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf\r
   AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf\r
   VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf\r
+  FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
 \r
 [LibraryClasses.EBC.PEIM]\r
   IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf\r
   MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf\r
   MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf\r
   MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf\r
+  MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
 \r
   MdeModulePkg/Universal/BdsDxe/BdsDxe.inf\r
   MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf\r