]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg/CommandLib: avoid NULL derefence and memory leak
[mirror_edk2.git] / ShellPkg / Library / UefiShellCommandLib / UefiShellCommandLib.c
index 28b7dda51e8b1a6560c300340469a5ab390ca335..826ced30a8c8c0e2b91be8f29ab29867808fd266 100644 (file)
@@ -1,31 +1,23 @@
 /** @file\r
   Provides interface to shell internal functions for shell commands.\r
 \r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "UefiShellCommandLib.h"\r
 \r
-/// The tag for use in identifying UNICODE files.\r
-/// If the file is UNICODE, the first 16 bits of the file will equal this value.\r
-enum {\r
-  gUnicodeFileTag = 0xFEFF\r
-};\r
-\r
 // STATIC local variables\r
 STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY  mCommandList;\r
 STATIC SCRIPT_FILE_LIST                   mScriptList;\r
 STATIC ALIAS_LIST                         mAliasList;\r
 STATIC BOOLEAN                            mEchoState;\r
 STATIC BOOLEAN                            mExitRequested;\r
+STATIC UINT64                             mExitCode;\r
 STATIC BOOLEAN                            mExitScript;\r
 STATIC CHAR16                             *mProfileList;\r
 STATIC UINTN                              mProfileListSize;\r
@@ -33,11 +25,29 @@ STATIC UINTN                              mFsMaxCount = 0;
 STATIC UINTN                              mBlkMaxCount = 0;\r
 STATIC BUFFER_LIST                        mFileHandleList;\r
 \r
+STATIC CONST CHAR8 Hex[] = {\r
+  '0',\r
+  '1',\r
+  '2',\r
+  '3',\r
+  '4',\r
+  '5',\r
+  '6',\r
+  '7',\r
+  '8',\r
+  '9',\r
+  'A',\r
+  'B',\r
+  'C',\r
+  'D',\r
+  'E',\r
+  'F'\r
+};\r
+\r
 // global variables required by library class.\r
 EFI_UNICODE_COLLATION_PROTOCOL    *gUnicodeCollation            = NULL;\r
-EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *gDevPathToText               = NULL;\r
 SHELL_MAP_LIST                    gShellMapList;\r
-SHELL_MAP_LIST                    *gShellCurDir                 = NULL;\r
+SHELL_MAP_LIST                    *gShellCurMapping             = NULL;\r
 \r
 CONST CHAR16* SupportLevel[] = {\r
   L"Minimal",\r
@@ -56,20 +66,78 @@ CommandInit(
   VOID\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  UINTN                           NumHandles;\r
+  EFI_HANDLE                      *Handles;\r
+  EFI_UNICODE_COLLATION_PROTOCOL  *Uc;\r
+  CHAR8                           *BestLanguage;\r
+  UINTN                           Index;\r
+  EFI_STATUS                      Status;\r
+  CHAR8                           *PlatformLang;\r
+\r
   if (gUnicodeCollation == NULL) {\r
-    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
-    if (EFI_ERROR(Status)) {\r
-      return (EFI_DEVICE_ERROR);\r
+\r
+    GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME, (VOID**)&PlatformLang, NULL);\r
+\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiUnicodeCollation2ProtocolGuid,\r
+                    NULL,\r
+                    &NumHandles,\r
+                    &Handles\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      NumHandles = 0;\r
+      Handles    = NULL;\r
     }\r
-  }\r
-  if (gDevPathToText == NULL) {\r
-    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDevPathToText);\r
-    if (EFI_ERROR(Status)) {\r
-      return (EFI_DEVICE_ERROR);\r
+    for (Index = 0; Index < NumHandles; Index++) {\r
+      //\r
+      // Open Unicode Collation Protocol\r
+      //\r
+      Status = gBS->OpenProtocol (\r
+                      Handles[Index],\r
+                      &gEfiUnicodeCollation2ProtocolGuid,\r
+                      (VOID **) &Uc,\r
+                      gImageHandle,\r
+                      NULL,\r
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Without clue provided use the first Unicode Collation2 protocol.\r
+      //\r
+      if (PlatformLang == NULL) {\r
+        gUnicodeCollation = Uc;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Find the best matching matching language from the supported languages\r
+      // of Unicode Collation2 protocol.\r
+      //\r
+      BestLanguage = GetBestLanguage (\r
+                       Uc->SupportedLanguages,\r
+                       FALSE,\r
+                       PlatformLang,\r
+                       NULL\r
+                       );\r
+      if (BestLanguage != NULL) {\r
+        FreePool (BestLanguage);\r
+        gUnicodeCollation = Uc;\r
+        break;\r
+      }\r
+    }\r
+    if (Handles != NULL) {\r
+      FreePool (Handles);\r
+    }\r
+    if (PlatformLang != NULL) {\r
+      FreePool (PlatformLang);\r
     }\r
   }\r
-  return (EFI_SUCCESS);\r
+\r
+  return (gUnicodeCollation == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -102,16 +170,44 @@ ShellCommandLibConstructor (
   mProfileListSize  = 0;\r
   mProfileList      = NULL;\r
 \r
-  if (gUnicodeCollation == NULL) {\r
-    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
-    if (EFI_ERROR(Status)) {\r
-      return (EFI_DEVICE_ERROR);\r
-    }\r
+  Status = CommandInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   return (RETURN_SUCCESS);\r
 }\r
 \r
+/**\r
+  Frees list of file handles.\r
+\r
+  @param[in] List     The list to free.\r
+**/\r
+VOID\r
+FreeFileHandleList (\r
+  IN BUFFER_LIST *List\r
+  )\r
+{\r
+  BUFFER_LIST               *BufferListEntry;\r
+\r
+  if (List == NULL){\r
+    return;\r
+  }\r
+  //\r
+  // enumerate through the buffer list and free all memory\r
+  //\r
+  for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
+      ; !IsListEmpty (&List->Link)\r
+      ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
+     ){\r
+    RemoveEntryList(&BufferListEntry->Link);\r
+    ASSERT(BufferListEntry->Buffer != NULL);\r
+    SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);\r
+    SHELL_FREE_NON_NULL(BufferListEntry->Buffer);\r
+    SHELL_FREE_NON_NULL(BufferListEntry);\r
+  }\r
+}\r
+\r
 /**\r
   Destructor for the library.  free any resources.\r
 \r
@@ -128,7 +224,7 @@ ShellCommandLibDestructor (
   )\r
 {\r
   SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
-  COMMAND_LIST                      *Node2;\r
+  ALIAS_LIST                        *Node2;\r
   SCRIPT_FILE_LIST                  *Node3;\r
   SHELL_MAP_LIST                    *MapNode;\r
   //\r
@@ -143,13 +239,14 @@ ShellCommandLibDestructor (
   }\r
 \r
   //\r
-  // enumerate through the init command list and free all memory\r
+  // enumerate through the alias list and free all memory\r
   //\r
   while (!IsListEmpty (&mAliasList.Link)) {\r
-    Node2 = (COMMAND_LIST *)GetFirstNode(&mAliasList.Link);\r
+    Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);\r
     RemoveEntryList(&Node2->Link);\r
     SHELL_FREE_NON_NULL(Node2->CommandString);\r
-    FreePool(Node2);\r
+    SHELL_FREE_NON_NULL(Node2->Alias);\r
+    SHELL_FREE_NON_NULL(Node2);\r
     DEBUG_CODE(Node2 = NULL;);\r
   }\r
 \r
@@ -180,7 +277,7 @@ ShellCommandLibDestructor (
     }\r
   }\r
   if (!IsListEmpty(&mFileHandleList.Link)){\r
-    FreeBufferList(&mFileHandleList);\r
+    FreeFileHandleList(&mFileHandleList);\r
   }\r
 \r
   if (mProfileList != NULL) {\r
@@ -188,21 +285,83 @@ ShellCommandLibDestructor (
   }\r
 \r
   gUnicodeCollation            = NULL;\r
-  gDevPathToText               = NULL;\r
-  gShellCurDir                 = NULL;\r
+  gShellCurMapping             = NULL;\r
 \r
   return (RETURN_SUCCESS);\r
 }\r
 \r
 /**\r
-  Checks if a command is already on the list.\r
+  Find a dynamic command protocol instance given a command name string.\r
+\r
+  @param CommandString  the command name string\r
+\r
+  @return instance      the command protocol instance, if dynamic command instance found\r
+  @retval NULL          no dynamic command protocol instance found for name\r
+**/\r
+CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *\r
+ShellCommandFindDynamicCommand (\r
+  IN CONST CHAR16 *CommandString\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          *CommandHandleList;\r
+  EFI_HANDLE                          *NextCommand;\r
+  EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *DynamicCommand;\r
+\r
+  CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);\r
+  if (CommandHandleList == NULL) {\r
+    //\r
+    // not found or out of resources\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {\r
+    Status = gBS->HandleProtocol(\r
+      *NextCommand,\r
+      &gEfiShellDynamicCommandProtocolGuid,\r
+      (VOID **)&DynamicCommand\r
+      );\r
+\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (gUnicodeCollation->StriColl(\r
+          gUnicodeCollation,\r
+          (CHAR16*)CommandString,\r
+          (CHAR16*)DynamicCommand->CommandName) == 0\r
+          ){\r
+        FreePool(CommandHandleList);\r
+        return (DynamicCommand);\r
+    }\r
+  }\r
+\r
+  FreePool(CommandHandleList);\r
+  return (NULL);\r
+}\r
+\r
+/**\r
+  Checks if a command exists as a dynamic command protocol instance\r
 \r
   @param[in] CommandString        The command string to check for on the list.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
-ShellCommandIsCommandOnList (\r
-  IN CONST  CHAR16                      *CommandString\r
+ShellCommandDynamicCommandExists (\r
+  IN CONST CHAR16 *CommandString\r
+  )\r
+{\r
+  return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));\r
+}\r
+\r
+/**\r
+  Checks if a command is already on the internal command list.\r
+\r
+  @param[in] CommandString        The command string to check for on the list.\r
+**/\r
+BOOLEAN\r
+ShellCommandIsCommandOnInternalList(\r
+  IN CONST  CHAR16 *CommandString\r
   )\r
 {\r
   SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
@@ -232,7 +391,51 @@ ShellCommandIsCommandOnList (
 }\r
 \r
 /**\r
-  Get the help text for a command.\r
+  Checks if a command exists, either internally or through the dynamic command protocol.\r
+\r
+  @param[in] CommandString        The command string to check for on the list.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ShellCommandIsCommandOnList(\r
+  IN CONST  CHAR16                      *CommandString\r
+  )\r
+{\r
+  if (ShellCommandIsCommandOnInternalList(CommandString)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return ShellCommandDynamicCommandExists(CommandString);\r
+}\r
+\r
+/**\r
+ Get the help text for a dynamic command.\r
+\r
+  @param[in] CommandString        The command name.\r
+\r
+  @retval NULL  No help text was found.\r
+  @return       String of help text. Caller required to free.\r
+**/\r
+CHAR16*\r
+ShellCommandGetDynamicCommandHelp(\r
+  IN CONST  CHAR16                      *CommandString\r
+  )\r
+{\r
+  EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *DynamicCommand;\r
+\r
+  DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *)ShellCommandFindDynamicCommand(CommandString);\r
+  if (DynamicCommand == NULL) {\r
+    return (NULL);\r
+  }\r
+\r
+  //\r
+  // TODO: how to get proper language?\r
+  //\r
+  return DynamicCommand->GetHelp(DynamicCommand, "en");\r
+}\r
+\r
+/**\r
+  Get the help text for an internal command.\r
 \r
   @param[in] CommandString        The command name.\r
 \r
@@ -240,8 +443,7 @@ ShellCommandIsCommandOnList (
   @return       String of help text. Caller reuiqred to free.\r
 **/\r
 CHAR16*\r
