/** Edit an IPv4 address The function displays as a string following the "%d.%d.%d.%d" format the IPv4 address that is passed in and asks the user to modify it. If the resulting string defines a valid IPv4 address, the four bytes of the corresponding IPv4 address are extracted from the string and returned by the function. As long as the user does not define a valid IP address, he is asked for one. He can always escape by pressing ESC. @param[in ] EFI_IP_ADDRESS InIpAddr Input IPv4 address @param[out] EFI_IP_ADDRESS OutIpAddr Returned IPv4 address. Valid if and only if the returned value is equal to EFI_SUCCESS @retval EFI_SUCCESS Update completed @retval EFI_ABORTED Editing aborted by the user @retval EFI_INVALID_PARAMETER The string returned by the user is mal-formated @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to lack of resource **/ EFI_STATUS EditHIInputIP ( IN EFI_IP_ADDRESS *InIpAddr, OUT EFI_IP_ADDRESS *OutIpAddr ) { EFI_STATUS Status; CHAR16 CmdLine[48]; while (TRUE) { UnicodeSPrint ( CmdLine, 48, L"%d.%d.%d.%d", InIpAddr->v4.Addr[0], InIpAddr->v4.Addr[1], InIpAddr->v4.Addr[2], InIpAddr->v4.Addr[3] ); Status = EditHIInputStr (CmdLine, 48); if (EFI_ERROR (Status)) { return EFI_ABORTED; } Status = NetLibStrToIp4 (CmdLine, &OutIpAddr->v4); if (Status == EFI_INVALID_PARAMETER) { Print (L"Invalid address\n"); } else { return Status; } } }
EFI_STATUS BdsLoadOptionMemMapUpdateDevicePath ( IN EFI_DEVICE_PATH *OldDevicePath, IN CHAR16* FileName, OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath ) { EFI_STATUS Status; CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX]; CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX]; MEMMAP_DEVICE_PATH* EndingDevicePath; EFI_DEVICE_PATH* DevicePath; DevicePath = DuplicateDevicePath (OldDevicePath); EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath); Print(L"Starting Address of the %s: ", FileName); UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress); Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX); if (EFI_ERROR(Status)) { //return EFI_ABORTED; goto Exit; } Print(L"Ending Address of the %s: ", FileName); UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress); Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX); if (EFI_ERROR(Status)) { goto Exit; //return EFI_ABORTED; } EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress); EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress); Exit: if (EFI_ERROR(Status)) { FreePool(DevicePath); } else { *NewDevicePath = DevicePath; } return Status; }
EFI_STATUS BdsLoadOptionFileSystemUpdateDevicePath ( IN EFI_DEVICE_PATH *OldDevicePath, IN CHAR16* FileName, OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath ) { EFI_STATUS Status; CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; UINTN BootFilePathSize; FILEPATH_DEVICE_PATH* EndingDevicePath; FILEPATH_DEVICE_PATH* FilePathDevicePath; EFI_DEVICE_PATH* DevicePath; DevicePath = DuplicateDevicePath (OldDevicePath); EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath); Print(L"File path of the %s: ", FileName); StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX); Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); if (EFI_ERROR(Status)) { return Status; } BootFilePathSize = StrSize(BootFilePath); if (BootFilePathSize == 2) { *NewDevicePath = NULL; return EFI_NOT_FOUND; } // Create the FilePath Device Path node FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); if (NULL == FilePathDevicePath) { return EFI_INVALID_PARAMETER; } FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH; FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP; SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize); // Generate the new Device Path by replacing the last node by the updated node SetDevicePathEndNode (EndingDevicePath); *NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath); FreePool(DevicePath); return EFI_SUCCESS; }
EFI_STATUS GetHIInputStr ( IN OUT CHAR16 *CmdLine, IN UINTN MaxCmdLine ) { EFI_STATUS Status; // For a new input just passed an empty string CmdLine[0] = L'\0'; Status = EditHIInputStr (CmdLine, MaxCmdLine); return Status; }
EFI_STATUS GetHIInputInteger ( OUT UINTN *Integer ) { CHAR16 CmdLine[255]; EFI_STATUS Status; CmdLine[0] = '\0'; Status = EditHIInputStr (CmdLine, 255); if (!EFI_ERROR(Status)) { *Integer = StrDecimalToUintn (CmdLine); } return Status; }
EFI_STATUS EditHIInputAscii ( IN OUT CHAR8 *CmdLine, IN UINTN MaxCmdLine ) { CHAR16* Str; EFI_STATUS Status; Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16)); AsciiStrToUnicodeStr (CmdLine, Str); Status = EditHIInputStr (Str, MaxCmdLine); if (!EFI_ERROR(Status)) { UnicodeStrToAsciiStr (Str, CmdLine); } FreePool (Str); return Status; }
EFI_STATUS GetHIInputIP ( OUT EFI_IP_ADDRESS *Ip ) { CHAR16 CmdLine[255]; CHAR16 *Str; EFI_STATUS Status; CmdLine[0] = '\0'; Status = EditHIInputStr (CmdLine,255); if (!EFI_ERROR(Status)) { Str = CmdLine; Ip->v4.Addr[0] = (UINT8)StrDecimalToUintn (Str); Str = StrStr (Str, L"."); if (Str == NULL) { return EFI_INVALID_PARAMETER; } Ip->v4.Addr[1] = (UINT8)StrDecimalToUintn (++Str); Str = StrStr (Str, L"."); if (Str == NULL) { return EFI_INVALID_PARAMETER; } Ip->v4.Addr[2] = (UINT8)StrDecimalToUintn (++Str); Str = StrStr (Str, L"."); if (Str == NULL) { return EFI_INVALID_PARAMETER; } Ip->v4.Addr[3] = (UINT8)StrDecimalToUintn (++Str); } return Status; }
/** Get an IPv4 address The function asks the user for an IPv4 address. If the input string defines a valid IPv4 address, the four bytes of the corresponding IPv4 address are extracted from the string and returned by the function. As long as the user does not define a valid IP address, he is asked for one. He can always escape by pressing ESC. @param[out] EFI_IP_ADDRESS OutIpAddr Returned IPv4 address. Valid if and only if the returned value is equal to EFI_SUCCESS @retval EFI_SUCCESS Input completed @retval EFI_ABORTED Editing aborted by the user @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to lack of resource **/ EFI_STATUS GetHIInputIP ( OUT EFI_IP_ADDRESS *OutIpAddr ) { EFI_STATUS Status; CHAR16 CmdLine[48]; while (TRUE) { CmdLine[0] = '\0'; Status = EditHIInputStr (CmdLine, 48); if (EFI_ERROR (Status)) { return EFI_ABORTED; } Status = NetLibStrToIp4 (CmdLine, &OutIpAddr->v4); if (Status == EFI_INVALID_PARAMETER) { Print (L"Invalid address\n"); } else { return Status; } } }
/** Update the parameters of a TFTP boot option The function asks sequentially to update the IPv4 parameters as well as the boot file path, providing the previously set value if any. @param[in] OldDevicePath Current complete device path of the Tftp boot option. This has to be a valid complete Tftp boot option path. By complete, we mean that it is not only the Tftp specific end part built by the "BdsLoadOptionTftpCreateDevicePath()" function. This path is handled as read only. @param[in] FileName Description of the file the path is asked for @param[out] NewDevicePath Pointer to the new complete device path. @retval EFI_SUCCESS Update completed @retval EFI_ABORTED Update aborted by the user @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource **/ EFI_STATUS BdsLoadOptionTftpUpdateDevicePath ( IN EFI_DEVICE_PATH *OldDevicePath, IN CHAR16 *FileName, OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath; EFI_DEVICE_PATH *DevicePathNode; UINT8 *Ipv4NodePtr; IPv4_DEVICE_PATH Ipv4Node; BOOLEAN IsDHCP; EFI_IP_ADDRESS OldIp; EFI_IP_ADDRESS OldSubnetMask; EFI_IP_ADDRESS OldGatewayIp; EFI_IP_ADDRESS LocalIp; EFI_IP_ADDRESS SubnetMask; EFI_IP_ADDRESS GatewayIp; EFI_IP_ADDRESS RemoteIp; UINT8 *FileNodePtr; CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; UINTN PathSize; UINTN BootFilePathSize; FILEPATH_DEVICE_PATH *NewFilePathNode; Ipv4NodePtr = NULL; // // Make a copy of the complete device path that is made of : // the device path of the device that support the Simple Network protocol // followed by an IPv4 node (type IPv4_DEVICE_PATH), // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up // by an end node. The IPv6 case is not handled yet. // DevicePath = DuplicateDevicePath (OldDevicePath); if (DevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } // // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the // call to this function, we know that the device path ends with an IPv4 node // followed by a file path node and finally an end node. To get the address of // the last IPv4 node, we loop over the whole device path, noting down the // address of each encountered IPv4 node. // for (DevicePathNode = DevicePath; !IsDevicePathEnd (DevicePathNode); DevicePathNode = NextDevicePathNode (DevicePathNode)) { if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) { Ipv4NodePtr = (UINT8*)DevicePathNode; } } // Copy for alignment of the IPv4 node data CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH)); Print (L"Get the IP address from DHCP: "); Status = GetHIInputBoolean (&IsDHCP); if (EFI_ERROR (Status)) { goto ErrorExit; } if (!IsDHCP) { Print (L"Local static IP address: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldIp, &LocalIp); } else { Status = GetHIInputIP (&LocalIp); } if (EFI_ERROR (Status)) { goto ErrorExit; } Print (L"Get the network mask: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldSubnetMask.v4, &Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldSubnetMask, &SubnetMask); } else { Status = GetHIInputIP (&SubnetMask); } if (EFI_ERROR (Status)) { goto ErrorExit; } Print (L"Get the gateway IP address: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldGatewayIp.v4, &Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldGatewayIp, &GatewayIp); } else { Status = GetHIInputIP (&GatewayIp); } if (EFI_ERROR (Status)) { goto ErrorExit; } } Print (L"TFTP server IP address: "); // Copy remote IPv4 address into IPv4 or IPv6 union CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldIp, &RemoteIp); if (EFI_ERROR (Status)) { goto ErrorExit; } // Get the path of the boot file and its size in number of bytes FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH); BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH; // // Ask for update of the boot file path // do { // Copy for 2-byte alignment of the Unicode string CopyMem ( BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH, MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX) ); BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0'; Print (L"File path of the %s: ", FileName); Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); if (EFI_ERROR (Status)) { goto ErrorExit; } PathSize = StrSize (BootFilePath); if (PathSize > 2) { break; } // Empty string, give the user another try Print (L"Empty string - Invalid path\n"); } while (PathSize <= 2) ; // // Update the IPv4 node. IPv6 case not handled yet. // if (IsDHCP) { Ipv4Node.StaticIpAddress = FALSE; ZeroMem (&Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); ZeroMem (&Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); ZeroMem (&Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); } else { Ipv4Node.StaticIpAddress = TRUE; CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Ipv4Node.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Ipv4Node.GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS)); } CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH)); // // Create the new file path node // NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool ( SIZE_OF_FILEPATH_DEVICE_PATH + PathSize ); NewFilePathNode->Header.Type = MEDIA_DEVICE_PATH; NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP; SetDevicePathNodeLength ( NewFilePathNode, SIZE_OF_FILEPATH_DEVICE_PATH + PathSize ); CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize); // // Generate the new Device Path by replacing the file path node at address // "FileNodePtr" by the new one "NewFilePathNode" and return its address. // SetDevicePathEndNode (FileNodePtr); *NewDevicePath = AppendDevicePathNode ( DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode ); ErrorExit: if (DevicePath != NULL) { FreePool (DevicePath) ; } return Status; }
EFI_STATUS LinuxLoaderConfig ( IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage ) { EFI_STATUS Status; LINUX_LOADER_ACTION Choice; UINTN BootOrderSize; UINT16* BootOrder; UINTN BootOrderCount; UINTN Index; CHAR16 Description[MAX_ASCII_INPUT]; CHAR8 CmdLine[MAX_ASCII_INPUT]; CHAR16 Initrd[MAX_STR_INPUT]; UINT16 InitrdPathListLength; UINT16 CmdLineLength; BDS_LOAD_OPTION* BdsLoadOption; BDS_LOAD_OPTION** SupportedBdsLoadOptions; UINTN SupportedBdsLoadOptionCount; LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData; EFI_DEVICE_PATH* DevicePathRoot; Choice = (LINUX_LOADER_ACTION)0; SupportedBdsLoadOptions = NULL; SupportedBdsLoadOptionCount = 0; do { Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW); Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE); Print (L"Option: "); Status = GetHIInputInteger ((UINTN*)&Choice); if (Status == EFI_INVALID_PARAMETER) { Print (L"\n"); return Status; } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) { Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE); Status = EFI_INVALID_PARAMETER; } } while (EFI_ERROR(Status)); if (Choice == LINUX_LOADER_UPDATE) { // If no compatible entry then we just create a new entry Choice = LINUX_LOADER_NEW; // Scan the OptionalData of every entry for the correct signature Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder); if (!EFI_ERROR(Status)) { BootOrderCount = BootOrderSize / sizeof(UINT16); // Allocate an array to handle maximum number of supported Boot Entry SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount); SupportedBdsLoadOptionCount = 0; // Check if the signature is present in the list of the current Boot entries for (Index = 0; Index < BootOrderCount; Index++) { Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption); if (!EFI_ERROR(Status)) { if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) && (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) { SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption; Choice = LINUX_LOADER_UPDATE; } } } } FreePool (BootOrder); } if (Choice == LINUX_LOADER_NEW) { Description[0] = '\0'; CmdLine[0] = '\0'; Initrd[0] = '\0'; BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION)); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); ASSERT_EFI_ERROR(Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); Print(L"EFI OS Loader: %s\n",DevicePathTxt); FreePool(DevicePathTxt); DEBUG_CODE_END(); // // Fill the known fields of BdsLoadOption // BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT; // Get the full Device Path for this file Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot); ASSERT_EFI_ERROR(Status); BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath); BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList); } else { if (SupportedBdsLoadOptionCount > 1) { for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) { Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description); } do { Print (L"Update Boot Entry: "); Status = GetHIInputInteger ((UINTN*)&Choice); if (Status == EFI_INVALID_PARAMETER) { Print (L"\n"); return Status; } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) { Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount); Status = EFI_INVALID_PARAMETER; } } while (EFI_ERROR(Status)); BdsLoadOption = SupportedBdsLoadOptions[Choice-1]; } StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT); LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData; if (LinuxOptionalData->CmdLineLength > 0) { CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength); } else { CmdLine[0] = '\0'; } if (LinuxOptionalData->InitrdPathListLength > 0) { CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength); } else { Initrd[0] = L'\0'; } DEBUG((EFI_D_ERROR,"L\n")); } // Description Print (L"Description: "); Status = EditHIInputStr (Description, MAX_STR_INPUT); if (EFI_ERROR(Status)) { return Status; } if (StrLen (Description) == 0) { StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT); } BdsLoadOption->Description = Description; // CmdLine Print (L"Command Line: "); Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT); if (EFI_ERROR(Status)) { return Status; } // Initrd Print (L"Initrd name: "); Status = EditHIInputStr (Initrd, MAX_STR_INPUT); if (EFI_ERROR(Status)) { return Status; } CmdLineLength = AsciiStrLen (CmdLine); if (CmdLineLength > 0) { CmdLineLength += sizeof(CHAR8); } InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16); if (InitrdPathListLength > 0) { InitrdPathListLength += sizeof(CHAR16); } BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength; LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize); BdsLoadOption->OptionalData = LinuxOptionalData; LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE; LinuxOptionalData->CmdLineLength = CmdLineLength; LinuxOptionalData->InitrdPathListLength = InitrdPathListLength; if (CmdLineLength > 0) { CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength); } if (InitrdPathListLength > 0) { CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength); } // Create or Update the boot entry Status = BootOptionToLoadOptionVariable (BdsLoadOption); return Status; }
EFI_STATUS BootMenuUpdateBootOption ( IN LIST_ENTRY *BootOptionsList ) { EFI_STATUS Status; BDS_LOAD_OPTION_ENTRY *BootOptionEntry; BDS_LOAD_OPTION *BootOption; BDS_LOAD_OPTION_SUPPORT* DeviceSupport; ARM_BDS_LOADER_ARGUMENTS* BootArguments; CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX]; CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX]; CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX]; EFI_DEVICE_PATH *DevicePath; EFI_DEVICE_PATH *TempInitrdPath; ARM_BDS_LOADER_TYPE BootType; ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData; ARM_BDS_LINUX_ARGUMENTS* LinuxArguments; EFI_DEVICE_PATH *InitrdPathNodes; EFI_DEVICE_PATH *InitrdPath; UINTN InitrdSize; UINTN CmdLineSize; BOOLEAN InitrdSupport; UINT8* OptionalData; UINTN OptionalDataSize; BOOLEAN IsPrintable; BOOLEAN IsUnicode; DisplayBootOptions (BootOptionsList); Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry); if (EFI_ERROR (Status)) { return Status; } BootOption = BootOptionEntry->BdsLoadOption; // Get the device support for this Boot Option Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport); if (EFI_ERROR(Status)) { Print(L"Not possible to retrieve the supported device for the update\n"); return EFI_UNSUPPORTED; } Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } if (DeviceSupport->RequestBootType) { Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } } LoaderOptionalData = BootOption->OptionalData; if (LoaderOptionalData != NULL) { BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType)); } else { BootType = BDS_LOADER_EFI_APPLICATION; } if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) { LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments; CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Print(L"Keep the initrd: "); } else { Print(L"Add an initrd: "); } Status = GetHIInputBoolean (&InitrdSupport); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } if (InitrdSupport) { if (InitrdSize > 0) { // Case we update the initrd device path Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath); if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd Status = EFI_ABORTED; goto EXIT; } InitrdSize = GetDevicePathSize (InitrdPath); } else { // Case we create the initrd device path Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes); if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd Status = EFI_ABORTED; goto EXIT; } if (InitrdPathNodes != NULL) { // Duplicate Linux kernel Device Path TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList); // Replace Linux kernel Node by EndNode SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath)); // Append the Device Path to the selected device path InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes); FreePool (TempInitrdPath); // Free the InitrdPathNodes created by Support->CreateDevicePathNode() FreePool (InitrdPathNodes); if (InitrdPath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto EXIT; } InitrdSize = GetDevicePathSize (InitrdPath); } else { InitrdPath = NULL; } } } else { InitrdSize = 0; } Print(L"Arguments to pass to the binary: "); if (CmdLineSize > 0) { AsciiStrnCpy (CmdLine, (CONST CHAR8*)(LinuxArguments + 1), sizeof (CmdLine)); CmdLine[sizeof (CmdLine) - 1] = '\0'; } else { CmdLine[0] = '\0'; } Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } CmdLineSize = AsciiStrSize (CmdLine); OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize; BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize); BootArguments->LinuxArguments.CmdLineSize = CmdLineSize; BootArguments->LinuxArguments.InitrdSize = InitrdSize; CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize); CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize); OptionalData = (UINT8*)BootArguments; } else { Print (L"Arguments to pass to the EFI Application: "); if (BootOption->OptionalDataSize > 0) { IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode); if (IsPrintable) { // // The size in bytes of the string, final zero included, should // be equal to or at least lower than "BootOption->OptionalDataSize" // and the "IsPrintableString()" has already tested that the length // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX, // final '\0' included. We can thus copy the string for editing // using "CopyMem()". Furthermore, note that in the case of an Unicode // string "StrnCpy()" and "StrCpy()" can not be used to copy the // string because the data pointed to by "BootOption->OptionalData" // is not necessarily 2-byte aligned. // if (IsUnicode) { CopyMem ( UnicodeCmdLine, BootOption->OptionalData, MIN (sizeof (UnicodeCmdLine), BootOption->OptionalDataSize) ); } else { CopyMem ( CmdLine, BootOption->OptionalData, MIN (sizeof (CmdLine), BootOption->OptionalDataSize) ); } } } else { UnicodeCmdLine[0] = L'\0'; IsPrintable = TRUE; IsUnicode = TRUE; } // We do not request arguments for OptionalData that cannot be printed if (IsPrintable) { if (IsUnicode) { Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR (Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } OptionalData = (UINT8*)UnicodeCmdLine; OptionalDataSize = StrSize (UnicodeCmdLine); } else { Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR (Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } OptionalData = (UINT8*)CmdLine; OptionalDataSize = AsciiStrSize (CmdLine); } } else { // We keep the former OptionalData OptionalData = BootOption->OptionalData; OptionalDataSize = BootOption->OptionalDataSize; } } Print(L"Description for this new Entry: "); StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX); Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } // Update the entry Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize); FREE_DEVICE_PATH: FreePool (DevicePath); EXIT: if (Status == EFI_ABORTED) { Print(L"\n"); } return Status; }