Home | History | Annotate | Download | only in UefiShellBcfgCommandLib
      1 /** @file
      2   Main file for BCFG command.
      3 
      4   (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include <Uefi.h>
     18 #include <ShellBase.h>
     19 
     20 #include <Guid/GlobalVariable.h>
     21 #include <Guid/ShellLibHiiGuid.h>
     22 
     23 #include <Protocol/EfiShell.h>
     24 #include <Protocol/EfiShellParameters.h>
     25 #include <Protocol/DevicePath.h>
     26 #include <Protocol/LoadedImage.h>
     27 #include <Protocol/UnicodeCollation.h>
     28 
     29 #include <Library/BaseLib.h>
     30 #include <Library/BaseMemoryLib.h>
     31 #include <Library/DebugLib.h>
     32 #include <Library/MemoryAllocationLib.h>
     33 #include <Library/PcdLib.h>
     34 #include <Library/ShellCommandLib.h>
     35 #include <Library/ShellLib.h>
     36 #include <Library/SortLib.h>
     37 #include <Library/UefiLib.h>
     38 #include <Library/UefiRuntimeServicesTableLib.h>
     39 #include <Library/UefiBootServicesTableLib.h>
     40 #include <Library/HiiLib.h>
     41 #include <Library/FileHandleLib.h>
     42 #include <Library/PrintLib.h>
     43 #include <Library/HandleParsingLib.h>
     44 #include <Library/DevicePathLib.h>
     45 
     46 STATIC CONST CHAR16 mFileName[] = L"ShellCommands";
     47 STATIC EFI_HANDLE gShellBcfgHiiHandle  = NULL;
     48 
     49 typedef enum {
     50   BcfgTargetBootOrder    = 0,
     51   BcfgTargetDriverOrder  = 1,
     52   BcfgTargetMax          = 2
     53 } BCFG_OPERATION_TARGET;
     54 
     55 typedef enum {
     56   BcfgTypeDump       = 0,
     57   BcfgTypeAdd        = 1,
     58   BcfgTypeAddp       = 2,
     59   BcfgTypeAddh       = 3,
     60   BcfgTypeRm         = 4,
     61   BcfgTypeMv         = 5,
     62   BcfgTypeOpt        = 6,
     63   BcfgTypeMax        = 7
     64 } BCFG_OPERATION_TYPE;
     65 
     66 typedef struct {
     67   BCFG_OPERATION_TARGET Target;
     68   BCFG_OPERATION_TYPE   Type;
     69   UINT16                Number1;
     70   UINT16                Number2;
     71   UINTN                 HandleIndex;
     72   CHAR16                *FileName;
     73   CHAR16                *Description;
     74   UINT16                *Order;
     75   CONST CHAR16          *OptData;
     76 } BGFG_OPERATION;
     77 
     78 /**
     79   Update the optional data for a boot or driver option.
     80 
     81   If optional data exists it will be changed.
     82 
     83   @param[in]      Index     The boot or driver option index update.
     84   @param[in]      DataSize  The size in bytes of Data.
     85   @param[in]      Data      The buffer for the optioanl data.
     86   @param[in]      Target    The target of the operation.
     87 
     88   @retval EFI_SUCCESS       The data was sucessfully updated.
     89   @retval other             A error occured.
     90 **/
     91 EFI_STATUS
     92 EFIAPI
     93 UpdateOptionalData(
     94   UINT16                          Index,
     95   UINTN                           DataSize,
     96   UINT8                           *Data,
     97   IN CONST BCFG_OPERATION_TARGET  Target
     98   )
     99 {
    100   EFI_STATUS  Status;
    101   CHAR16      VariableName[12];
    102   UINTN       OriginalSize;
    103   UINT8       *OriginalData;
    104   UINTN       NewSize;
    105   UINT8       *NewData;
    106   UINTN       OriginalOptionDataSize;
    107 
    108   UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", Index);
    109 
    110   OriginalSize = 0;
    111   OriginalData = NULL;
    112   NewData      = NULL;
    113   NewSize      = 0;
    114 
    115   Status = gRT->GetVariable(
    116       VariableName,
    117       (EFI_GUID*)&gEfiGlobalVariableGuid,
    118       NULL,
    119       &OriginalSize,
    120       OriginalData);
    121   if (Status == EFI_BUFFER_TOO_SMALL) {
    122     OriginalData = AllocateZeroPool(OriginalSize);
    123     if (OriginalData == NULL) {
    124       return (EFI_OUT_OF_RESOURCES);
    125     }
    126     Status = gRT->GetVariable(
    127         VariableName,
    128         (EFI_GUID*)&gEfiGlobalVariableGuid,
    129         NULL,
    130         &OriginalSize,
    131         OriginalData);
    132   }
    133 
    134   if (!EFI_ERROR(Status)) {
    135     //
    136     // Allocate new struct and discard old optional data.
    137     //
    138     ASSERT (OriginalData != NULL);
    139     OriginalOptionDataSize  = sizeof(UINT32) + sizeof(UINT16) + StrSize(((CHAR16*)(OriginalData + sizeof(UINT32) + sizeof(UINT16))));
    140     OriginalOptionDataSize += (*(UINT16*)(OriginalData + sizeof(UINT32)));
    141     OriginalOptionDataSize -= OriginalSize;
    142     NewSize = OriginalSize - OriginalOptionDataSize + DataSize;
    143     NewData = AllocateCopyPool(NewSize, OriginalData);
    144     if (NewData == NULL) {
    145       Status = EFI_OUT_OF_RESOURCES;
    146     } else {
    147       CopyMem(NewData + OriginalSize - OriginalOptionDataSize, Data, DataSize);
    148     }
    149   }
    150 
    151   if (!EFI_ERROR(Status)) {
    152     //
    153     // put the data back under the variable
    154     //
    155     Status = gRT->SetVariable(
    156       VariableName,
    157       (EFI_GUID*)&gEfiGlobalVariableGuid,
    158       EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    159       NewSize,
    160       NewData);
    161   }
    162 
    163   SHELL_FREE_NON_NULL(OriginalData);
    164   SHELL_FREE_NON_NULL(NewData);
    165   return (Status);
    166 }
    167 
    168 /**
    169   This function will get a CRC for a boot option.
    170 
    171   @param[in, out] Crc         The CRC value to return.
    172   @param[in]      BootIndex   The boot option index to CRC.
    173 
    174   @retval EFI_SUCCESS           The CRC was sucessfully returned.
    175   @retval other                 A error occured.
    176 **/
    177 EFI_STATUS
    178 EFIAPI
    179 GetBootOptionCrc(
    180   UINT32      *Crc,
    181   UINT16      BootIndex
    182   )
    183 {
    184   CHAR16      VariableName[12];
    185   EFI_STATUS  Status;
    186   UINT8       *Buffer;
    187   UINTN       BufferSize;
    188 
    189   Buffer      = NULL;
    190   BufferSize  = 0;
    191 
    192   //
    193   // Get the data Buffer
    194   //
    195   UnicodeSPrint(VariableName, sizeof(VariableName), L"%Boot%04x", BootIndex);
    196   Status = gRT->GetVariable(
    197       VariableName,
    198       (EFI_GUID*)&gEfiGlobalVariableGuid,
    199       NULL,
    200       &BufferSize,
    201       NULL);
    202   if (Status == EFI_BUFFER_TOO_SMALL) {
    203     Buffer = AllocateZeroPool(BufferSize);
    204     Status = gRT->GetVariable(
    205         VariableName,
    206         (EFI_GUID*)&gEfiGlobalVariableGuid,
    207         NULL,
    208         &BufferSize,
    209         Buffer);
    210   }
    211 
    212   //
    213   // Get the CRC computed
    214   //
    215   if (!EFI_ERROR(Status)) {
    216     Status = gBS->CalculateCrc32 (Buffer, BufferSize, Crc);
    217   }
    218 
    219   SHELL_FREE_NON_NULL(Buffer);
    220   return EFI_SUCCESS;
    221 }
    222 
    223 /**
    224   This function will populate the device path protocol parameter based on TheHandle.
    225 
    226   @param[in]      TheHandle     Driver handle.
    227   @param[in, out] FilePath      On a sucessful return the device path to the handle.
    228 
    229   @retval EFI_SUCCESS           The device path was sucessfully returned.
    230   @retval other                 A error from gBS->HandleProtocol.
    231 
    232   @sa HandleProtocol
    233 **/
    234 EFI_STATUS
    235 EFIAPI
    236 GetDevicePathForDriverHandle (
    237   IN EFI_HANDLE                   TheHandle,
    238   IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath
    239   )
    240 {
    241   EFI_STATUS                Status;
    242   EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
    243   EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath;
    244 
    245   Status = gBS->OpenProtocol (
    246                 TheHandle,
    247                 &gEfiLoadedImageProtocolGuid,
    248                 (VOID**)&LoadedImage,
    249                 gImageHandle,
    250                 NULL,
    251                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
    252                );
    253   if (!EFI_ERROR (Status)) {
    254     Status = gBS->OpenProtocol (
    255                   LoadedImage->DeviceHandle,
    256                   &gEfiDevicePathProtocolGuid,
    257                   (VOID**)&ImageDevicePath,
    258                   gImageHandle,
    259                   NULL,
    260                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    261                  );
    262     if (!EFI_ERROR (Status)) {
    263 //      *DevPath  = DuplicateDevicePath (ImageDevicePath);
    264 //      *FilePath = DuplicateDevicePath (LoadedImage->FilePath);
    265         *FilePath = AppendDevicePath(ImageDevicePath,LoadedImage->FilePath);
    266       gBS->CloseProtocol(
    267                   LoadedImage->DeviceHandle,
    268                   &gEfiDevicePathProtocolGuid,
    269                   gImageHandle,
    270                   NULL);
    271     }
    272     gBS->CloseProtocol(
    273                 TheHandle,
    274                 &gEfiLoadedImageProtocolGuid,
    275                 gImageHandle,
    276                 NULL);
    277   }
    278   return (Status);
    279 }
    280 
    281 /**
    282   Function to add a option.
    283 
    284   @param[in] Position       The position to add Target at.
    285   @param[in] File           The file to make the target.
    286   @param[in] Desc           The description text.
    287   @param[in] CurrentOrder   The pointer to the current order of items.
    288   @param[in] OrderCount     The number if items in CurrentOrder.
    289   @param[in] Target         The info on the option to add.
    290   @param[in] UseHandle      TRUE to use HandleNumber, FALSE to use File and Desc.
    291   @param[in] UsePath        TRUE to convert to devicepath.
    292   @param[in] HandleNumber   The handle number to add.
    293 
    294   @retval SHELL_SUCCESS             The operation was successful.
    295   @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
    296 **/
    297 SHELL_STATUS
    298 EFIAPI
    299 BcfgAdd(
    300   IN       UINTN                  Position,
    301   IN CONST CHAR16                 *File,
    302   IN CONST CHAR16                 *Desc,
    303   IN CONST UINT16                 *CurrentOrder,
    304   IN CONST UINTN                  OrderCount,
    305   IN CONST BCFG_OPERATION_TARGET  Target,
    306   IN CONST BOOLEAN                UseHandle,
    307   IN CONST BOOLEAN                UsePath,
    308   IN CONST UINTN                  HandleNumber
    309   )
    310 {
    311   EFI_STATUS                Status;
    312   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    313   EFI_DEVICE_PATH_PROTOCOL  *FilePath;
    314   CHAR16                    *Str;
    315   UINT8                     *TempByteBuffer;
    316   UINT8                     *TempByteStart;
    317   EFI_SHELL_FILE_INFO       *Arg;
    318   EFI_SHELL_FILE_INFO       *FileList;
    319   CHAR16                    OptionStr[40];
    320   UINTN                     DescSize, FilePathSize;
    321   BOOLEAN                   Found;
    322   UINTN                     TargetLocation;
    323   UINTN                     Index;
    324   EFI_HANDLE                *Handles;
    325   EFI_HANDLE                CurHandle;
    326   UINTN                     DriverBindingHandleCount;
    327   UINTN                     ParentControllerHandleCount;
    328   UINTN                     ChildControllerHandleCount;
    329   SHELL_STATUS              ShellStatus;
    330   UINT16                    *NewOrder;
    331 
    332   if (!UseHandle) {
    333     if (File == NULL || Desc == NULL) {
    334       return (SHELL_INVALID_PARAMETER);
    335     }
    336   } else {
    337     if (HandleNumber == 0) {
    338       return (SHELL_INVALID_PARAMETER);
    339     }
    340   }
    341 
    342   if (Position > OrderCount) {
    343     Position =  OrderCount;
    344   }
    345 
    346   Str             = NULL;
    347   FilePath        = NULL;
    348   FileList        = NULL;
    349   Handles         = NULL;
    350   ShellStatus     = SHELL_SUCCESS;
    351   TargetLocation  = 0xFFFF;
    352 
    353   if (UseHandle) {
    354     CurHandle = ConvertHandleIndexToHandle(HandleNumber);
    355     if (CurHandle == NULL) {
    356       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
    357       ShellStatus = SHELL_INVALID_PARAMETER;
    358     } else {
    359       if (Target == BcfgTargetBootOrder) {
    360         //
    361         //Make sure that the handle should point to a real controller
    362         //
    363         Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
    364                    CurHandle,
    365                    &DriverBindingHandleCount,
    366                    NULL);
    367 
    368         Status = PARSE_HANDLE_DATABASE_PARENTS (
    369                    CurHandle,
    370                    &ParentControllerHandleCount,
    371                    NULL);
    372 
    373         Status = ParseHandleDatabaseForChildControllers (
    374                    CurHandle,
    375                    &ChildControllerHandleCount,
    376                    NULL);
    377 
    378         if (DriverBindingHandleCount > 0
    379               || ParentControllerHandleCount > 0
    380               || ChildControllerHandleCount > 0) {
    381           FilePath = NULL;
    382           Status = gBS->HandleProtocol (
    383                      CurHandle,
    384                      &gEfiDevicePathProtocolGuid,
    385                      (VOID**)&FilePath);
    386         }
    387         if (EFI_ERROR (Status)) {
    388           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_HANDLE), gShellBcfgHiiHandle, L"bcfg", HandleNumber);
    389           ShellStatus = SHELL_INVALID_PARAMETER;
    390         }
    391       } else {
    392         //
    393         //Make sure that the handle should point to driver, not a controller.
    394         //
    395         Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
    396                    CurHandle,
    397                    &DriverBindingHandleCount,
    398                    NULL);
    399 
    400         Status = PARSE_HANDLE_DATABASE_PARENTS (
    401                    CurHandle,
    402                    &ParentControllerHandleCount,
    403                    NULL);
    404 
    405         Status = ParseHandleDatabaseForChildControllers (
    406                    CurHandle,
    407                    &ChildControllerHandleCount,
    408                    NULL);
    409 
    410         Status = gBS->HandleProtocol (
    411                    CurHandle,
    412                    &gEfiDevicePathProtocolGuid,
    413                    (VOID**)&FilePath);
    414 
    415         if (DriverBindingHandleCount > 0
    416               || ParentControllerHandleCount > 0
    417               || ChildControllerHandleCount > 0
    418               || !EFI_ERROR(Status) ) {
    419           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
    420           ShellStatus = SHELL_INVALID_PARAMETER;
    421         } else {
    422           //
    423           // Get the DevicePath from the loaded image information.
    424           //
    425           Status = GetDevicePathForDriverHandle(CurHandle, &FilePath);
    426         }
    427       }
    428     }
    429   } else {
    430     //
    431     // Get file info
    432     //
    433     ShellOpenFileMetaArg ((CHAR16*)File, EFI_FILE_MODE_READ, &FileList);
    434 
    435     if (FileList == NULL) {
    436       //
    437       // If filename matched nothing fail
    438       //
    439       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", File);
    440       ShellStatus = SHELL_INVALID_PARAMETER;
    441     } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) {
    442       //
    443       // If filename expanded to multiple names, fail
    444       //
    445       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", File);
    446       ShellStatus = SHELL_INVALID_PARAMETER;
    447     } else {
    448       Arg = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link);
    449       if (EFI_ERROR(Arg->Status)) {
    450         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", File);
    451         ShellStatus = SHELL_INVALID_PARAMETER;
    452       } else {
    453         //
    454         // Build FilePath to the filename
    455         //
    456 
    457         //
    458         // get the device path
    459         //
    460         DevicePath = gEfiShellProtocol->GetDevicePathFromFilePath(Arg->FullName);
    461         if (DevicePath == NULL) {
    462           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName);
    463           ShellStatus = SHELL_UNSUPPORTED;
    464         } else {
    465 /*
    466           if (UsePath) {
    467             DevPath = DevicePath;
    468             while (!IsDevicePathEnd(DevPath)) {
    469               if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) &&
    470                 (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) {
    471 
    472                 //
    473                 // If we find it use it instead
    474                 //
    475                 DevicePath = DevPath;
    476                 break;
    477               }
    478               DevPath = NextDevicePathNode(DevPath);
    479             }
    480             //
    481             // append the file
    482             //
    483             for(StringWalker=Arg->FullName; *StringWalker != CHAR_NULL && *StringWalker != ':'; StringWalker++);
    484             FileNode = FileDevicePath(NULL, StringWalker+1);
    485             FilePath = AppendDevicePath(DevicePath, FileNode);
    486             FreePool(FileNode);
    487           } else {
    488 */
    489             FilePath = DuplicateDevicePath(DevicePath);
    490 /*
    491           }
    492 */
    493           FreePool(DevicePath);
    494         }
    495       }
    496     }
    497   }
    498 
    499 
    500   if (ShellStatus == SHELL_SUCCESS) {
    501     //
    502     // Find a free target ,a brute force implementation
    503     //
    504     Found = FALSE;
    505     for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) {
    506       Found = TRUE;
    507       for (Index=0; Index < OrderCount; Index++) {
    508         if (CurrentOrder[Index] == TargetLocation) {
    509           Found = FALSE;
    510           break;
    511         }
    512       }
    513 
    514       if (Found) {
    515         break;
    516       }
    517     }
    518 
    519     if (TargetLocation == 0xFFFF) {
    520       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET_NF), gShellBcfgHiiHandle, L"bcfg");
    521     } else {
    522       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET), gShellBcfgHiiHandle, TargetLocation);
    523     }
    524   }
    525 
    526   if (ShellStatus == SHELL_SUCCESS) {
    527     //
    528     // Add the option
    529     //
    530     DescSize = StrSize(Desc);
    531     FilePathSize = GetDevicePathSize (FilePath);
    532 
    533     TempByteBuffer = AllocateZeroPool(sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize);
    534     if (TempByteBuffer != NULL) {
    535       TempByteStart  = TempByteBuffer;
    536       *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE;      // Attributes
    537       TempByteBuffer += sizeof (UINT32);
    538 
    539       *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize;    // FilePathListLength
    540       TempByteBuffer += sizeof (UINT16);
    541 
    542       CopyMem (TempByteBuffer, Desc, DescSize);
    543       TempByteBuffer += DescSize;
    544       ASSERT (FilePath != NULL);
    545       CopyMem (TempByteBuffer, FilePath, FilePathSize);
    546 
    547       UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", TargetLocation);
    548       Status = gRT->SetVariable (
    549             OptionStr,
    550             &gEfiGlobalVariableGuid,
    551             EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    552             sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize,
    553             TempByteStart
    554            );
    555 
    556       FreePool(TempByteStart);
    557     } else {
    558       Status = EFI_OUT_OF_RESOURCES;
    559     }
    560 
    561     if (EFI_ERROR(Status)) {
    562       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr);
    563     } else {
    564       NewOrder = AllocateZeroPool((OrderCount+1)*sizeof(NewOrder[0]));
    565       ASSERT(NewOrder != NULL);
    566       CopyMem(NewOrder, CurrentOrder, (OrderCount)*sizeof(NewOrder[0]));
    567 
    568       //
    569       // Insert target into order list
    570       //
    571       for (Index=OrderCount; Index > Position; Index--) {
    572         NewOrder[Index] = NewOrder[Index-1];
    573       }
    574 
    575       NewOrder[Position] = (UINT16) TargetLocation;
    576       Status = gRT->SetVariable (
    577         Target == BcfgTargetBootOrder?L"BootOrder":L"DriverOrder",
    578         &gEfiGlobalVariableGuid,
    579         EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    580         (OrderCount+1) * sizeof(UINT16),
    581         NewOrder
    582        );
    583 
    584       FreePool(NewOrder);
    585 
    586       if (EFI_ERROR(Status)) {
    587         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?L"BootOrder":L"DriverOrder");
    588         ShellStatus = SHELL_INVALID_PARAMETER;
    589       } else {
    590         Print (L"bcfg: Add %s as %x\n", OptionStr, Position);
    591       }
    592     }
    593   }
    594 
    595 //
    596 //If always Free FilePath, will free devicepath in system when use "addh"
    597 //
    598   if (FilePath!=NULL && !UseHandle) {
    599     FreePool (FilePath);
    600   }
    601 
    602   if (Str != NULL) {
    603     FreePool(Str);
    604   }
    605 
    606   if (Handles != NULL) {
    607     FreePool (Handles);
    608   }
    609 
    610   if (FileList != NULL) {
    611     ShellCloseFileMetaArg (&FileList);
    612   }
    613 
    614   return (ShellStatus);
    615 }
    616 
    617 /**
    618   Funciton to remove an item.
    619 
    620   @param[in] Target         The target item to move.
    621   @param[in] CurrentOrder   The pointer to the current order of items.
    622   @param[in] OrderCount     The number if items in CurrentOrder.
    623   @param[in] Location       The current location of the Target.
    624 
    625   @retval SHELL_SUCCESS             The operation was successful.
    626   @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
    627 **/
    628 SHELL_STATUS
    629 EFIAPI
    630 BcfgRemove(
    631   IN CONST BCFG_OPERATION_TARGET  Target,
    632   IN CONST UINT16                 *CurrentOrder,
    633   IN CONST UINTN                  OrderCount,
    634   IN CONST UINT16                 Location
    635   )
    636 {
    637   CHAR16      VariableName[12];
    638   UINT16      *NewOrder;
    639   EFI_STATUS  Status;
    640   UINTN       NewCount;
    641 
    642   UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", CurrentOrder[Location]);
    643   Status = gRT->SetVariable(
    644     VariableName,
    645     (EFI_GUID*)&gEfiGlobalVariableGuid,
    646     EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    647     0,
    648     NULL);
    649   if (EFI_ERROR(Status)) {
    650     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
    651     return (SHELL_INVALID_PARAMETER);
    652   }
    653   NewOrder = AllocateZeroPool(OrderCount*sizeof(CurrentOrder[0]));
    654   if (NewOrder != NULL) {
    655     NewCount = OrderCount;
    656     CopyMem(NewOrder, CurrentOrder, OrderCount*sizeof(CurrentOrder[0]));
    657     CopyMem(NewOrder+Location, NewOrder+Location+1, (OrderCount - Location - 1)*sizeof(CurrentOrder[0]));
    658     NewCount--;
    659 
    660     Status = gRT->SetVariable(
    661       Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
    662       (EFI_GUID*)&gEfiGlobalVariableGuid,
    663       EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    664       NewCount*sizeof(NewOrder[0]),
    665       NewOrder);
    666     FreePool(NewOrder);
    667   } else {
    668     Status = EFI_OUT_OF_RESOURCES;
    669   }
    670   if (EFI_ERROR(Status)) {
    671     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
    672     return (SHELL_INVALID_PARAMETER);
    673   }
    674   return (SHELL_SUCCESS);
    675 }
    676 
    677 /**
    678   Funciton to move a item to another location.
    679 
    680   @param[in] Target         The target item to move.
    681   @param[in] CurrentOrder   The pointer to the current order of items.
    682   @param[in] OrderCount     The number if items in CurrentOrder.
    683   @param[in] OldLocation    The current location of the Target.
    684   @param[in] NewLocation    The desired location of the Target.
    685 
    686   @retval SHELL_SUCCESS             The operation was successful.
    687   @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
    688 **/
    689 SHELL_STATUS
    690 EFIAPI
    691 BcfgMove(
    692   IN CONST BCFG_OPERATION_TARGET  Target,
    693   IN CONST UINT16                 *CurrentOrder,
    694   IN CONST UINTN                  OrderCount,
    695   IN CONST UINT16                 OldLocation,
    696   IN       UINT16                 NewLocation
    697   )
    698 {
    699   UINT16            *NewOrder;
    700   EFI_STATUS        Status;
    701   UINT16            Temp;
    702 
    703   NewOrder = AllocateCopyPool(OrderCount*sizeof(CurrentOrder[0]), CurrentOrder);
    704   if (NewOrder == NULL) {
    705     return (SHELL_OUT_OF_RESOURCES);
    706   }
    707 
    708   //
    709   // correct the new location
    710   //
    711   if (NewLocation >= OrderCount) {
    712     if (OrderCount > 0) {
    713       NewLocation = (UINT16)OrderCount - 1;
    714     } else {
    715       NewLocation = 0;
    716     }
    717   }
    718 
    719   Temp = CurrentOrder[OldLocation];
    720   CopyMem(NewOrder+OldLocation, NewOrder+OldLocation+1, (OrderCount - OldLocation - 1)*sizeof(CurrentOrder[0]));
    721   CopyMem(NewOrder+NewLocation+1, NewOrder+NewLocation, (OrderCount - NewLocation - 1)*sizeof(CurrentOrder[0]));
    722   NewOrder[NewLocation] = Temp;
    723 
    724   Status = gRT->SetVariable(
    725     Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
    726     (EFI_GUID*)&gEfiGlobalVariableGuid,
    727     EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    728     OrderCount*sizeof(CurrentOrder[0]),
    729     NewOrder);
    730 
    731   FreePool(NewOrder);
    732 
    733   if (EFI_ERROR(Status)) {
    734     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
    735     return (SHELL_INVALID_PARAMETER);
    736   }
    737   return (SHELL_SUCCESS);
    738 }
    739 
    740 /**
    741   Function to add optional data to an option.
    742 
    743   @param[in] OptData      The optional data to add.
    744   @param[in] CurrentOrder The pointer to the current order of items.
    745   @param[in] OrderCount   The number if items in CurrentOrder.
    746   @param[in] Target       The target of the operation.
    747 
    748   @retval SHELL_SUCCESS   The operation was succesful.
    749 **/
    750 SHELL_STATUS
    751 EFIAPI
    752 BcfgAddOpt(
    753   IN CONST CHAR16                 *OptData,
    754   IN CONST UINT16                 *CurrentOrder,
    755   IN CONST UINTN                  OrderCount,
    756   IN CONST BCFG_OPERATION_TARGET  Target
    757   )
    758 {
    759   EFI_KEY_OPTION  NewKeyOption;
    760   EFI_KEY_OPTION *KeyOptionBuffer;
    761   SHELL_STATUS    ShellStatus;
    762   EFI_STATUS      Status;
    763   UINT16          OptionIndex;
    764   UINT16          LoopCounter;
    765   UINT64          Intermediate;
    766   CONST CHAR16    *Temp;
    767   CONST CHAR16    *Walker;
    768   CHAR16          *FileName;
    769   CHAR16          *Temp2;
    770   CHAR16          *Data;
    771   UINT32          KeyIndex;
    772   CHAR16          VariableName[12];
    773   VOID            *VariableData;
    774 
    775   SHELL_FILE_HANDLE FileHandle;
    776 
    777   Status          = EFI_SUCCESS;
    778   ShellStatus     = SHELL_SUCCESS;
    779   Walker          = OptData;
    780   FileName        = NULL;
    781   Data            = NULL;
    782   KeyOptionBuffer = NULL;
    783   VariableData    = NULL;
    784 
    785   ZeroMem(&NewKeyOption, sizeof(EFI_KEY_OPTION));
    786   ZeroMem(VariableName, sizeof(VariableName));
    787 
    788   while(Walker[0] == L' ') {
    789     Walker++;
    790   }
    791 
    792   //
    793   // Get the index of the variable we are changing.
    794   //
    795   Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
    796   if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL || ((UINT16)Intermediate) > ((UINT16)OrderCount)) {
    797     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
    798     ShellStatus = SHELL_INVALID_PARAMETER;
    799     return (ShellStatus);
    800   }
    801   OptionIndex = (UINT16)Intermediate;
    802 
    803   Temp = StrStr(Walker, L" ");
    804   if (Temp != NULL) {
    805     Walker = Temp;
    806   }
    807   while(Walker[0] == L' ') {
    808     Walker++;
    809   }
    810 
    811   //
    812   // determine whether we have file with data, quote delimited information, or a hot-key
    813   //
    814   if (Walker[0] == L'\"') {
    815     //
    816     // quoted filename or quoted information.
    817     //
    818     Temp = StrStr(Walker+1, L"\"");
    819     if (Temp == NULL || StrLen(Temp) != 1) {
    820       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
    821       ShellStatus = SHELL_INVALID_PARAMETER;
    822     } else {
    823       FileName = StrnCatGrow(&FileName, NULL, Walker+1, 0);
    824       if (FileName == NULL) {
    825         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellBcfgHiiHandle, L"bcfg");
    826         ShellStatus = SHELL_OUT_OF_RESOURCES;
    827         return (ShellStatus);
    828       }
    829       Temp2 = StrStr(FileName, L"\"");
    830       ASSERT(Temp2 != NULL);
    831       Temp2[0] = CHAR_NULL;
    832       Temp2++;
    833       if (StrLen(Temp2)>0) {
    834         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
    835         ShellStatus = SHELL_INVALID_PARAMETER;
    836       }
    837       if (EFI_ERROR(ShellFileExists(Walker))) {
    838         //
    839         // Not a file.  must be misc information.
    840         //
    841         Data     = FileName;
    842         FileName = NULL;
    843       } else {
    844         FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
    845       }
    846     }
    847   } else {
    848     //
    849     // filename or hot key information.
    850     //
    851     if (StrStr(Walker, L" ") == NULL) {
    852       //
    853       // filename
    854       //
    855       if (EFI_ERROR(ShellFileExists(Walker))) {
    856         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellBcfgHiiHandle, L"bcfg", Walker);
    857         ShellStatus = SHELL_INVALID_PARAMETER;
    858       } else {
    859         FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
    860       }
    861     } else {
    862       if (Target != BcfgTargetBootOrder) {
    863         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_BOOT_ONLY), gShellBcfgHiiHandle, L"bcfg");
    864         ShellStatus = SHELL_INVALID_PARAMETER;
    865       }
    866 
    867       if (ShellStatus == SHELL_SUCCESS) {
    868         //
    869         // Get hot key information
    870         //
    871         Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
    872         if (EFI_ERROR(Status) || (((UINT32)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
    873           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
    874           ShellStatus = SHELL_INVALID_PARAMETER;
    875         }
    876         NewKeyOption.KeyData.PackedValue = (UINT32)Intermediate;
    877         Temp = StrStr(Walker, L" ");
    878         if (Temp != NULL) {
    879           Walker = Temp;
    880         }
    881         while(Walker[0] == L' ') {
    882           Walker++;
    883         }
    884       }
    885 
    886       if (ShellStatus == SHELL_SUCCESS) {
    887         //
    888         // Now we know how many EFI_INPUT_KEY structs we need to attach to the end of the EFI_KEY_OPTION struct.
    889         // Re-allocate with the added information.
    890         //
    891         KeyOptionBuffer = AllocateCopyPool(sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount), &NewKeyOption);
    892         if (KeyOptionBuffer == NULL) {
    893           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
    894           ShellStatus = SHELL_OUT_OF_RESOURCES;
    895         }
    896       }
    897       for (LoopCounter = 0 ; ShellStatus == SHELL_SUCCESS && LoopCounter < NewKeyOption.KeyData.Options.InputKeyCount; LoopCounter++) {
    898         //
    899         // ScanCode
    900         //
    901         Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
    902         if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
    903           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
    904           ShellStatus = SHELL_INVALID_PARAMETER;
    905         }
    906         ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].ScanCode = (UINT16)Intermediate;
    907         Temp = StrStr(Walker, L" ");
    908         if (Temp != NULL) {
    909           Walker = Temp;
    910         }
    911         while(Walker[0] == L' ') {
    912           Walker++;
    913         }
    914 
    915         //
    916         // UnicodeChar
    917         //
    918         Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
    919         if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate)) {
    920           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
    921           ShellStatus = SHELL_INVALID_PARAMETER;
    922         }
    923         ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].UnicodeChar = (UINT16)Intermediate;
    924         Temp = StrStr(Walker, L" ");
    925         if (Temp != NULL) {
    926           Walker = Temp;
    927         }
    928         while(Walker[0] == L' ') {
    929           Walker++;
    930         }
    931       }
    932 
    933       if (ShellStatus == SHELL_SUCCESS) {
    934         //
    935         // Now do the BootOption / BootOptionCrc
    936         //
    937         ASSERT (OptionIndex <= OrderCount);
    938         KeyOptionBuffer->BootOption    = CurrentOrder[OptionIndex];
    939         Status = GetBootOptionCrc(&(KeyOptionBuffer->BootOptionCrc), KeyOptionBuffer->BootOption);
    940         if (EFI_ERROR(Status)) {
    941           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
    942           ShellStatus = SHELL_INVALID_PARAMETER;
    943         }
    944       }
    945 
    946       if (ShellStatus == SHELL_SUCCESS) {
    947         for (Temp2 = NULL, KeyIndex = 0 ; KeyIndex <= 0xFFFF ; KeyIndex++) {
    948           UnicodeSPrint(VariableName, sizeof(VariableName), L"Key%04x", KeyIndex);
    949           Status = GetEfiGlobalVariable2 (VariableName, &VariableData, NULL);
    950           if (Status == EFI_NOT_FOUND) {
    951             break;
    952           }
    953           if (!EFI_ERROR(Status)) {
    954             SHELL_FREE_NON_NULL(VariableData);
    955           }
    956         }
    957         if (KeyIndex <= 0xFFFF) {
    958           Status = gRT->SetVariable(
    959             VariableName,
    960             (EFI_GUID*)&gEfiGlobalVariableGuid,
    961             EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
    962             sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount),
    963             KeyOptionBuffer);
    964           if (EFI_ERROR(Status)) {
    965             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
    966             ShellStatus = SHELL_INVALID_PARAMETER;
    967           }
    968         } else {
    969           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_NO_NUM), gShellBcfgHiiHandle, L"bcfg");
    970           ShellStatus = SHELL_INVALID_PARAMETER;
    971         }
    972         ASSERT(FileName == NULL && Data == NULL);
    973       }
    974     }
    975   }
    976 
    977   //
    978   // Shouldn't be possible to have have both. Neither is ok though.
    979   //
    980   ASSERT(FileName == NULL || Data == NULL);
    981 
    982   if (ShellStatus == SHELL_SUCCESS && (FileName != NULL || Data != NULL)) {
    983     if (FileName != NULL) {
    984       //
    985       // Open the file and populate the data buffer.
    986       //
    987       Status = ShellOpenFileByName(
    988         FileName,
    989         &FileHandle,
    990         EFI_FILE_MODE_READ,
    991         0);
    992       if (!EFI_ERROR(Status)) {
    993         Status = ShellGetFileSize(FileHandle, &Intermediate);
    994       }
    995       Data = AllocateZeroPool((UINTN)Intermediate);
    996       if (Data == NULL) {
    997         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
    998         ShellStatus = SHELL_OUT_OF_RESOURCES;
    999       }
   1000       if (!EFI_ERROR(Status)) {
   1001         Status = ShellReadFile(FileHandle, (UINTN *)&Intermediate, Data);
   1002       }
   1003     } else {
   1004       Intermediate = StrSize(Data);
   1005     }
   1006 
   1007     if (!EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS && Data != NULL) {
   1008       Status = UpdateOptionalData(CurrentOrder[OptionIndex], (UINTN)Intermediate, (UINT8*)Data, Target);
   1009       if (EFI_ERROR(Status)) {
   1010         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
   1011         ShellStatus = SHELL_INVALID_PARAMETER;
   1012       }
   1013     }
   1014     if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
   1015       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
   1016       ShellStatus = SHELL_INVALID_PARAMETER;
   1017     }
   1018   }
   1019 
   1020   SHELL_FREE_NON_NULL(Data);
   1021   SHELL_FREE_NON_NULL(KeyOptionBuffer);
   1022   SHELL_FREE_NON_NULL(FileName);
   1023   return ShellStatus;
   1024 }
   1025 
   1026 /**
   1027   Function to dump the Bcfg information.
   1028 
   1029   @param[in] Op             The operation.
   1030   @param[in] OrderCount     How many to dump.
   1031   @param[in] CurrentOrder   The pointer to the current order of items.
   1032   @param[in] VerboseOutput  TRUE for extra output.  FALSE otherwise.
   1033 
   1034   @retval SHELL_SUCCESS           The dump was successful.
   1035   @retval SHELL_INVALID_PARAMETER A parameter was invalid.
   1036 **/
   1037 SHELL_STATUS
   1038 EFIAPI
   1039 BcfgDisplayDump(
   1040   IN CONST CHAR16   *Op,
   1041   IN CONST UINTN    OrderCount,
   1042   IN CONST UINT16   *CurrentOrder,
   1043   IN CONST BOOLEAN  VerboseOutput
   1044   )
   1045 {
   1046   EFI_STATUS  Status;
   1047   UINT8       *Buffer;
   1048   UINTN       BufferSize;
   1049   CHAR16      VariableName[12];
   1050   UINTN       LoopVar;
   1051   UINTN       LoopVar2;
   1052   CHAR16      *DevPathString;
   1053   VOID        *DevPath;
   1054 
   1055   if (OrderCount == 0) {
   1056     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_BCFG_NONE), gShellBcfgHiiHandle, L"bcfg");
   1057     return (SHELL_SUCCESS);
   1058   }
   1059 
   1060   for (LoopVar = 0 ; LoopVar < OrderCount ; LoopVar++) {
   1061     Buffer      = NULL;
   1062     BufferSize  = 0;
   1063     UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Op, CurrentOrder[LoopVar]);
   1064 
   1065     Status = gRT->GetVariable(
   1066         VariableName,
   1067         (EFI_GUID*)&gEfiGlobalVariableGuid,
   1068         NULL,
   1069         &BufferSize,
   1070         Buffer);
   1071     if (Status == EFI_BUFFER_TOO_SMALL) {
   1072       Buffer = AllocateZeroPool(BufferSize);
   1073       Status = gRT->GetVariable(
   1074           VariableName,
   1075           (EFI_GUID*)&gEfiGlobalVariableGuid,
   1076           NULL,
   1077           &BufferSize,
   1078           Buffer);
   1079     }
   1080 
   1081     if (EFI_ERROR(Status) || Buffer == NULL) {
   1082       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_READ_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
   1083       return (SHELL_INVALID_PARAMETER);
   1084     }
   1085 
   1086     if ((*(UINT16*)(Buffer+4)) != 0) {
   1087       DevPath = AllocateZeroPool(*(UINT16*)(Buffer+4));
   1088       if (DevPath == NULL) {
   1089         DevPathString = NULL;
   1090       } else {
   1091         CopyMem(DevPath, Buffer+6+StrSize((CHAR16*)(Buffer+6)), *(UINT16*)(Buffer+4));
   1092         DevPathString = ConvertDevicePathToText(DevPath, TRUE, FALSE);
   1093       }
   1094     } else {
   1095       DevPath       = NULL;
   1096       DevPathString = NULL;
   1097     }
   1098     ShellPrintHiiEx(
   1099       -1,
   1100       -1,
   1101       NULL,
   1102       STRING_TOKEN(STR_BCFG_LOAD_OPTIONS),
   1103       gShellBcfgHiiHandle,
   1104       LoopVar,
   1105       VariableName,
   1106       (CHAR16*)(Buffer+6),
   1107       DevPathString,
   1108       (StrSize((CHAR16*)(Buffer+6)) + *(UINT16*)(Buffer+4) + 6) <= BufferSize?L'N':L'Y');
   1109     if (VerboseOutput) {
   1110       for (LoopVar2 = (StrSize((CHAR16*)(Buffer+6)) + *(UINT16*)(Buffer+4) + 6);LoopVar2<BufferSize;LoopVar2++){
   1111         ShellPrintEx(
   1112           -1,
   1113           -1,
   1114           NULL,
   1115           L"%02x",
   1116           Buffer[LoopVar2]);
   1117       }
   1118       ShellPrintEx(
   1119         -1,
   1120         -1,
   1121         NULL,
   1122         L"\r\n");
   1123     }
   1124 
   1125     if (Buffer != NULL) {
   1126       FreePool(Buffer);
   1127     }
   1128     if (DevPath != NULL) {
   1129       FreePool(DevPath);
   1130     }
   1131     if (DevPathString != NULL) {
   1132       FreePool(DevPathString);
   1133     }
   1134   }
   1135   return (SHELL_SUCCESS);
   1136 }
   1137 
   1138 /**
   1139   Function to initialize the BCFG operation structure.
   1140 
   1141   @param[in] Struct   The stuct to initialize.
   1142 **/
   1143 VOID
   1144 EFIAPI
   1145 InitBcfgStruct(
   1146   IN BGFG_OPERATION *Struct
   1147   )
   1148 {
   1149   ASSERT(Struct != NULL);
   1150   Struct->Target      = BcfgTargetMax;
   1151   Struct->Type        = BcfgTypeMax;
   1152   Struct->Number1     = 0;
   1153   Struct->Number2     = 0;
   1154   Struct->HandleIndex = 0;
   1155   Struct->FileName    = NULL;
   1156   Struct->Description = NULL;
   1157   Struct->Order       = NULL;
   1158   Struct->OptData     = NULL;
   1159 }
   1160 
   1161 
   1162 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
   1163   {L"-v", TypeFlag},
   1164   {L"-opt", TypeMaxValue},
   1165   {NULL, TypeMax}
   1166   };
   1167 
   1168 /**
   1169   Function for 'bcfg' command.
   1170 
   1171   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
   1172   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
   1173 **/
   1174 SHELL_STATUS
   1175 EFIAPI
   1176 ShellCommandRunBcfg (
   1177   IN EFI_HANDLE        ImageHandle,
   1178   IN EFI_SYSTEM_TABLE  *SystemTable
   1179   )
   1180 {
   1181   EFI_STATUS            Status;
   1182   LIST_ENTRY            *Package;
   1183   CHAR16                *ProblemParam;
   1184   SHELL_STATUS          ShellStatus;
   1185   UINTN                 ParamNumber;
   1186   CONST CHAR16          *CurrentParam;
   1187   BGFG_OPERATION        CurrentOperation;
   1188   UINTN                 Length;
   1189   UINT64                Intermediate;
   1190   UINT16                Count;
   1191 
   1192   Length              = 0;
   1193   ProblemParam        = NULL;
   1194   Package             = NULL;
   1195   ShellStatus         = SHELL_SUCCESS;
   1196 
   1197   InitBcfgStruct(&CurrentOperation);
   1198 
   1199   //
   1200   // initialize the shell lib (we must be in non-auto-init...)
   1201   //
   1202   Status = ShellInitialize();
   1203   ASSERT_EFI_ERROR(Status);
   1204 
   1205   Status = CommandInit();
   1206   ASSERT_EFI_ERROR(Status);
   1207 
   1208   //
   1209   // parse the command line
   1210   //
   1211   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
   1212   if (EFI_ERROR(Status)) {
   1213     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
   1214       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellBcfgHiiHandle, L"bcfg", ProblemParam);
   1215       FreePool(ProblemParam);
   1216       ShellStatus = SHELL_INVALID_PARAMETER;
   1217     } else {
   1218       ASSERT(FALSE);
   1219     }
   1220   } else {
   1221     //
   1222     // Read in if we are doing -OPT
   1223     //
   1224     if (ShellCommandLineGetFlag(Package, L"-opt")) {
   1225       CurrentOperation.OptData = ShellCommandLineGetValue(Package, L"-opt");
   1226       if (CurrentOperation.OptData == NULL) {
   1227         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellBcfgHiiHandle, L"bcfg", L"-opt");
   1228         ShellStatus = SHELL_INVALID_PARAMETER;
   1229       }
   1230       CurrentOperation.Type = BcfgTypeOpt;
   1231     }
   1232 
   1233     //
   1234     // small block to read the target of the operation
   1235     //
   1236     if ((ShellCommandLineGetCount(Package) < 3 && CurrentOperation.Type != BcfgTypeOpt) ||
   1237         (ShellCommandLineGetCount(Package) < 2 && CurrentOperation.Type == BcfgTypeOpt)
   1238        ){
   1239       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1240       ShellStatus = SHELL_INVALID_PARAMETER;
   1241     } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"driver") == 0) {
   1242       CurrentOperation.Target = BcfgTargetDriverOrder;
   1243     } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"boot") == 0) {
   1244       CurrentOperation.Target = BcfgTargetBootOrder;
   1245     } else {
   1246       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_DRIVER_BOOT), gShellBcfgHiiHandle, L"bcfg");
   1247       ShellStatus = SHELL_INVALID_PARAMETER;
   1248     }
   1249 
   1250 
   1251     //
   1252     // Read in the boot or driver order environment variable (not needed for opt)
   1253     //
   1254     if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
   1255       Length = 0;
   1256       Status = gRT->GetVariable(
   1257         CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
   1258         (EFI_GUID*)&gEfiGlobalVariableGuid,
   1259         NULL,
   1260         &Length,
   1261         CurrentOperation.Order);
   1262       if (Status == EFI_BUFFER_TOO_SMALL) {
   1263         CurrentOperation.Order = AllocateZeroPool(Length+(4*sizeof(CurrentOperation.Order[0])));
   1264         if (CurrentOperation.Order == NULL) {
   1265           ShellStatus = SHELL_OUT_OF_RESOURCES;
   1266         } else {
   1267           Status = gRT->GetVariable(
   1268             CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
   1269             (EFI_GUID*)&gEfiGlobalVariableGuid,
   1270             NULL,
   1271             &Length,
   1272             CurrentOperation.Order);
   1273         }
   1274       }
   1275     }
   1276 
   1277     Count = (UINT16) (Length / sizeof(CurrentOperation.Order[0]));
   1278 
   1279     //
   1280     // large block to read the type of operation and verify parameter types for the info.
   1281     //
   1282     if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
   1283       for (ParamNumber = 2 ; ParamNumber < ShellCommandLineGetCount(Package) && ShellStatus == SHELL_SUCCESS; ParamNumber++) {
   1284         CurrentParam = ShellCommandLineGetRawValue(Package, ParamNumber);
   1285         if        (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"dump") == 0)    {
   1286           CurrentOperation.Type = BcfgTypeDump;
   1287         } else if (ShellCommandLineGetFlag(Package, L"-v")) {
   1288           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"-v (without dump)");
   1289           ShellStatus = SHELL_INVALID_PARAMETER;
   1290         } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"add") == 0)     {
   1291           if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
   1292             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1293             ShellStatus = SHELL_INVALID_PARAMETER;
   1294           }
   1295           CurrentOperation.Type = BcfgTypeAdd;
   1296           CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1297           if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1298             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1299             ShellStatus = SHELL_INVALID_PARAMETER;
   1300           } else {
   1301             Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1302             CurrentOperation.Number1     = (UINT16)Intermediate;
   1303             ASSERT(CurrentOperation.FileName == NULL);
   1304             CurrentOperation.FileName    = StrnCatGrow(&CurrentOperation.FileName   , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
   1305             ASSERT(CurrentOperation.Description == NULL);
   1306             CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
   1307           }
   1308         } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addp") == 0)    {
   1309           if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
   1310             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1311             ShellStatus = SHELL_INVALID_PARAMETER;
   1312           }
   1313           CurrentOperation.Type = BcfgTypeAddp;
   1314           CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1315           if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1316             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1317             ShellStatus = SHELL_INVALID_PARAMETER;
   1318           } else {
   1319             Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1320             CurrentOperation.Number1     = (UINT16)Intermediate;
   1321             ASSERT(CurrentOperation.FileName == NULL);
   1322             CurrentOperation.FileName    = StrnCatGrow(&CurrentOperation.FileName   , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
   1323             ASSERT(CurrentOperation.Description == NULL);
   1324             CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
   1325           }
   1326         } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addh") == 0)    {
   1327           if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
   1328             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1329             ShellStatus = SHELL_INVALID_PARAMETER;
   1330           }
   1331           CurrentOperation.Type = BcfgTypeAddh;
   1332           CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1333           if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1334             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1335             ShellStatus = SHELL_INVALID_PARAMETER;
   1336           } else {
   1337             Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1338             CurrentOperation.Number1     = (UINT16)Intermediate;
   1339             CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1340             if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1341               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1342               ShellStatus = SHELL_INVALID_PARAMETER;
   1343             } else {
   1344               Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1345               CurrentOperation.HandleIndex = (UINT16)Intermediate;
   1346               ASSERT(CurrentOperation.Description == NULL);
   1347               CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
   1348             }
   1349           }
   1350         } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"rm") == 0)      {
   1351           if ((ParamNumber + 1) >= ShellCommandLineGetCount(Package)) {
   1352             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1353             ShellStatus = SHELL_INVALID_PARAMETER;
   1354           }
   1355           CurrentOperation.Type = BcfgTypeRm;
   1356           CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1357           if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1358             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1359             ShellStatus = SHELL_INVALID_PARAMETER;
   1360           } else {
   1361             Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1362             CurrentOperation.Number1     = (UINT16)Intermediate;
   1363             if (CurrentOperation.Number1 >= Count){
   1364               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
   1365               ShellStatus = SHELL_INVALID_PARAMETER;
   1366             }
   1367           }
   1368         } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"mv") == 0)      {
   1369           if ((ParamNumber + 2) >= ShellCommandLineGetCount(Package)) {
   1370             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
   1371             ShellStatus = SHELL_INVALID_PARAMETER;
   1372           }
   1373           CurrentOperation.Type = BcfgTypeMv;
   1374           CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1375           if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1376             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1377             ShellStatus = SHELL_INVALID_PARAMETER;
   1378           } else {
   1379             Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1380             CurrentOperation.Number1     = (UINT16)Intermediate;
   1381             if (CurrentOperation.Number1 >= Count){
   1382               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
   1383               ShellStatus = SHELL_INVALID_PARAMETER;
   1384             } else {
   1385               CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
   1386               if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
   1387                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1388                 ShellStatus = SHELL_INVALID_PARAMETER;
   1389               } else {
   1390                 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
   1391                 CurrentOperation.Number2     = (UINT16)Intermediate;
   1392               }
   1393               if (CurrentOperation.Number2 == CurrentOperation.Number1
   1394                 ||CurrentOperation.Number2 >= Count
   1395                ){
   1396                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
   1397                 ShellStatus = SHELL_INVALID_PARAMETER;
   1398               }
   1399             }
   1400           }
   1401         } else {
   1402           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
   1403           ShellStatus = SHELL_INVALID_PARAMETER;
   1404         }
   1405       }
   1406     }
   1407     if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax && CurrentOperation.Type < BcfgTypeMax) {
   1408       //
   1409       // we have all the info.  Do the work
   1410       //
   1411       switch (CurrentOperation.Type) {
   1412         case   BcfgTypeDump:
   1413           ShellStatus = BcfgDisplayDump(
   1414             CurrentOperation.Target == BcfgTargetBootOrder?L"Boot":L"Driver",
   1415             Count,
   1416             CurrentOperation.Order,
   1417             ShellCommandLineGetFlag(Package, L"-v"));
   1418           break;
   1419         case   BcfgTypeMv:
   1420           ShellStatus = BcfgMove(
   1421             CurrentOperation.Target,
   1422             CurrentOperation.Order,
   1423             Count,
   1424             CurrentOperation.Number1,
   1425             CurrentOperation.Number2);
   1426           break;
   1427         case   BcfgTypeRm:
   1428           ShellStatus = BcfgRemove(
   1429             CurrentOperation.Target,
   1430             CurrentOperation.Order,
   1431             Count,
   1432             CurrentOperation.Number1);
   1433           break;
   1434         case   BcfgTypeAdd:
   1435         case   BcfgTypeAddp:
   1436         case   BcfgTypeAddh:
   1437           ShellStatus = BcfgAdd(
   1438             CurrentOperation.Number1,
   1439             CurrentOperation.FileName,
   1440             CurrentOperation.Description==NULL?L"":CurrentOperation.Description,
   1441             CurrentOperation.Order,
   1442             Count,
   1443             CurrentOperation.Target,
   1444             (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddh),
   1445             (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddp),
   1446             CurrentOperation.HandleIndex);
   1447           break;
   1448         case   BcfgTypeOpt:
   1449           ShellStatus = BcfgAddOpt(
   1450             CurrentOperation.OptData,
   1451             CurrentOperation.Order,
   1452             Count,
   1453             CurrentOperation.Target);
   1454           break;
   1455         default:
   1456           ASSERT(FALSE);
   1457       }
   1458     }
   1459   }
   1460 
   1461   if (Package != NULL) {
   1462     ShellCommandLineFreeVarList (Package);
   1463   }
   1464   if (CurrentOperation.FileName != NULL) {
   1465     FreePool(CurrentOperation.FileName);
   1466   }
   1467   if (CurrentOperation.Description != NULL) {
   1468     FreePool(CurrentOperation.Description);
   1469   }
   1470   if (CurrentOperation.Order != NULL) {
   1471     FreePool(CurrentOperation.Order);
   1472   }
   1473 
   1474   return (ShellStatus);
   1475 }
   1476 
   1477 
   1478 /**
   1479   Function to get the filename with help context if HII will not be used.
   1480 
   1481   @return   The filename with help text in it.
   1482 **/
   1483 CONST CHAR16*
   1484 EFIAPI
   1485 ShellCommandGetManFileNameBcfg (
   1486   VOID
   1487   )
   1488 {
   1489   return (mFileName);
   1490 }
   1491 
   1492 /**
   1493   "Constructor" for the library.
   1494 
   1495   This will register the handler for the bcfg command.
   1496 
   1497   @param[in] ImageHandle    the image handle of the process
   1498   @param[in] SystemTable    the EFI System Table pointer
   1499   @param[in] Name           the profile name to use
   1500 
   1501   @retval EFI_SUCCESS        the shell command handlers were installed sucessfully
   1502   @retval EFI_UNSUPPORTED    the shell level required was not found.
   1503 **/
   1504 EFI_STATUS
   1505 EFIAPI
   1506 BcfgLibraryRegisterBcfgCommand (
   1507   IN EFI_HANDLE        ImageHandle,
   1508   IN EFI_SYSTEM_TABLE  *SystemTable,
   1509   IN CONST CHAR16      *Name
   1510   )
   1511 {
   1512   if (gShellBcfgHiiHandle != NULL) {
   1513     return (EFI_SUCCESS);
   1514   }
   1515 
   1516   gShellBcfgHiiHandle = HiiAddPackages (&gShellBcfgHiiGuid, gImageHandle, UefiShellBcfgCommandLibStrings, NULL);
   1517   if (gShellBcfgHiiHandle == NULL) {
   1518     return (EFI_DEVICE_ERROR);
   1519   }
   1520 
   1521   //
   1522   // install our shell command handler
   1523   //
   1524   ShellCommandRegisterCommandName(L"bcfg", ShellCommandRunBcfg , ShellCommandGetManFileNameBcfg, 0, Name, FALSE, gShellBcfgHiiHandle, STRING_TOKEN(STR_GET_HELP_BCFG));
   1525 
   1526   return (EFI_SUCCESS);
   1527 }
   1528 
   1529 /**
   1530   Destructor for the library.  free any resources.
   1531 
   1532   @param ImageHandle            The image handle of the process.
   1533   @param SystemTable            The EFI System Table pointer.
   1534 **/
   1535 EFI_STATUS
   1536 EFIAPI
   1537 BcfgLibraryUnregisterBcfgCommand (
   1538   IN EFI_HANDLE        ImageHandle,
   1539   IN EFI_SYSTEM_TABLE  *SystemTable
   1540   )
   1541 {
   1542   if (gShellBcfgHiiHandle != NULL) {
   1543     HiiRemovePackages(gShellBcfgHiiHandle);
   1544   }
   1545   gShellBcfgHiiHandle = NULL;
   1546   return (EFI_SUCCESS);
   1547 }
   1548 
   1549