-EFIAPI\r
-ShellCommandGetCommandHelp (\r
+ShellCommandGetInternalCommandHelp(\r
   IN CONST  CHAR16                      *CommandString\r
   )\r
 {\r
@@ -271,6 +473,31 @@ ShellCommandGetCommandHelp (
   return (NULL);\r
 }\r
 \r
+/**\r
+  Get the help text for a command.\r
+\r
+  @param[in] CommandString        The command name.\r
+\r
+  @retval NULL  No help text was found.\r
+  @return       String of help text.Caller reuiqred to free.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+ShellCommandGetCommandHelp (\r
+  IN CONST  CHAR16                      *CommandString\r
+  )\r
+{\r
+  CHAR16      *HelpStr;\r
+  HelpStr = ShellCommandGetInternalCommandHelp(CommandString);\r
+\r
+  if (HelpStr == NULL) {\r
+    HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);\r
+  }\r
+\r
+  return HelpStr;\r
+}\r
+\r
+\r
 /**\r
   Registers handlers of type SHELL_RUN_COMMAND and\r
   SHELL_GET_MAN_FILENAME for each shell command.\r
@@ -332,6 +559,16 @@ ShellCommandRegisterCommandName (
   )\r
 {\r
   SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
+  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;\r
+  SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;\r
+  INTN LexicalMatchValue;\r
+\r
+  //\r
+  // Initialize local variables.\r
+  //\r
+  Command = NULL;\r
+  PrevCommand = NULL;\r
+  LexicalMatchValue = 0;\r
 \r
   //\r
   // ASSERTs for NULL parameters\r
@@ -359,14 +596,14 @@ ShellCommandRegisterCommandName (
   // allocate memory for new struct\r
   //\r
   Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));\r
-  ASSERT(Node != NULL);\r
-  Node->CommandString = AllocateZeroPool(StrSize(CommandString));\r
-  ASSERT(Node->CommandString != NULL);\r
-\r
-  //\r
-  // populate the new struct\r
-  //\r
-  StrCpy(Node->CommandString, CommandString);\r
+  if (Node == NULL) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+  Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);\r
+  if (Node->CommandString == NULL) {\r
+    FreePool (Node);\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
 \r
   Node->GetManFileName  = GetManFileName;\r
   Node->CommandHandler  = CommandHandler;\r
@@ -390,9 +627,40 @@ ShellCommandRegisterCommandName (
   }\r
 \r
   //\r
-  // add the new struct to the list\r
+  // Insert a new entry on top of the list\r
+  //\r
+  InsertHeadList (&mCommandList.Link, &Node->Link);\r
+\r
+  //\r
+  // Move a new registered command to its sorted ordered location in the list\r
   //\r
-  InsertTailList (&mCommandList.Link, &Node->Link);\r
+  for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),\r
+        PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)\r
+        ; !IsNull (&mCommandList.Link, &Command->Link)\r
+        ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {\r
+\r
+    //\r
+    // Get Lexical Comparison Value between PrevCommand and Command list entry\r
+    //\r
+    LexicalMatchValue = gUnicodeCollation->StriColl (\r
+                                             gUnicodeCollation,\r
+                                             PrevCommand->CommandString,\r
+                                             Command->CommandString\r
+                                             );\r
+\r
+    //\r
+    // Swap PrevCommand and Command list entry if PrevCommand list entry\r
+    // is alphabetically greater than Command list entry\r
+    //\r
+    if (LexicalMatchValue > 0){\r
+      Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);\r
+    } else if (LexicalMatchValue < 0) {\r
+      //\r
+      // PrevCommand entry is lexically lower than Command entry\r
+      //\r
+      break;\r
+    }\r
+  }\r
 \r
   return (RETURN_SUCCESS);\r
 }\r
@@ -424,12 +692,12 @@ ShellCommandGetProfileList (
   information will be returned. If Sections is NULL, then all help text information\r
   available will be returned.\r
 \r
-  @param[in]  CommandString         Pointer to the command name.  This is the name\r
-                                    found on the command line in the shell.\r
-  @param[in,out] RetVal             Pointer to the return vaule from the command handler.\r
+  @param[in]  CommandString          Pointer to the command name.  This is the name\r
+                                     found on the command line in the shell.\r
+  @param[in, out] RetVal             Pointer to the return vaule from the command handler.\r
 \r
-  @param[in,out]  CanAffectLE       indicates whether this command's return value\r
-                                    needs to be placed into LASTERROR environment variable.\r
+  @param[in, out]  CanAffectLE       indicates whether this command's return value\r
+                                     needs to be placed into LASTERROR environment variable.\r
 \r
   @retval RETURN_SUCCESS            The handler was run.\r
   @retval RETURN_NOT_FOUND          The CommandString did not match a registered\r
@@ -444,7 +712,8 @@ ShellCommandRunCommandHandler (
   IN OUT BOOLEAN                *CanAffectLE OPTIONAL\r
   )\r
 {\r
-  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
+  SHELL_COMMAND_INTERNAL_LIST_ENTRY   *Node;\r
+  EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *DynamicCommand;\r
 \r
   //\r
   // assert for NULL parameters\r
@@ -463,7 +732,7 @@ ShellCommandRunCommandHandler (
           gUnicodeCollation,\r
           (CHAR16*)CommandString,\r
           Node->CommandString) == 0\r
-       ){\r
+      ){\r
       if (CanAffectLE != NULL) {\r
         *CanAffectLE = Node->LastError;\r
       }\r
@@ -475,6 +744,20 @@ ShellCommandRunCommandHandler (
       return (RETURN_SUCCESS);\r
     }\r
   }\r
+\r
+  //\r
+  // An internal command was not found, try to find a dynamic command\r
+  //\r
+  DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *)ShellCommandFindDynamicCommand(CommandString);\r
+  if (DynamicCommand != NULL) {\r
+    if (RetVal != NULL) {\r
+      *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
+    } else {\r
+      DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
+    }\r
+    return (RETURN_SUCCESS);\r
+  }\r
+\r
   return (RETURN_NOT_FOUND);\r
 }\r
 \r
@@ -565,6 +848,9 @@ ShellCommandRegisterAlias (
   )\r
 {\r
   ALIAS_LIST *Node;\r
+  ALIAS_LIST *CommandAlias;\r
+  ALIAS_LIST *PrevCommandAlias;\r
+  INTN       LexicalMatchValue;\r
 \r
   //\r
   // Asserts for NULL\r
@@ -576,22 +862,52 @@ ShellCommandRegisterAlias (
   // allocate memory for new struct\r
   //\r
   Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
-  ASSERT(Node != NULL);\r
-  Node->CommandString = AllocateZeroPool(StrSize(Command));\r
-  Node->Alias = AllocateZeroPool(StrSize(Alias));\r
-  ASSERT(Node->CommandString != NULL);\r
-  ASSERT(Node->Alias != NULL);\r
+  if (Node == NULL) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+  Node->CommandString = AllocateCopyPool(StrSize(Command), Command);\r
+  if (Node->CommandString == NULL) {\r
+    FreePool (Node);\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+  Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);\r
+  if (Node->Alias == NULL) {\r
+    FreePool (Node->CommandString);\r
+    FreePool (Node);\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
 \r
-  //\r
-  // populate the new struct\r
-  //\r
-  StrCpy(Node->CommandString, Command);\r
-  StrCpy(Node->Alias        , Alias );\r
+  InsertHeadList (&mAliasList.Link, &Node->Link);\r
 \r
   //\r
-  // add the new struct to the list\r
+  // Move a new pre-defined registered alias to its sorted ordered location in the list\r
   //\r
-  InsertTailList (&mAliasList.Link, &Node->Link);\r
+  for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),\r
+         PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)\r
+       ; !IsNull (&mAliasList.Link, &CommandAlias->Link)\r
+       ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {\r
+    //\r
+    // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry\r
+    //\r
+    LexicalMatchValue = gUnicodeCollation->StriColl (\r
+                                             gUnicodeCollation,\r
+                                             PrevCommandAlias->Alias,\r
+                                             CommandAlias->Alias\r
+                                             );\r
+\r
+    //\r
+    // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry\r
+    // is alphabetically greater than CommandAlias list entry\r
+    //\r
+    if (LexicalMatchValue > 0) {\r
+      CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);\r
+    } else if (LexicalMatchValue < 0) {\r
+      //\r
+      // PrevCommandAlias entry is lexically lower than CommandAlias entry\r
+      //\r
+      break;\r
+    }\r
+  }\r
 \r
   return (RETURN_SUCCESS);\r
 }\r
@@ -661,7 +977,7 @@ ShellCommandIsOnAliasList(
 }\r
 \r
 /**\r
-  Function to determine current state of ECHO.  Echo determins if lines from scripts\r
+  Function to determine current state of ECHO.  Echo determines if lines from scripts\r
   and ECHO commands are enabled.\r
 \r
   @retval TRUE    Echo is currently enabled\r
@@ -677,7 +993,7 @@ ShellCommandGetEchoState(
 }\r
 \r
 /**\r
-  Function to set current state of ECHO.  Echo determins if lines from scripts\r
+  Function to set current state of ECHO.  Echo determines if lines from scripts\r
   and ECHO commands are enabled.\r
 \r
   If State is TRUE, Echo will be enabled.\r
@@ -697,12 +1013,14 @@ ShellCommandSetEchoState(
 /**\r
   Indicate that the current shell or script should exit.\r
 \r
-  @param[in] ScriptOnly   TRUE if only exiting a script, FALSE othrwise.\r
+  @param[in] ScriptOnly   TRUE if exiting a script; FALSE otherwise.\r
+  @param[in] ErrorCode    The 64 bit error code to return.\r
 **/\r
 VOID\r
 EFIAPI\r
 ShellCommandRegisterExit (\r
-  IN BOOLEAN ScriptOnly\r
+  IN BOOLEAN      ScriptOnly,\r
+  IN CONST UINT64 ErrorCode\r
   )\r
 {\r
   mExitRequested = (BOOLEAN)(!mExitRequested);\r
@@ -711,6 +1029,7 @@ ShellCommandRegisterExit (
   } else {\r
     mExitScript    = FALSE;\r
   }\r
+  mExitCode = ErrorCode;\r
 }\r
 \r
 /**\r
@@ -728,6 +1047,21 @@ ShellCommandGetExit (
   return (mExitRequested);\r
 }\r
 \r
+/**\r
+  Retrieve the Exit code.\r
+\r
+  If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
+\r
+  @return the value passed into RegisterExit.\r
+**/\r
+UINT64\r
+EFIAPI\r
+ShellCommandGetExitCode (\r
+  VOID\r
+  )\r
+{\r
+  return (mExitCode);\r
+}\r
 /**\r
   Retrieve the Exit script indicator.\r
 \r
@@ -916,12 +1250,11 @@ ShellCommandAddMapItemAndUpdatePath(
     Status = EFI_OUT_OF_RESOURCES;\r
   } else {\r
     MapListNode->Flags = Flags;\r
-    MapListNode->MapName = AllocateZeroPool(StrSize(Name));\r
+    MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);\r
     MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
     if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
       Status = EFI_OUT_OF_RESOURCES;\r
     } else {\r
-      StrCpy(MapListNode->MapName, Name);\r
       InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
     }\r
   }\r
@@ -944,10 +1277,8 @@ ShellCommandAddMapItemAndUpdatePath(
     ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
     if (OriginalPath != NULL) {\r
       StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
-    } else {\r
-      StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);\r
+      StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
     }\r
-    StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
     StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
     StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
     StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
@@ -993,7 +1324,14 @@ ShellCommandCreateInitialMappingsAndPaths(
   CHAR16                    *NewConsistName;\r
   EFI_DEVICE_PATH_PROTOCOL  **ConsistMappingTable;\r
   SHELL_MAP_LIST            *MapListNode;\r
-\r
+  CONST CHAR16              *CurDir;\r
+  CHAR16                    *SplitCurDir;\r
+  CHAR16                    *MapName;\r
+  SHELL_MAP_LIST            *MapListItem;\r
+\r
+  SplitCurDir = NULL;\r
+  MapName     = NULL;\r
+  MapListItem = NULL;\r
   HandleList  = NULL;\r
 \r
   //\r
@@ -1013,6 +1351,9 @@ ShellCommandCreateInitialMappingsAndPaths(
         ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
        ){\r
           RemoveEntryList(&MapListNode->Link);\r
+          SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
+          SHELL_FREE_NON_NULL(MapListNode->MapName);\r
+          SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
           FreePool(MapListNode);\r
     } // for loop\r
   }\r
@@ -1031,7 +1372,10 @@ ShellCommandCreateInitialMappingsAndPaths(
     // Get all Device Paths\r
     //\r
     DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
-    ASSERT(DevicePathList != NULL);\r
+    if (DevicePathList == NULL) {\r
+      SHELL_FREE_NON_NULL (HandleList);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
     for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
       DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
@@ -1073,6 +1417,33 @@ ShellCommandCreateInitialMappingsAndPaths(
     SHELL_FREE_NON_NULL(DevicePathList);\r
 \r
     HandleList = NULL;\r
+\r
+    //\r
+    //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,\r
+    //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,\r
+    //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.\r
+    //\r
+    if (gShellCurMapping != NULL) {\r
+      gShellCurMapping = NULL;\r
+      CurDir = gEfiShellProtocol->GetEnv(L"cwd");\r
+      if (CurDir != NULL) {\r
+        MapName = AllocateCopyPool (StrSize(CurDir), CurDir);\r
+        if (MapName == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        SplitCurDir = StrStr (MapName, L":");\r
+        if (SplitCurDir == NULL) {\r
+          SHELL_FREE_NON_NULL (MapName);\r
+          return EFI_UNSUPPORTED;\r
+        }\r
+        *(SplitCurDir + 1) = CHAR_NULL;\r
+        MapListItem = ShellCommandFindMapItem (MapName);\r
+        if (MapListItem != NULL) {\r
+          gShellCurMapping = MapListItem;\r
+        }\r
+        SHELL_FREE_NON_NULL (MapName);\r
+      }\r
+    }\r
   } else {\r
     Count = (UINTN)-1;\r
   }\r
@@ -1088,7 +1459,10 @@ ShellCommandCreateInitialMappingsAndPaths(
     // Get all Device Paths\r
     //\r
     DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
-    ASSERT(DevicePathList != NULL);\r
+    if (DevicePathList == NULL) {\r
+      SHELL_FREE_NON_NULL (HandleList);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
     for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
       DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
@@ -1122,6 +1496,113 @@ ShellCommandCreateInitialMappingsAndPaths(
   return (EFI_SUCCESS);\r
 }\r
 \r
+/**\r
+  Add mappings for any devices without one.  Do not change any existing maps.\r
+\r
+  @retval EFI_SUCCESS   The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellCommandUpdateMapping (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                *HandleList;\r
+  UINTN                     Count;\r
+  EFI_DEVICE_PATH_PROTOCOL  **DevicePathList;\r
+  CHAR16                    *NewDefaultName;\r
+  CHAR16                    *NewConsistName;\r
+  EFI_DEVICE_PATH_PROTOCOL  **ConsistMappingTable;\r
+\r
+  HandleList  = NULL;\r
+  Status      = EFI_SUCCESS;\r
+\r
+  //\r
+  // remove mappings that represent removed devices.\r
+  //\r
+\r
+  //\r
+  // Find each handle with Simple File System\r
+  //\r
+  HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
+  if (HandleList != NULL) {\r
+    //\r
+    // Do a count of the handles\r
+    //\r
+    for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
+\r
+    //\r
+    // Get all Device Paths\r
+    //\r
+    DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
+    if (DevicePathList == NULL) {\r
+      return (EFI_OUT_OF_RESOURCES);\r
+    }\r
+\r
+    for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
+      DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
+    }\r
+\r
+    //\r
+    // Sort all DevicePaths\r
+    //\r
+    PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
+\r
+    ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
+\r
+    //\r
+    // Assign new Mappings to remainders\r
+    //\r
+    for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {\r
+      //\r
+      // Skip ones that already have\r
+      //\r
+      if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {\r
+        continue;\r
+      }\r
+      //\r
+      // Get default name\r
+      //\r
+      NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
+      if (NewDefaultName == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Call shell protocol SetMap function now...\r
+      //\r
+      Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);\r
+\r
+      if (!EFI_ERROR(Status)) {\r
+        //\r
+        // Now do consistent name\r
+        //\r
+        NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
+        if (NewConsistName != NULL) {\r
+          Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);\r
+          FreePool(NewConsistName);\r
+        }\r
+      }\r
+\r
+      FreePool(NewDefaultName);\r
+    }\r
+    ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
+    SHELL_FREE_NON_NULL(HandleList);\r
+    SHELL_FREE_NON_NULL(DevicePathList);\r
+\r
+    HandleList = NULL;\r
+  } else {\r
+    Count = (UINTN)-1;\r
+  }\r
+  //\r
+  // Do it all over again for gEfiBlockIoProtocolGuid\r
+  //\r
+\r
+  return (Status);\r
+}\r
+\r
 /**\r
   Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
 \r
@@ -1164,11 +1645,14 @@ ConvertEfiFileProtocolToShellHandle(
     }\r
     NewNode             = AllocateZeroPool(sizeof(BUFFER_LIST));\r
     if (NewNode == NULL) {\r
+      SHELL_FREE_NON_NULL(Buffer);\r
       return (NULL);\r
     }\r
     Buffer->FileHandle  = (EFI_FILE_PROTOCOL*)Handle;\r
     Buffer->Path        = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
     if (Buffer->Path == NULL) {\r
+      SHELL_FREE_NON_NULL(NewNode);\r
+      SHELL_FREE_NON_NULL(Buffer);\r
       return (NULL);\r
     }\r
     NewNode->Buffer     = Buffer;\r
@@ -1264,7 +1748,6 @@ ShellFileHandleEof(
 \r
   gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
   Info = gEfiShellProtocol->GetFileInfo (Handle);\r
-  ASSERT(Info != NULL);\r
   gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
 \r
   if (Info == NULL) {\r
@@ -1283,185 +1766,142 @@ ShellFileHandleEof(
 }\r
 \r
 /**\r
-  Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned\r
-  buffer.  The returned buffer must be callee freed.\r
-\r
-  If the position upon start is 0, then the Ascii Boolean will be set.  This should be\r
-  maintained and not changed for all operations with the same file.\r
-\r
-  @param[in]      Handle        SHELL_FILE_HANDLE to read from.\r
-  @param[in,out]  Ascii         Boolean value for indicating whether the file is\r
-                                Ascii (TRUE) or UCS2 (FALSE).\r
-\r
-  @return                       The line of text from the file.\r
+  Frees any BUFFER_LIST defined type.\r
 \r
-  @sa ShellFileHandleReadLine\r
+  @param[in] List     The BUFFER_LIST object to free.\r
 **/\r
-CHAR16*\r
+VOID\r
 EFIAPI\r
-ShellFileHandleReturnLine(\r
-  IN SHELL_FILE_HANDLE            Handle,\r
-  IN OUT BOOLEAN                *Ascii\r
+FreeBufferList (\r
+  IN BUFFER_LIST *List\r
   )\r
 {\r
-  CHAR16          *RetVal;\r
-  UINTN           Size;\r
-  EFI_STATUS      Status;\r
-\r
-  Size = 0;\r
-  RetVal = NULL;\r
+  BUFFER_LIST               *BufferListEntry;\r
 \r
-  Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);\r
-  if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    RetVal = AllocateZeroPool(Size);\r
-    Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);\r
+  if (List == NULL){\r
+    return;\r
   }\r
-  ASSERT_EFI_ERROR(Status);\r
-  if (EFI_ERROR(Status) && (RetVal != NULL)) {\r
-    FreePool(RetVal);\r
-    RetVal = NULL;\r
+  //\r
+  // enumerate through the buffer list and free all memory\r
+  //\r
+  for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
+      ; !IsListEmpty (&List->Link)\r
+      ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
+     ){\r
+    RemoveEntryList(&BufferListEntry->Link);\r
+    if (BufferListEntry->Buffer != NULL) {\r
+      FreePool(BufferListEntry->Buffer);\r
+    }\r
+    FreePool(BufferListEntry);\r
   }\r
-  return (RetVal);\r
 }\r
 \r
 /**\r
-  Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.\r
-\r
-  If the position upon start is 0, then the Ascii Boolean will be set.  This should be\r
-  maintained and not changed for all operations with the same file.\r
-\r
-  @param[in]      Handle        SHELL_FILE_HANDLE to read from.\r
-  @param[in,out]  Buffer        The pointer to buffer to read into.\r
-  @param[in,out]  Size          The pointer to number of bytes in Buffer.\r
-  @param[in]      Truncate      If the buffer is large enough, this has no effect.\r
-                                If the buffer is is too small and Truncate is TRUE,\r
-                                the line will be truncated.\r
-                                If the buffer is is too small and Truncate is FALSE,\r
-                                then no read will occur.\r
-\r
-  @param[in,out]  Ascii         Boolean value for indicating whether the file is\r
-                                Ascii (TRUE) or UCS2 (FALSE).\r
-\r
-  @retval EFI_SUCCESS           The operation was successful.  The line is stored in\r
-                                Buffer.\r
-  @retval EFI_INVALID_PARAMETER Handle was NULL.\r
-  @retval EFI_INVALID_PARAMETER Size was NULL.\r
-  @retval EFI_BUFFER_TOO_SMALL  Size was not large enough to store the line.\r
-                                Size was updated to the minimum space required.\r
-  @sa ShellFileHandleRead\r
+  Dump some hexadecimal data to the screen.\r
+\r
+  @param[in] Indent     How many spaces to indent the output.\r
+  @param[in] Offset     The offset of the printing.\r
+  @param[in] DataSize   The size in bytes of UserData.\r
+  @param[in] UserData   The data to print out.\r
 **/\r
-EFI_STATUS\r
+VOID\r
 EFIAPI\r
-ShellFileHandleReadLine(\r
-  IN SHELL_FILE_HANDLE          Handle,\r
-  IN OUT CHAR16                 *Buffer,\r
-  IN OUT UINTN                  *Size,\r
-  IN BOOLEAN                    Truncate,\r
-  IN OUT BOOLEAN                *Ascii\r
+DumpHex (\r
+  IN UINTN        Indent,\r
+  IN UINTN        Offset,\r
+  IN UINTN        DataSize,\r
+  IN VOID         *UserData\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  CHAR16      CharBuffer;\r
-  UINTN       CharSize;\r
-  UINTN       CountSoFar;\r
-  UINT64      OriginalFilePosition;\r
+  UINT8 *Data;\r
 \r
+  CHAR8 Val[50];\r
 \r
-  if (Handle == NULL\r
-    ||Size   == NULL\r
-   ){\r
-    return (EFI_INVALID_PARAMETER);\r
-  }\r
-  if (Buffer == NULL) {\r
-    ASSERT(*Size == 0);\r
-  } else {\r
-    *Buffer = CHAR_NULL;\r
-  }\r
-  gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);\r
-  if (OriginalFilePosition == 0) {\r
-    CharSize = sizeof(CHAR16);\r
-    Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);\r
-    ASSERT_EFI_ERROR(Status);\r
-    if (CharBuffer == gUnicodeFileTag) {\r
-      *Ascii = FALSE;\r
-    } else {\r
-      *Ascii = TRUE;\r
-      gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
-    }\r
-  }\r
+  CHAR8 Str[20];\r
 \r
-  for (CountSoFar = 0;;CountSoFar++){\r
-    CharBuffer = 0;\r
-    if (*Ascii) {\r
-      CharSize = sizeof(CHAR8);\r
-    } else {\r
-      CharSize = sizeof(CHAR16);\r
-    }\r
-    Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);\r
-    if (  EFI_ERROR(Status)\r
-       || CharSize == 0\r
-       || (CharBuffer == L'\n' && !(*Ascii))\r
-       || (CharBuffer ==  '\n' && *Ascii)\r
-     ){\r
-      break;\r
-    }\r
-    //\r
-    // if we have space save it...\r
-    //\r
-    if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
-      ASSERT(Buffer != NULL);\r
-      ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
-      ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
+  UINT8 TempByte;\r
+  UINTN Size;\r
+  UINTN Index;\r
+\r
+  Data = UserData;\r
+  while (DataSize != 0) {\r
+    Size = 16;\r
+    if (Size > DataSize) {\r
+      Size = DataSize;\r
     }\r
-  }\r
 \r
-  //\r
-  // if we ran out of space tell when...\r
-  //\r
-  if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
-    *Size = (CountSoFar+1)*sizeof(CHAR16);\r
-    if (!Truncate) {\r
-      gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
-    } else {\r
-      DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
+    for (Index = 0; Index < Size; Index += 1) {\r
+      TempByte            = Data[Index];\r
+      Val[Index * 3 + 0]  = Hex[TempByte >> 4];\r
+      Val[Index * 3 + 1]  = Hex[TempByte & 0xF];\r
+      Val[Index * 3 + 2]  = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+      Str[Index]          = (CHAR8) ((TempByte < ' ' || TempByte > '~') ? '.' : TempByte);\r
     }\r
-    return (EFI_BUFFER_TOO_SMALL);\r
-  }\r
-  while(Buffer[StrLen(Buffer)-1] == L'\r') {\r
-    Buffer[StrLen(Buffer)-1] = CHAR_NULL;\r
-  }\r
 \r
-  return (Status);\r
+    Val[Index * 3]  = 0;\r
+    Str[Index]      = 0;\r
+    ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
+\r
+    Data += Size;\r
+    Offset += Size;\r
+    DataSize -= Size;\r
+  }\r
 }\r
