EFI_STATUS GetHIInputAscii ( IN OUT CHAR8 *CmdLine, IN UINTN MaxCmdLine ) { // For a new input just passed an empty string CmdLine[0] = '\0'; return EditHIInputAscii (CmdLine,MaxCmdLine); }
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; }