Esempio n. 1
0
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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}