+\r
 /**\r
-  Frees any BUFFER_LIST defined type.\r
+  Dump HEX data into buffer.\r
 \r
-  @param[in] List     The BUFFER_LIST object to free.\r
+  @param[in] Buffer     HEX data to be dumped in Buffer.\r
+  @param[in] Indent     How many spaces to indent the output.\r
+  @param[in] Offset     The offset of the printing.\r
+  @param[in] DataSize   The size in bytes of UserData.\r
+  @param[in] UserData   The data to print out.\r
 **/\r
-VOID\r
+CHAR16*\r
 EFIAPI\r
-FreeBufferList (\r
-  IN BUFFER_LIST *List\r
+CatSDumpHex (\r
+  IN CHAR16  *Buffer,\r
+  IN UINTN   Indent,\r
+  IN UINTN   Offset,\r
+  IN UINTN   DataSize,\r
+  IN VOID    *UserData\r
   )\r
 {\r
-  BUFFER_LIST               *BufferListEntry;\r
+  UINT8   *Data;\r
+  UINT8   TempByte;\r
+  UINTN   Size;\r
+  UINTN   Index;\r
+  CHAR8   Val[50];\r
+  CHAR8   Str[20];\r
+  CHAR16  *RetVal;\r
+  CHAR16  *TempRetVal;\r
+\r
+  Data = UserData;\r
+  RetVal = Buffer;\r
+  while (DataSize != 0) {\r
+    Size = 16;\r
+    if (Size > DataSize) {\r
+      Size = DataSize;\r
+    }\r
 \r
-  if (List == NULL){\r
-    return;\r
-  }\r
-  //\r
-  // enumerate through the buffer list and free all memory\r
-  //\r
-  for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
-      ; !IsListEmpty (&List->Link)\r
-      ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
-     ){\r
-    RemoveEntryList(&BufferListEntry->Link);\r
-    ASSERT(BufferListEntry->Buffer != NULL);\r
-    if (BufferListEntry->Buffer != NULL) {\r
-      FreePool(BufferListEntry->Buffer);\r
+    for (Index = 0; Index < Size; Index += 1) {\r
+      TempByte            = Data[Index];\r
+      Val[Index * 3 + 0]  = Hex[TempByte >> 4];\r
+      Val[Index * 3 + 1]  = Hex[TempByte & 0xF];\r
+      Val[Index * 3 + 2]  = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+      Str[Index]          = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
     }\r
-    FreePool(BufferListEntry);\r
+\r
+    Val[Index * 3]  = 0;\r
+    Str[Index]      = 0;\r
+    TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
+    SHELL_FREE_NON_NULL (RetVal);\r
+    RetVal = TempRetVal;\r
+\r
+    Data += Size;\r
+    Offset += Size;\r
+    DataSize -= Size;\r
   }\r
-}\r
 \r
+  return RetVal;\r
+}\r