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