/** @file Main file for BCFG command. (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include STATIC CONST CHAR16 mFileName[] = L"ShellCommands"; STATIC EFI_HII_HANDLE gShellBcfgHiiHandle = NULL; typedef enum { BcfgTargetBootOrder = 0, BcfgTargetDriverOrder = 1, BcfgTargetMax = 2 } BCFG_OPERATION_TARGET; typedef enum { BcfgTypeDump = 0, BcfgTypeAdd = 1, BcfgTypeAddp = 2, BcfgTypeAddh = 3, BcfgTypeRm = 4, BcfgTypeMv = 5, BcfgTypeOpt = 6, BcfgTypeMod = 7, BcfgTypeModf = 8, BcfgTypeModp = 9, BcfgTypeModh = 10, BcfgTypeMax = 11 } BCFG_OPERATION_TYPE; typedef struct { BCFG_OPERATION_TARGET Target; BCFG_OPERATION_TYPE Type; UINT16 Number1; UINT16 Number2; UINTN HandleIndex; CHAR16 *FileName; CHAR16 *Description; UINT16 *Order; CONST CHAR16 *OptData; } BGFG_OPERATION; /** Update the optional data for a boot or driver option. If optional data exists it will be changed. @param[in] Index The boot or driver option index update. @param[in] DataSize The size in bytes of Data. @param[in] Data The buffer for the optioanl data. @param[in] Target The target of the operation. @retval EFI_SUCCESS The data was sucessfully updated. @retval other A error occurred. **/ EFI_STATUS UpdateOptionalData ( UINT16 Index, UINTN DataSize, UINT8 *Data, IN CONST BCFG_OPERATION_TARGET Target ) { EFI_STATUS Status; CHAR16 VariableName[12]; UINTN OriginalSize; UINT8 *OriginalData; UINTN NewSize; UINT8 *NewData; UINTN OriginalOptionDataSize; UnicodeSPrint (VariableName, sizeof (VariableName), L"%s%04x", Target == BcfgTargetBootOrder ? L"Boot" : L"Driver", Index); OriginalSize = 0; OriginalData = NULL; NewData = NULL; NewSize = 0; Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &OriginalSize, OriginalData ); if (Status == EFI_BUFFER_TOO_SMALL) { OriginalData = AllocateZeroPool (OriginalSize); if (OriginalData == NULL) { return (EFI_OUT_OF_RESOURCES); } Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &OriginalSize, OriginalData ); } if (!EFI_ERROR (Status)) { // // Allocate new struct and discard old optional data. // ASSERT (OriginalData != NULL); OriginalOptionDataSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (((CHAR16 *)(OriginalData + sizeof (UINT32) + sizeof (UINT16)))); OriginalOptionDataSize += (*(UINT16 *)(OriginalData + sizeof (UINT32))); OriginalOptionDataSize -= OriginalSize; NewSize = OriginalSize - OriginalOptionDataSize + DataSize; NewData = AllocatePool (NewSize); if (NewData == NULL) { Status = EFI_OUT_OF_RESOURCES; } else { CopyMem (NewData, OriginalData, OriginalSize - OriginalOptionDataSize); CopyMem (NewData + OriginalSize - OriginalOptionDataSize, Data, DataSize); } } if (!EFI_ERROR (Status)) { // // put the data back under the variable // Status = gRT->SetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, NewSize, NewData ); } SHELL_FREE_NON_NULL (OriginalData); SHELL_FREE_NON_NULL (NewData); return (Status); } /** This function will get a CRC for a boot option. @param[in, out] Crc The CRC value to return. @param[in] BootIndex The boot option index to CRC. @retval EFI_SUCCESS The CRC was sucessfully returned. @retval other A error occurred. **/ EFI_STATUS GetBootOptionCrc ( UINT32 *Crc, UINT16 BootIndex ) { CHAR16 VariableName[12]; EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; Buffer = NULL; BufferSize = 0; // // Get the data Buffer // UnicodeSPrint (VariableName, sizeof (VariableName), L"%Boot%04x", BootIndex); Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &BufferSize, NULL ); if (Status == EFI_BUFFER_TOO_SMALL) { Buffer = AllocateZeroPool (BufferSize); Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &BufferSize, Buffer ); } // // Get the CRC computed // if (!EFI_ERROR (Status)) { Status = gBS->CalculateCrc32 (Buffer, BufferSize, Crc); } SHELL_FREE_NON_NULL (Buffer); return EFI_SUCCESS; } /** This function will populate the device path protocol parameter based on TheHandle. @param[in] TheHandle Driver handle. @param[in, out] FilePath On a sucessful return the device path to the handle. @retval EFI_SUCCESS The device path was sucessfully returned. @retval other A error from gBS->HandleProtocol. @sa HandleProtocol **/ EFI_STATUS GetDevicePathForDriverHandle ( IN EFI_HANDLE TheHandle, IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath ) { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; Status = gBS->OpenProtocol ( TheHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (!EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&ImageDevicePath, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (!EFI_ERROR (Status)) { // *DevPath = DuplicateDevicePath (ImageDevicePath); // *FilePath = DuplicateDevicePath (LoadedImage->FilePath); *FilePath = AppendDevicePath (ImageDevicePath, LoadedImage->FilePath); gBS->CloseProtocol ( LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, gImageHandle, NULL ); } gBS->CloseProtocol ( TheHandle, &gEfiLoadedImageProtocolGuid, gImageHandle, NULL ); } return (Status); } /** Functino to get Device Path by a handle. @param[in] TheHandle Use it to get DevicePath. @param[in] Target Boot option target. @param[in, out] DevicePath On a sucessful return the device path to the handle. @retval SHELL_INVALID_PARAMETER The handle was NULL. @retval SHELL_NOT_FOUND Not found device path by handle. @retval SHELL_SUCCESS Get device path successfully. **/ SHELL_STATUS GetDevicePathByHandle ( IN EFI_HANDLE TheHandle, IN BCFG_OPERATION_TARGET Target, IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ) { EFI_STATUS Status; SHELL_STATUS ShellStatus; UINTN DriverBindingHandleCount; UINTN ParentControllerHandleCount; UINTN ChildControllerHandleCount; ShellStatus = SHELL_SUCCESS; if (TheHandle == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); return SHELL_INVALID_PARAMETER; } Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (TheHandle, &DriverBindingHandleCount, NULL); if (EFI_ERROR (Status)) { DriverBindingHandleCount = 0; } Status = PARSE_HANDLE_DATABASE_PARENTS (TheHandle, &ParentControllerHandleCount, NULL); if (EFI_ERROR (Status)) { ParentControllerHandleCount = 0; } Status = ParseHandleDatabaseForChildControllers (TheHandle, &ChildControllerHandleCount, NULL); if (EFI_ERROR (Status)) { ChildControllerHandleCount = 0; } Status = gBS->HandleProtocol (TheHandle, &gEfiDevicePathProtocolGuid, (VOID **)DevicePath); if ((DriverBindingHandleCount > 0) || (ParentControllerHandleCount > 0) || (ChildControllerHandleCount > 0) || !EFI_ERROR (Status) ) { // // The handle points to a real controller which has a device path. // if (Target == BcfgTargetDriverOrder) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle should point to driver image." ); ShellStatus = SHELL_NOT_FOUND; } } else { // // The handle points to a driver image. // if (Target == BcfgTargetBootOrder) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle should point to controller." ); ShellStatus = SHELL_NOT_FOUND; } else { if (EFI_ERROR (GetDevicePathForDriverHandle (TheHandle, DevicePath))) { ShellStatus = SHELL_NOT_FOUND; } } } return (ShellStatus); } /** Function to modify an option. @param[in] BcfgOperation Pointer to BCFG operation. @param[in] OrderCount The number if items in CurrentOrder. @retval SHELL_SUCCESS The operation was successful. @retval SHELL_INVALID_PARAMETER A parameter was invalid. @retval SHELL_OUT_OF_RESOUCES A memory allocation failed. **/ SHELL_STATUS BcfgMod ( IN CONST BGFG_OPERATION *BcfgOperation, IN CONST UINTN OrderCount ) { EFI_STATUS Status; EFI_HANDLE CurHandle; SHELL_STATUS ShellStatus; CHAR16 OptionStr[40]; EFI_SHELL_FILE_INFO *FileList; EFI_SHELL_FILE_INFO *Arg; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePathBuffer; EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker; EFI_BOOT_MANAGER_LOAD_OPTION LoadOption; ShellStatus = SHELL_SUCCESS; FileList = NULL; DevicePath = NULL; DevicePathBuffer = NULL; ZeroMem (&LoadOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); if (((BcfgOperation->Type == BcfgTypeMod) && (BcfgOperation->Description == NULL)) || ((BcfgOperation->Type == BcfgTypeModf) && (BcfgOperation->FileName == NULL)) || ((BcfgOperation->Type == BcfgTypeModp) && (BcfgOperation->FileName == NULL)) || ((BcfgOperation->Type == BcfgTypeModh) && (BcfgOperation->HandleIndex == 0)) || (BcfgOperation->Number1 > OrderCount) ) { return (SHELL_INVALID_PARAMETER); } if (BcfgOperation->Type == BcfgTypeModh) { CurHandle = ConvertHandleIndexToHandle (BcfgOperation->HandleIndex); ShellStatus = GetDevicePathByHandle (CurHandle, BcfgOperation->Target, &DevicePathBuffer); if (ShellStatus == SHELL_SUCCESS) { DevicePath = DuplicateDevicePath (DevicePathBuffer); } } else if ((BcfgOperation->Type == BcfgTypeModf) || (BcfgOperation->Type == BcfgTypeModp)) { // // Get Device Path by FileName. // ShellOpenFileMetaArg ((CHAR16 *)BcfgOperation->FileName, EFI_FILE_MODE_READ, &FileList); if (FileList == NULL) { // // The name of file matched nothing. // ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); ShellStatus = SHELL_INVALID_PARAMETER; } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) { // // If the name of file expanded to multiple names, it's fail. // ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); ShellStatus = SHELL_INVALID_PARAMETER; } else { Arg = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link); if (EFI_ERROR (Arg->Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName); ShellStatus = SHELL_INVALID_PARAMETER; } else { DevicePathBuffer = gEfiShellProtocol->GetDevicePathFromFilePath (Arg->FullName); if (DevicePathBuffer == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName); ShellStatus = SHELL_UNSUPPORTED; } } } if (ShellStatus == SHELL_SUCCESS) { if (BcfgOperation->Type == BcfgTypeModp) { ShellStatus = SHELL_INVALID_PARAMETER; DevicePathWalker = DevicePathBuffer; while (!IsDevicePathEnd (DevicePathWalker)) { if ((DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePathWalker) == MEDIA_HARDDRIVE_DP) ) { // // We found the portion of device path starting with the hard driver partition. // ShellStatus = SHELL_SUCCESS; DevicePath = DuplicateDevicePath (DevicePathWalker); break; } else { DevicePathWalker = NextDevicePathNode (DevicePathWalker); } } } else { DevicePath = DuplicateDevicePath (DevicePathBuffer); } FreePool (DevicePathBuffer); } } if (ShellStatus == SHELL_SUCCESS) { if (BcfgOperation->Target == BcfgTargetBootOrder) { UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Boot%04x", BcfgOperation->Order[BcfgOperation->Number1]); } else { UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Driver%04x", BcfgOperation->Order[BcfgOperation->Number1]); } Status = EfiBootManagerVariableToLoadOption (OptionStr, &LoadOption); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NONE), gShellBcfgHiiHandle); ShellStatus = SHELL_NOT_FOUND; } } if (ShellStatus == SHELL_SUCCESS) { if (BcfgOperation->Type == BcfgTypeMod) { SHELL_FREE_NON_NULL (LoadOption.Description); LoadOption.Description = AllocateCopyPool (StrSize (BcfgOperation->Description), BcfgOperation->Description); } else { SHELL_FREE_NON_NULL (LoadOption.FilePath); LoadOption.FilePath = DuplicateDevicePath (DevicePath); } Status = EfiBootManagerLoadOptionToVariable (&LoadOption); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr); ShellStatus = SHELL_INVALID_PARAMETER; } } EfiBootManagerFreeLoadOption (&LoadOption); if (DevicePath != NULL) { FreePool (DevicePath); } if (FileList != NULL) { ShellCloseFileMetaArg (&FileList); } return (ShellStatus); } /** Function to add a option. @param[in] Position The position to add Target at. @param[in] File The file to make the target. @param[in] Desc The description text. @param[in] CurrentOrder The pointer to the current order of items. @param[in] OrderCount The number if items in CurrentOrder. @param[in] Target The info on the option to add. @param[in] UseHandle TRUE to use HandleNumber, FALSE to use File and Desc. @param[in] UsePath TRUE to convert to devicepath. @param[in] HandleNumber The handle number to add. @retval SHELL_SUCCESS The operation was successful. @retval SHELL_INVALID_PARAMETER A parameter was invalid. **/ SHELL_STATUS BcfgAdd ( IN UINTN Position, IN CONST CHAR16 *File, IN CONST CHAR16 *Desc, IN CONST UINT16 *CurrentOrder, IN CONST UINTN OrderCount, IN CONST BCFG_OPERATION_TARGET Target, IN CONST BOOLEAN UseHandle, IN CONST BOOLEAN UsePath, IN CONST UINTN HandleNumber ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevPath; EFI_DEVICE_PATH_PROTOCOL *FilePath; CHAR16 *Str; UINT8 *TempByteBuffer; UINT8 *TempByteStart; EFI_SHELL_FILE_INFO *Arg; EFI_SHELL_FILE_INFO *FileList; CHAR16 OptionStr[40]; UINTN DescSize, FilePathSize; BOOLEAN Found; UINTN TargetLocation; UINTN Index; EFI_HANDLE *Handles; EFI_HANDLE CurHandle; UINTN DriverBindingHandleCount; UINTN ParentControllerHandleCount; UINTN ChildControllerHandleCount; SHELL_STATUS ShellStatus; UINT16 *NewOrder; if (!UseHandle) { if ((File == NULL) || (Desc == NULL)) { return (SHELL_INVALID_PARAMETER); } } else { if (HandleNumber == 0) { return (SHELL_INVALID_PARAMETER); } } if (Position > OrderCount) { Position = OrderCount; } Str = NULL; FilePath = NULL; FileList = NULL; Handles = NULL; ShellStatus = SHELL_SUCCESS; TargetLocation = 0xFFFF; if (UseHandle) { CurHandle = ConvertHandleIndexToHandle (HandleNumber); if (CurHandle == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); ShellStatus = SHELL_INVALID_PARAMETER; } else { if (Target == BcfgTargetBootOrder) { // // Make sure that the handle should point to a real controller // Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( CurHandle, &DriverBindingHandleCount, NULL ); Status = PARSE_HANDLE_DATABASE_PARENTS ( CurHandle, &ParentControllerHandleCount, NULL ); Status = ParseHandleDatabaseForChildControllers ( CurHandle, &ChildControllerHandleCount, NULL ); if ( (DriverBindingHandleCount > 0) || (ParentControllerHandleCount > 0) || (ChildControllerHandleCount > 0)) { FilePath = NULL; Status = gBS->HandleProtocol ( CurHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath ); } if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_HANDLE), gShellBcfgHiiHandle, L"bcfg", HandleNumber); ShellStatus = SHELL_INVALID_PARAMETER; } } else { // // Make sure that the handle should point to driver, not a controller. // Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( CurHandle, &DriverBindingHandleCount, NULL ); Status = PARSE_HANDLE_DATABASE_PARENTS ( CurHandle, &ParentControllerHandleCount, NULL ); Status = ParseHandleDatabaseForChildControllers ( CurHandle, &ChildControllerHandleCount, NULL ); Status = gBS->HandleProtocol ( CurHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath ); if ( (DriverBindingHandleCount > 0) || (ParentControllerHandleCount > 0) || (ChildControllerHandleCount > 0) || !EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number"); ShellStatus = SHELL_INVALID_PARAMETER; } else { // // Get the DevicePath from the loaded image information. // Status = GetDevicePathForDriverHandle (CurHandle, &FilePath); } } } } else { // // Get file info // ShellOpenFileMetaArg ((CHAR16 *)File, EFI_FILE_MODE_READ, &FileList); if (FileList == NULL) { // // If filename matched nothing fail // ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", File); ShellStatus = SHELL_INVALID_PARAMETER; } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) { // // If filename expanded to multiple names, fail // ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", File); ShellStatus = SHELL_INVALID_PARAMETER; } else { Arg = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link); if (EFI_ERROR (Arg->Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", File); ShellStatus = SHELL_INVALID_PARAMETER; } else { // // Build FilePath to the filename // // // get the device path // DevicePath = gEfiShellProtocol->GetDevicePathFromFilePath (Arg->FullName); if (DevicePath == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName); ShellStatus = SHELL_UNSUPPORTED; } else { if (UsePath) { DevPath = DevicePath; ShellStatus = SHELL_INVALID_PARAMETER; while (!IsDevicePathEnd (DevPath)) { if ((DevicePathType (DevPath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevPath) == MEDIA_HARDDRIVE_DP)) { // // If we find it use it instead // ShellStatus = SHELL_SUCCESS; FilePath = DuplicateDevicePath (DevPath); break; } DevPath = NextDevicePathNode (DevPath); } } else { FilePath = DuplicateDevicePath (DevicePath); } FreePool (DevicePath); } } } } if (ShellStatus == SHELL_SUCCESS) { // // Find a free target ,a brute force implementation // Found = FALSE; for (TargetLocation = 0; TargetLocation < 0xFFFF; TargetLocation++) { Found = TRUE; for (Index = 0; Index < OrderCount; Index++) { if (CurrentOrder[Index] == TargetLocation) { Found = FALSE; break; } } if (Found) { break; } } if (TargetLocation == 0xFFFF) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET_NF), gShellBcfgHiiHandle, L"bcfg"); } else { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET), gShellBcfgHiiHandle, TargetLocation); } } if (ShellStatus == SHELL_SUCCESS) { // // Add the option // DescSize = StrSize (Desc); FilePathSize = GetDevicePathSize (FilePath); TempByteBuffer = AllocateZeroPool (sizeof (UINT32) + sizeof (UINT16) + DescSize + FilePathSize); if (TempByteBuffer != NULL) { TempByteStart = TempByteBuffer; *((UINT32 *)TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes TempByteBuffer += sizeof (UINT32); *((UINT16 *)TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength TempByteBuffer += sizeof (UINT16); CopyMem (TempByteBuffer, Desc, DescSize); TempByteBuffer += DescSize; ASSERT (FilePath != NULL); CopyMem (TempByteBuffer, FilePath, FilePathSize); UnicodeSPrint (OptionStr, sizeof (OptionStr), L"%s%04x", Target == BcfgTargetBootOrder ? L"Boot" : L"Driver", TargetLocation); Status = gRT->SetVariable ( OptionStr, &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, sizeof (UINT32) + sizeof (UINT16) + DescSize + FilePathSize, TempByteStart ); FreePool (TempByteStart); } else { Status = EFI_OUT_OF_RESOURCES; } if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr); } else { NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (NewOrder[0])); if (NewOrder != NULL) { CopyMem (NewOrder, CurrentOrder, (OrderCount) * sizeof (NewOrder[0])); // // Insert target into order list // for (Index = OrderCount; Index > Position; Index--) { NewOrder[Index] = NewOrder[Index - 1]; } NewOrder[Position] = (UINT16)TargetLocation; Status = gRT->SetVariable ( Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, (OrderCount + 1) * sizeof (UINT16), NewOrder ); FreePool (NewOrder); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder"); ShellStatus = SHELL_INVALID_PARAMETER; } else { Print (L"bcfg: Add %s as %x\n", OptionStr, Position); } } } } // // If always Free FilePath, will free devicepath in system when use "addh" // if ((FilePath != NULL) && !UseHandle) { FreePool (FilePath); } if (Str != NULL) { FreePool (Str); } if (Handles != NULL) { FreePool (Handles); } if (FileList != NULL) { ShellCloseFileMetaArg (&FileList); } return (ShellStatus); } /** Funciton to remove an item. @param[in] Target The target item to move. @param[in] CurrentOrder The pointer to the current order of items. @param[in] OrderCount The number if items in CurrentOrder. @param[in] Location The current location of the Target. @retval SHELL_SUCCESS The operation was successful. @retval SHELL_INVALID_PARAMETER A parameter was invalid. **/ SHELL_STATUS BcfgRemove ( IN CONST BCFG_OPERATION_TARGET Target, IN CONST UINT16 *CurrentOrder, IN CONST UINTN OrderCount, IN CONST UINT16 Location ) { CHAR16 VariableName[12]; UINT16 *NewOrder; EFI_STATUS Status; UINTN NewCount; UnicodeSPrint (VariableName, sizeof (VariableName), L"%s%04x", Target == BcfgTargetBootOrder ? L"Boot" : L"Driver", CurrentOrder[Location]); Status = gRT->SetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL ); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); return (SHELL_INVALID_PARAMETER); } NewOrder = AllocateZeroPool (OrderCount*sizeof (CurrentOrder[0])); if (NewOrder != NULL) { NewCount = OrderCount; CopyMem (NewOrder, CurrentOrder, OrderCount*sizeof (CurrentOrder[0])); CopyMem (NewOrder+Location, NewOrder+Location+1, (OrderCount - Location - 1)*sizeof (CurrentOrder[0])); NewCount--; Status = gRT->SetVariable ( Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder", (EFI_GUID *)&gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, NewCount*sizeof (NewOrder[0]), NewOrder ); FreePool (NewOrder); } else { Status = EFI_OUT_OF_RESOURCES; } if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder"); return (SHELL_INVALID_PARAMETER); } return (SHELL_SUCCESS); } /** Funciton to move a item to another location. @param[in] Target The target item to move. @param[in] CurrentOrder The pointer to the current order of items. @param[in] OrderCount The number if items in CurrentOrder. @param[in] OldLocation The current location of the Target. @param[in] NewLocation The desired location of the Target. @retval SHELL_SUCCESS The operation was successful. @retval SHELL_INVALID_PARAMETER A parameter was invalid. **/ SHELL_STATUS BcfgMove ( IN CONST BCFG_OPERATION_TARGET Target, IN CONST UINT16 *CurrentOrder, IN CONST UINTN OrderCount, IN CONST UINT16 OldLocation, IN UINT16 NewLocation ) { UINT16 *NewOrder; EFI_STATUS Status; UINT16 Temp; NewOrder = AllocateCopyPool (OrderCount*sizeof (CurrentOrder[0]), CurrentOrder); if (NewOrder == NULL) { return (SHELL_OUT_OF_RESOURCES); } // // correct the new location // if (NewLocation >= OrderCount) { if (OrderCount > 0) { NewLocation = (UINT16)OrderCount - 1; } else { NewLocation = 0; } } Temp = CurrentOrder[OldLocation]; CopyMem (NewOrder+OldLocation, NewOrder+OldLocation+1, (OrderCount - OldLocation - 1)*sizeof (CurrentOrder[0])); CopyMem (NewOrder+NewLocation+1, NewOrder+NewLocation, (OrderCount - NewLocation - 1)*sizeof (CurrentOrder[0])); NewOrder[NewLocation] = Temp; Status = gRT->SetVariable ( Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder", (EFI_GUID *)&gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, OrderCount*sizeof (CurrentOrder[0]), NewOrder ); FreePool (NewOrder); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder"); return (SHELL_INVALID_PARAMETER); } return (SHELL_SUCCESS); } /** Function to add optional data to an option. @param[in] OptData The optional data to add. @param[in] CurrentOrder The pointer to the current order of items. @param[in] OrderCount The number if items in CurrentOrder. @param[in] Target The target of the operation. @retval SHELL_SUCCESS The operation was succesful. **/ SHELL_STATUS BcfgAddOpt ( IN CONST CHAR16 *OptData, IN CONST UINT16 *CurrentOrder, IN CONST UINTN OrderCount, IN CONST BCFG_OPERATION_TARGET Target ) { EFI_KEY_OPTION NewKeyOption; EFI_KEY_OPTION *KeyOptionBuffer; SHELL_STATUS ShellStatus; EFI_STATUS Status; UINT16 OptionIndex; UINT16 LoopCounter; UINT64 Intermediate; CONST CHAR16 *Temp; CONST CHAR16 *Walker; CHAR16 *FileName; CHAR16 *Temp2; CHAR16 *Data; UINT32 KeyIndex; CHAR16 VariableName[12]; VOID *VariableData; SHELL_FILE_HANDLE FileHandle; Status = EFI_SUCCESS; ShellStatus = SHELL_SUCCESS; Walker = OptData; FileName = NULL; Data = NULL; KeyOptionBuffer = NULL; VariableData = NULL; ZeroMem (&NewKeyOption, sizeof (EFI_KEY_OPTION)); ZeroMem (VariableName, sizeof (VariableName)); while (Walker[0] == L' ') { Walker++; } // // Get the index of the variable we are changing. // Status = ShellConvertStringToUint64 (Walker, &Intermediate, TRUE, TRUE); if (EFI_ERROR (Status) || (((UINT16)Intermediate) != Intermediate) || (StrStr (Walker, L" ") == NULL) || (((UINT16)Intermediate) > ((UINT16)OrderCount))) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index"); ShellStatus = SHELL_INVALID_PARAMETER; return (ShellStatus); } OptionIndex = (UINT16)Intermediate; Temp = StrStr (Walker, L" "); if (Temp != NULL) { Walker = Temp; } while (Walker[0] == L' ') { Walker++; } // // determine whether we have file with data, quote delimited information, or a hot-key // if (Walker[0] == L'\"') { // // quoted filename or quoted information. // Temp = StrStr (Walker+1, L"\""); if ((Temp == NULL) || (StrLen (Temp) != 1)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } else { FileName = StrnCatGrow (&FileName, NULL, Walker+1, 0); if (FileName == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_OUT_OF_RESOURCES; return (ShellStatus); } Temp2 = StrStr (FileName, L"\""); ASSERT (Temp2 != NULL); Temp2[0] = CHAR_NULL; Temp2++; if (StrLen (Temp2) > 0) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } if (EFI_ERROR (ShellFileExists (Walker))) { // // Not a file. must be misc information. // Data = FileName; FileName = NULL; } else { FileName = StrnCatGrow (&FileName, NULL, Walker, 0); } } } else { // // filename or hot key information. // if (StrStr (Walker, L" ") == NULL) { // // filename // if (EFI_ERROR (ShellFileExists (Walker))) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } else { FileName = StrnCatGrow (&FileName, NULL, Walker, 0); } } else { if (Target != BcfgTargetBootOrder) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_BOOT_ONLY), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } if (ShellStatus == SHELL_SUCCESS) { // // Get hot key information // Status = ShellConvertStringToUint64 (Walker, &Intermediate, FALSE, TRUE); if (EFI_ERROR (Status) || (((UINT32)Intermediate) != Intermediate) || (StrStr (Walker, L" ") == NULL)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } NewKeyOption.KeyData.PackedValue = (UINT32)Intermediate; Temp = StrStr (Walker, L" "); if (Temp != NULL) { Walker = Temp; } while (Walker[0] == L' ') { Walker++; } } if (ShellStatus == SHELL_SUCCESS) { // // Now we know how many EFI_INPUT_KEY structs we need to attach to the end of the EFI_KEY_OPTION struct. // Re-allocate with the added information. // KeyOptionBuffer = AllocatePool (sizeof (EFI_KEY_OPTION) + (sizeof (EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount)); if (KeyOptionBuffer == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_OUT_OF_RESOURCES; return ShellStatus; } CopyMem (KeyOptionBuffer, &NewKeyOption, sizeof (EFI_KEY_OPTION)); } for (LoopCounter = 0; ShellStatus == SHELL_SUCCESS && LoopCounter < NewKeyOption.KeyData.Options.InputKeyCount; LoopCounter++) { // // ScanCode // Status = ShellConvertStringToUint64 (Walker, &Intermediate, FALSE, TRUE); if (EFI_ERROR (Status) || (((UINT16)Intermediate) != Intermediate) || (StrStr (Walker, L" ") == NULL)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } ((EFI_INPUT_KEY *)(((UINT8 *)KeyOptionBuffer) + sizeof (EFI_KEY_OPTION)))[LoopCounter].ScanCode = (UINT16)Intermediate; Temp = StrStr (Walker, L" "); if (Temp != NULL) { Walker = Temp; } while (Walker[0] == L' ') { Walker++; } // // UnicodeChar // Status = ShellConvertStringToUint64 (Walker, &Intermediate, FALSE, TRUE); if (EFI_ERROR (Status) || (((UINT16)Intermediate) != Intermediate)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker); ShellStatus = SHELL_INVALID_PARAMETER; } ((EFI_INPUT_KEY *)(((UINT8 *)KeyOptionBuffer) + sizeof (EFI_KEY_OPTION)))[LoopCounter].UnicodeChar = (UINT16)Intermediate; Temp = StrStr (Walker, L" "); if (Temp != NULL) { Walker = Temp; } while (Walker[0] == L' ') { Walker++; } } if (ShellStatus == SHELL_SUCCESS) { // // Now do the BootOption / BootOptionCrc // ASSERT (OptionIndex <= OrderCount); KeyOptionBuffer->BootOption = CurrentOrder[OptionIndex]; Status = GetBootOptionCrc (&(KeyOptionBuffer->BootOptionCrc), KeyOptionBuffer->BootOption); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index"); ShellStatus = SHELL_INVALID_PARAMETER; } } if (ShellStatus == SHELL_SUCCESS) { for (Temp2 = NULL, KeyIndex = 0; KeyIndex <= 0xFFFF; KeyIndex++) { UnicodeSPrint (VariableName, sizeof (VariableName), L"Key%04x", KeyIndex); Status = GetEfiGlobalVariable2 (VariableName, &VariableData, NULL); if (Status == EFI_NOT_FOUND) { break; } if (!EFI_ERROR (Status)) { SHELL_FREE_NON_NULL (VariableData); } } if (KeyIndex <= 0xFFFF) { Status = gRT->SetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS, sizeof (EFI_KEY_OPTION) + (sizeof (EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount), KeyOptionBuffer ); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); ShellStatus = SHELL_INVALID_PARAMETER; } } else { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_NO_NUM), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } ASSERT (FileName == NULL && Data == NULL); } } } // // Shouldn't be possible to have have both. Neither is ok though. // ASSERT (FileName == NULL || Data == NULL); if ((ShellStatus == SHELL_SUCCESS) && ((FileName != NULL) || (Data != NULL))) { if (FileName != NULL) { // // Open the file and populate the data buffer. // Status = ShellOpenFileByName ( FileName, &FileHandle, EFI_FILE_MODE_READ, 0 ); if (!EFI_ERROR (Status)) { Status = ShellGetFileSize (FileHandle, &Intermediate); } Data = AllocateZeroPool ((UINTN)Intermediate); if (Data == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_OUT_OF_RESOURCES; } if (!EFI_ERROR (Status)) { Status = ShellReadFile (FileHandle, (UINTN *)&Intermediate, Data); } } else { Intermediate = StrSize (Data); } if (!EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS) && (Data != NULL)) { Status = UpdateOptionalData (CurrentOrder[OptionIndex], (UINTN)Intermediate, (UINT8 *)Data, Target); if (EFI_ERROR (Status)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); ShellStatus = SHELL_INVALID_PARAMETER; } } if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); ShellStatus = SHELL_INVALID_PARAMETER; } } SHELL_FREE_NON_NULL (Data); SHELL_FREE_NON_NULL (KeyOptionBuffer); SHELL_FREE_NON_NULL (FileName); return ShellStatus; } /** Function to dump the Bcfg information. @param[in] Op The operation. @param[in] OrderCount How many to dump. @param[in] CurrentOrder The pointer to the current order of items. @param[in] VerboseOutput TRUE for extra output. FALSE otherwise. @retval SHELL_SUCCESS The dump was successful. @retval SHELL_INVALID_PARAMETER A parameter was invalid. **/ SHELL_STATUS BcfgDisplayDump ( IN CONST CHAR16 *Op, IN CONST UINTN OrderCount, IN CONST UINT16 *CurrentOrder, IN CONST BOOLEAN VerboseOutput ) { EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; CHAR16 VariableName[12]; UINTN LoopVar; CHAR16 *DevPathString; VOID *FilePathList; UINTN Errors; EFI_LOAD_OPTION *LoadOption; CHAR16 *Description; UINTN DescriptionSize; UINTN OptionalDataOffset; if (OrderCount == 0) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NONE), gShellBcfgHiiHandle, L"bcfg"); return (SHELL_SUCCESS); } Errors = 0; for (LoopVar = 0; LoopVar < OrderCount; LoopVar++) { Buffer = NULL; BufferSize = 0; DevPathString = NULL; UnicodeSPrint (VariableName, sizeof (VariableName), L"%s%04x", Op, CurrentOrder[LoopVar]); Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &BufferSize, Buffer ); if (Status == EFI_BUFFER_TOO_SMALL) { Buffer = AllocateZeroPool (BufferSize); Status = gRT->GetVariable ( VariableName, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &BufferSize, Buffer ); } if (EFI_ERROR (Status) || (Buffer == NULL)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_READ_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName); ++Errors; goto Cleanup; } // // We expect the Attributes, FilePathListLength, and L'\0'-terminated // Description fields to be present. // if (BufferSize < sizeof *LoadOption + sizeof (CHAR16)) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_CORRUPT), gShellBcfgHiiHandle, L"bcfg", VariableName ); ++Errors; goto Cleanup; } LoadOption = (EFI_LOAD_OPTION *)Buffer; Description = (CHAR16 *)(Buffer + sizeof (EFI_LOAD_OPTION)); DescriptionSize = StrSize (Description); if (LoadOption->FilePathListLength != 0) { FilePathList = (UINT8 *)Description + DescriptionSize; DevPathString = ConvertDevicePathToText (FilePathList, TRUE, FALSE); } OptionalDataOffset = sizeof *LoadOption + DescriptionSize + LoadOption->FilePathListLength; ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_BCFG_LOAD_OPTIONS), gShellBcfgHiiHandle, LoopVar, VariableName, Description, DevPathString, OptionalDataOffset >= BufferSize ? L'N' : L'Y' ); if (VerboseOutput && (OptionalDataOffset < BufferSize)) { DumpHex ( 2, // Indent 0, // Offset (displayed) BufferSize - OptionalDataOffset, // DataSize Buffer + OptionalDataOffset // UserData ); } Cleanup: if (Buffer != NULL) { FreePool (Buffer); } if (DevPathString != NULL) { FreePool (DevPathString); } } return (Errors > 0) ? SHELL_INVALID_PARAMETER : SHELL_SUCCESS; } /** Function to initialize the BCFG operation structure. @param[in] Struct The stuct to initialize. **/ VOID InitBcfgStruct ( IN BGFG_OPERATION *Struct ) { ASSERT (Struct != NULL); Struct->Target = BcfgTargetMax; Struct->Type = BcfgTypeMax; Struct->Number1 = 0; Struct->Number2 = 0; Struct->HandleIndex = 0; Struct->FileName = NULL; Struct->Description = NULL; Struct->Order = NULL; Struct->OptData = NULL; } STATIC CONST SHELL_PARAM_ITEM ParamList[] = { { L"-v", TypeFlag }, { L"-opt", TypeMaxValue }, { NULL, TypeMax } }; /** Function for 'bcfg' command. @param[in] ImageHandle Handle to the Image (NULL if Internal). @param[in] SystemTable Pointer to the System Table (NULL if Internal). **/ SHELL_STATUS EFIAPI ShellCommandRunBcfg ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; LIST_ENTRY *Package; CHAR16 *ProblemParam; SHELL_STATUS ShellStatus; UINTN ParamNumber; CONST CHAR16 *CurrentParam; BGFG_OPERATION CurrentOperation; UINTN Length; UINT64 Intermediate; UINT16 Count; Length = 0; ProblemParam = NULL; Package = NULL; ShellStatus = SHELL_SUCCESS; InitBcfgStruct (&CurrentOperation); // // initialize the shell lib (we must be in non-auto-init...) // Status = ShellInitialize (); ASSERT_EFI_ERROR (Status); Status = CommandInit (); ASSERT_EFI_ERROR (Status); // // parse the command line // Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); if (EFI_ERROR (Status)) { if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellBcfgHiiHandle, L"bcfg", ProblemParam); FreePool (ProblemParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { ASSERT (FALSE); } } else { // // Read in if we are doing -OPT // if (ShellCommandLineGetFlag (Package, L"-opt")) { CurrentOperation.OptData = ShellCommandLineGetValue (Package, L"-opt"); if (CurrentOperation.OptData == NULL) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellBcfgHiiHandle, L"bcfg", L"-opt"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeOpt; } // // small block to read the target of the operation // if (((ShellCommandLineGetCount (Package) < 3) && (CurrentOperation.Type != BcfgTypeOpt)) || ((ShellCommandLineGetCount (Package) < 2) && (CurrentOperation.Type == BcfgTypeOpt)) ) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)ShellCommandLineGetRawValue (Package, 1), L"driver") == 0) { CurrentOperation.Target = BcfgTargetDriverOrder; } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)ShellCommandLineGetRawValue (Package, 1), L"boot") == 0) { CurrentOperation.Target = BcfgTargetBootOrder; } else { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_DRIVER_BOOT), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } // // Read in the boot or driver order environment variable (not needed for opt) // if ((ShellStatus == SHELL_SUCCESS) && (CurrentOperation.Target < BcfgTargetMax)) { Length = 0; Status = gRT->GetVariable ( CurrentOperation.Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder", (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &Length, CurrentOperation.Order ); if (Status == EFI_BUFFER_TOO_SMALL) { CurrentOperation.Order = AllocateZeroPool (Length+(4*sizeof (CurrentOperation.Order[0]))); if (CurrentOperation.Order == NULL) { ShellStatus = SHELL_OUT_OF_RESOURCES; } else { Status = gRT->GetVariable ( CurrentOperation.Target == BcfgTargetBootOrder ? (CHAR16 *)L"BootOrder" : (CHAR16 *)L"DriverOrder", (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &Length, CurrentOperation.Order ); } } } Count = (UINT16)(Length / sizeof (CurrentOperation.Order[0])); // // large block to read the type of operation and verify parameter types for the info. // if ((ShellStatus == SHELL_SUCCESS) && (CurrentOperation.Target < BcfgTargetMax)) { for (ParamNumber = 2; ParamNumber < ShellCommandLineGetCount (Package) && ShellStatus == SHELL_SUCCESS; ParamNumber++) { CurrentParam = ShellCommandLineGetRawValue (Package, ParamNumber); if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"dump") == 0) { CurrentOperation.Type = BcfgTypeDump; if (ShellCommandLineGetCount (Package) > 3) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } } else if (ShellCommandLineGetFlag (Package, L"-v")) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"-v (without dump)"); ShellStatus = SHELL_INVALID_PARAMETER; } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"add") == 0) { if ((ParamNumber + 3) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeAdd; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; ASSERT (CurrentOperation.FileName == NULL); CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); ASSERT (CurrentOperation.Description == NULL); CurrentOperation.Description = StrnCatGrow (&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"addp") == 0) { if ((ParamNumber + 3) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeAddp; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; ASSERT (CurrentOperation.FileName == NULL); CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); ASSERT (CurrentOperation.Description == NULL); CurrentOperation.Description = StrnCatGrow (&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"addh") == 0) { if ((ParamNumber + 3) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeAddh; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.HandleIndex = (UINT16)Intermediate; ASSERT (CurrentOperation.Description == NULL); CurrentOperation.Description = StrnCatGrow (&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"rm") == 0) { if ((ParamNumber + 1) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeRm; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"mv") == 0) { if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } CurrentOperation.Type = BcfgTypeMv; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number2 = (UINT16)Intermediate; } if ( (CurrentOperation.Number2 == CurrentOperation.Number1) || (CurrentOperation.Number2 >= Count) ) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"mod") == 0) { if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentOperation.Type = BcfgTypeMod; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { ASSERT (CurrentOperation.Description == NULL); CurrentOperation.Description = StrnCatGrow (&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"modf") == 0) { if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentOperation.Type = BcfgTypeModf; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { ASSERT (CurrentOperation.FileName == NULL); CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"modp") == 0) { if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentOperation.Type = BcfgTypeModp; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { ASSERT (CurrentOperation.FileName == NULL); CurrentOperation.FileName = StrnCatGrow (&CurrentOperation.FileName, NULL, ShellCommandLineGetRawValue (Package, ++ParamNumber), 0); } } } } else if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)CurrentParam, L"modh") == 0) { if ((ParamNumber + 2) >= ShellCommandLineGetCount (Package)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg"); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentOperation.Type = BcfgTypeModh; CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.Number1 = (UINT16)Intermediate; if (CurrentOperation.Number1 >= Count) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count); ShellStatus = SHELL_INVALID_PARAMETER; } else { CurrentParam = ShellCommandLineGetRawValue (Package, ++ParamNumber); if ((CurrentParam == NULL) || !ShellIsHexOrDecimalNumber (CurrentParam, TRUE, FALSE)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } else { Status = ShellConvertStringToUint64 (CurrentParam, &Intermediate, TRUE, FALSE); CurrentOperation.HandleIndex = (UINT16)Intermediate; } } } } } else { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam); ShellStatus = SHELL_INVALID_PARAMETER; } } } if ((ShellStatus == SHELL_SUCCESS) && (CurrentOperation.Target < BcfgTargetMax) && (CurrentOperation.Type < BcfgTypeMax)) { // // we have all the info. Do the work // switch (CurrentOperation.Type) { case BcfgTypeDump: ShellStatus = BcfgDisplayDump ( CurrentOperation.Target == BcfgTargetBootOrder ? L"Boot" : L"Driver", Count, CurrentOperation.Order, ShellCommandLineGetFlag (Package, L"-v") ); break; case BcfgTypeMv: ShellStatus = BcfgMove ( CurrentOperation.Target, CurrentOperation.Order, Count, CurrentOperation.Number1, CurrentOperation.Number2 ); break; case BcfgTypeRm: ShellStatus = BcfgRemove ( CurrentOperation.Target, CurrentOperation.Order, Count, CurrentOperation.Number1 ); break; case BcfgTypeAdd: case BcfgTypeAddp: case BcfgTypeAddh: ShellStatus = BcfgAdd ( CurrentOperation.Number1, CurrentOperation.FileName, CurrentOperation.Description == NULL ? L"" : CurrentOperation.Description, CurrentOperation.Order, Count, CurrentOperation.Target, (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddh), (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddp), CurrentOperation.HandleIndex ); break; case BcfgTypeMod: case BcfgTypeModf: case BcfgTypeModp: case BcfgTypeModh: ShellStatus = BcfgMod (&CurrentOperation, Count); break; case BcfgTypeOpt: ShellStatus = BcfgAddOpt ( CurrentOperation.OptData, CurrentOperation.Order, Count, CurrentOperation.Target ); break; default: ASSERT (FALSE); } } } if (Package != NULL) { ShellCommandLineFreeVarList (Package); } if (CurrentOperation.FileName != NULL) { FreePool (CurrentOperation.FileName); } if (CurrentOperation.Description != NULL) { FreePool (CurrentOperation.Description); } if (CurrentOperation.Order != NULL) { FreePool (CurrentOperation.Order); } return (ShellStatus); } /** Function to get the filename with help context if HII will not be used. @return The filename with help text in it. **/ CONST CHAR16 * EFIAPI ShellCommandGetManFileNameBcfg ( VOID ) { return (mFileName); } /** "Constructor" for the library. This will register the handler for the bcfg command. @param[in] ImageHandle the image handle of the process @param[in] SystemTable the EFI System Table pointer @param[in] Name the profile name to use @retval EFI_SUCCESS the shell command handlers were installed sucessfully @retval EFI_UNSUPPORTED the shell level required was not found. **/ EFI_STATUS EFIAPI BcfgLibraryRegisterBcfgCommand ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable, IN CONST CHAR16 *Name ) { if (gShellBcfgHiiHandle != NULL) { return (EFI_SUCCESS); } gShellBcfgHiiHandle = HiiAddPackages (&gShellBcfgHiiGuid, gImageHandle, UefiShellBcfgCommandLibStrings, NULL); if (gShellBcfgHiiHandle == NULL) { return (EFI_DEVICE_ERROR); } // // install our shell command handler // ShellCommandRegisterCommandName (L"bcfg", ShellCommandRunBcfg, ShellCommandGetManFileNameBcfg, 0, Name, FALSE, gShellBcfgHiiHandle, STRING_TOKEN (STR_GET_HELP_BCFG)); return (EFI_SUCCESS); } /** Destructor for the library. free any resources. @param ImageHandle The image handle of the process. @param SystemTable The EFI System Table pointer. **/ EFI_STATUS EFIAPI BcfgLibraryUnregisterBcfgCommand ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { if (gShellBcfgHiiHandle != NULL) { HiiRemovePackages (gShellBcfgHiiHandle); } gShellBcfgHiiHandle = NULL; return (EFI_SUCCESS); }