+/**\r
+ Functino to get Device Path by a handle.\r
+\r
+ @param[in] TheHandle Use it to get DevicePath.\r
+ @param[in] Target Boot option target.\r
+ @param[in, out] DevicePath On a sucessful return the device path to the handle.\r
+\r
+ @retval SHELL_INVALID_PARAMETER The handle was NULL.\r
+ @retval SHELL_NOT_FOUND Not found device path by handle.\r
+ @retval SHELL_SUCCESS Get device path successfully.\r
+**/\r
+SHELL_STATUS\r
+GetDevicePathByHandle(\r
+ IN EFI_HANDLE TheHandle,\r
+ IN BCFG_OPERATION_TARGET Target,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_STATUS ShellStatus;\r
+\r
+ UINTN DriverBindingHandleCount;\r
+ UINTN ParentControllerHandleCount;\r
+ UINTN ChildControllerHandleCount;\r
+\r
+ ShellStatus = SHELL_SUCCESS;\r
+\r
+ if (TheHandle == NULL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");\r
+ return SHELL_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (TheHandle, &DriverBindingHandleCount, NULL);\r
+ if (EFI_ERROR(Status)) {\r
+ DriverBindingHandleCount = 0;\r
+ }\r
+\r
+ Status = PARSE_HANDLE_DATABASE_PARENTS (TheHandle, &ParentControllerHandleCount, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ ParentControllerHandleCount = 0;\r
+ }\r
+\r
+ Status = ParseHandleDatabaseForChildControllers (TheHandle, &ChildControllerHandleCount, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ ChildControllerHandleCount = 0;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (TheHandle, &gEfiDevicePathProtocolGuid, (VOID**)DevicePath);\r
+\r
+ if ( DriverBindingHandleCount > 0 ||\r
+ ParentControllerHandleCount > 0 ||\r
+ ChildControllerHandleCount > 0 ||\r
+ !EFI_ERROR(Status)\r
+ ) {\r
+ //\r
+ // The handle points to a real controller which has a device path.\r
+ //\r
+ if (Target == BcfgTargetDriverOrder) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,STRING_TOKEN (STR_GEN_PARAM_INV),\r
+ gShellBcfgHiiHandle,\r
+ L"bcfg",\r
+ L"Handle should point to driver image."\r
+ );\r
+ ShellStatus = SHELL_NOT_FOUND;\r
+ }\r
+ } else {\r
+ //\r
+ // The handle points to a driver image.\r
+ //\r
+ if (Target == BcfgTargetBootOrder) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_GEN_PARAM_INV),\r
+ gShellBcfgHiiHandle,\r
+ L"bcfg",\r
+ L"Handle should point to controller."\r
+ );\r
+ ShellStatus = SHELL_NOT_FOUND;\r
+ } else {\r
+ if (EFI_ERROR (GetDevicePathForDriverHandle (TheHandle, DevicePath))) {\r
+ ShellStatus = SHELL_NOT_FOUND;\r
+ }\r
+ }\r
+ }\r
+\r
+ return (ShellStatus);\r
+}\r
+\r
+/**\r
+ Function to modify an option.\r
+\r
+ @param[in] BcfgOperation Pointer to BCFG operation.\r
+ @param[in] OrderCount The number if items in CurrentOrder.\r
+\r
+ @retval SHELL_SUCCESS The operation was successful.\r
+ @retval SHELL_INVALID_PARAMETER A parameter was invalid.\r
+ @retval SHELL_OUT_OF_RESOUCES A memory allocation failed.\r
+**/\r
+SHELL_STATUS\r
+BcfgMod (\r
+ IN CONST BGFG_OPERATION *BcfgOperation,\r
+ IN CONST UINTN OrderCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE CurHandle;\r
+ SHELL_STATUS ShellStatus;\r
+ CHAR16 OptionStr[40];\r
+ EFI_SHELL_FILE_INFO *FileList;\r
+ EFI_SHELL_FILE_INFO *Arg;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
+\r
+ ShellStatus = SHELL_SUCCESS;\r
+ FileList = NULL;\r
+ DevicePath = NULL;\r
+\r
+ ZeroMem (&LoadOption, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));\r
+\r
+ if ( (BcfgOperation->Type == BcfgTypeMod && BcfgOperation->Description == NULL) ||\r
+ (BcfgOperation->Type == BcfgTypeModf && BcfgOperation->FileName == NULL) ||\r
+ (BcfgOperation->Type == BcfgTypeModp && BcfgOperation->FileName == NULL) ||\r
+ (BcfgOperation->Type == BcfgTypeModh && BcfgOperation->HandleIndex == 0) ||\r
+ (BcfgOperation->Number1 > OrderCount)\r
+ ) {\r
+ return (SHELL_INVALID_PARAMETER);\r
+ }\r
+\r
+ if (BcfgOperation->Type == BcfgTypeModh) {\r
+ CurHandle = ConvertHandleIndexToHandle (BcfgOperation->HandleIndex);\r
+ ShellStatus = GetDevicePathByHandle (CurHandle, BcfgOperation->Target, &DevicePathBuffer);\r
+ if (ShellStatus == SHELL_SUCCESS) {\r
+ DevicePath = DuplicateDevicePath (DevicePathBuffer);\r
+ }\r
+ } else if (BcfgOperation->Type == BcfgTypeModf || BcfgOperation->Type == BcfgTypeModp) {\r
+ //\r
+ // Get Device Path by FileName.\r
+ //\r
+ ShellOpenFileMetaArg ((CHAR16 *)BcfgOperation->FileName, EFI_FILE_MODE_READ, &FileList);\r
+ if (FileList == NULL) {\r
+ //\r
+ // The name of file matched nothing.\r
+ //\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ }\r
+ else if (FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
+ //\r
+ // If the name of file expanded to multiple names, it's fail.\r
+ //\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ } else {\r
+ Arg = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link);\r
+ if (EFI_ERROR (Arg->Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", BcfgOperation->FileName);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ } else {\r
+ DevicePathBuffer = gEfiShellProtocol->GetDevicePathFromFilePath (Arg->FullName);\r
+ if (DevicePathBuffer == NULL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName);\r
+ ShellStatus = SHELL_UNSUPPORTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (ShellStatus == SHELL_SUCCESS) {\r
+ if (BcfgOperation->Type == BcfgTypeModp) {\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ DevicePathWalker = DevicePathBuffer;\r
+ while (!IsDevicePathEnd (DevicePathWalker)) {\r
+ if ( DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH &&\r
+ DevicePathSubType (DevicePathWalker) == MEDIA_HARDDRIVE_DP\r
+ ) {\r
+ //\r
+ // We found the portion of device path starting with the hard driver partition.\r
+ //\r
+ ShellStatus = SHELL_SUCCESS;\r
+ DevicePath = DuplicateDevicePath (DevicePathWalker);\r
+ break;\r
+ } else {\r
+ DevicePathWalker = NextDevicePathNode (DevicePathWalker);\r
+ }\r
+ }\r
+ } else {\r
+ DevicePath = DuplicateDevicePath (DevicePathBuffer);\r
+ }\r
+\r
+ FreePool (DevicePathBuffer);\r
+ }\r
+ }\r
+\r
+ if (ShellStatus == SHELL_SUCCESS) {\r
+ if (BcfgOperation->Target == BcfgTargetBootOrder) {\r
+ UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Boot%04x", BcfgOperation->Order[BcfgOperation->Number1]);\r
+ } else {\r
+ UnicodeSPrint (OptionStr, sizeof (OptionStr), L"Driver%04x", BcfgOperation->Order[BcfgOperation->Number1]);\r
+ }\r
+ Status = EfiBootManagerVariableToLoadOption (OptionStr, &LoadOption);\r
+ if (EFI_ERROR(Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_NONE), gShellBcfgHiiHandle);\r
+ ShellStatus = SHELL_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ if (ShellStatus == SHELL_SUCCESS) {\r
+ if (BcfgOperation->Type == BcfgTypeMod) {\r
+ SHELL_FREE_NON_NULL (LoadOption.Description);\r
+ LoadOption.Description = AllocateCopyPool (StrSize (BcfgOperation->Description), BcfgOperation->Description);\r
+ } else {\r
+ SHELL_FREE_NON_NULL (LoadOption.FilePath);\r
+ LoadOption.FilePath = DuplicateDevicePath (DevicePath);\r
+ }\r
+\r
+ Status = EfiBootManagerLoadOptionToVariable (&LoadOption);\r
+ if (EFI_ERROR(Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ EfiBootManagerFreeLoadOption (&LoadOption);\r
+\r
+ if (DevicePath != NULL) {\r
+ FreePool (DevicePath);\r
+ }\r
+\r
+ if (FileList != NULL) {\r
+ ShellCloseFileMetaArg (&FileList);\r
+ }\r
+\r
+ return (ShellStatus);\r
+}\r
+\r