mirror of https://github.com/acidanthera/audk.git
475 lines
13 KiB
C
475 lines
13 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.
|
|
*
|
|
* This program and the accompanying materials
|
|
* are licensed and made available under the terms and conditions of the BSD License
|
|
* which accompanies this distribution. The full text of the license may be found at
|
|
* http://opensource.org/licenses/bsd-license.php
|
|
*
|
|
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
*
|
|
**/
|
|
|
|
#include <Library/NetLib.h>
|
|
#include "BdsInternal.h"
|
|
|
|
EFI_STATUS
|
|
EditHIInputStr (
|
|
IN OUT CHAR16 *CmdLine,
|
|
IN UINTN MaxCmdLine
|
|
)
|
|
{
|
|
UINTN CmdLineIndex;
|
|
UINTN WaitIndex;
|
|
CHAR8 Char;
|
|
EFI_INPUT_KEY Key;
|
|
EFI_STATUS Status;
|
|
|
|
// The command line must be at least one character long
|
|
ASSERT (MaxCmdLine > 0);
|
|
|
|
// Ensure the last character of the buffer is the NULL character
|
|
CmdLine[MaxCmdLine - 1] = '\0';
|
|
|
|
Print (CmdLine);
|
|
|
|
// To prevent a buffer overflow, we only allow to enter (MaxCmdLine-1) characters
|
|
for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {
|
|
Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
// Unicode character is valid when Scancode is NUll
|
|
if (Key.ScanCode == SCAN_NULL) {
|
|
// Scan code is NUll, hence read Unicode character
|
|
Char = (CHAR8)Key.UnicodeChar;
|
|
} else {
|
|
Char = CHAR_NULL;
|
|
}
|
|
|
|
if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {
|
|
CmdLine[CmdLineIndex] = '\0';
|
|
Print (L"\r\n");
|
|
|
|
return EFI_SUCCESS;
|
|
} else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
|
|
if (CmdLineIndex != 0) {
|
|
CmdLineIndex--;
|
|
Print (L"\b \b");
|
|
}
|
|
} else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
} else if (CmdLineIndex < (MaxCmdLine-1)) {
|
|
CmdLine[CmdLineIndex++] = Key.UnicodeChar;
|
|
Print (L"%c", Key.UnicodeChar);
|
|
}
|
|
}
|
|
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
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
|
|
GetHIInputBoolean (
|
|
OUT BOOLEAN *Value
|
|
)
|
|
{
|
|
CHAR16 CmdBoolean[2];
|
|
EFI_STATUS Status;
|
|
|
|
while(1) {
|
|
Print (L"[y/n] ");
|
|
Status = GetHIInputStr (CmdBoolean, 2);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
} else if ((CmdBoolean[0] == L'y') || (CmdBoolean[0] == L'Y')) {
|
|
if (Value) *Value = TRUE;
|
|
return EFI_SUCCESS;
|
|
} else if ((CmdBoolean[0] == L'n') || (CmdBoolean[0] == L'N')) {
|
|
if (Value) *Value = FALSE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
HasFilePathEfiExtension (
|
|
IN CHAR16* FilePath
|
|
)
|
|
{
|
|
return (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".EFI") == 0) ||
|
|
(StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".efi") == 0);
|
|
}
|
|
|
|
// Return the last non end-type Device Path Node from a Device Path
|
|
EFI_DEVICE_PATH*
|
|
GetLastDevicePathNode (
|
|
IN EFI_DEVICE_PATH* DevicePath
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH* PrevDevicePathNode;
|
|
|
|
PrevDevicePathNode = DevicePath;
|
|
while (!IsDevicePathEndType (DevicePath)) {
|
|
PrevDevicePathNode = DevicePath;
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
return PrevDevicePathNode;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GenerateDeviceDescriptionName (
|
|
IN EFI_HANDLE Handle,
|
|
IN OUT CHAR16* Description
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
|
|
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
|
|
CHAR16* DriverName;
|
|
CHAR16* DevicePathTxt;
|
|
EFI_DEVICE_PATH* DevicePathNode;
|
|
|
|
ComponentName2Protocol = NULL;
|
|
Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
|
|
if (!EFI_ERROR(Status)) {
|
|
//TODO: Fixme. we must find the best langague
|
|
Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
|
|
if (!EFI_ERROR(Status)) {
|
|
StrnCpy (Description, DriverName, BOOT_DEVICE_DESCRIPTION_MAX);
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
// Use the lastest non null entry of the Device path as a description
|
|
Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Convert the last non end-type Device Path Node in text for the description
|
|
DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
|
|
Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
|
|
ASSERT_EFI_ERROR(Status);
|
|
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePathNode, TRUE, TRUE);
|
|
StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
|
|
FreePool (DevicePathTxt);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BdsStartBootOption (
|
|
IN CHAR16* BootOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BDS_LOAD_OPTION *BdsLoadOption;
|
|
|
|
Status = BootOptionFromLoadOptionVariable (BootOption, &BdsLoadOption);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = BootOptionStart (BdsLoadOption);
|
|
FreePool (BdsLoadOption);
|
|
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_NOT_STARTED;
|
|
}
|
|
} else {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
UINTN
|
|
GetUnalignedDevicePathSize (
|
|
IN EFI_DEVICE_PATH* DevicePath
|
|
)
|
|
{
|
|
UINTN Size;
|
|
EFI_DEVICE_PATH* AlignedDevicePath;
|
|
|
|
if ((UINTN)DevicePath & 0x1) {
|
|
AlignedDevicePath = DuplicateDevicePath (DevicePath);
|
|
Size = GetDevicePathSize (AlignedDevicePath);
|
|
FreePool (AlignedDevicePath);
|
|
} else {
|
|
Size = GetDevicePathSize (DevicePath);
|
|
}
|
|
return Size;
|
|
}
|
|
|
|
EFI_DEVICE_PATH*
|
|
GetAlignedDevicePath (
|
|
IN EFI_DEVICE_PATH* DevicePath
|
|
)
|
|
{
|
|
if ((UINTN)DevicePath & 0x1) {
|
|
return DuplicateDevicePath (DevicePath);
|
|
} else {
|
|
return DevicePath;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IsUnicodeString (
|
|
IN VOID* String
|
|
)
|
|
{
|
|
// We do not support NULL pointer
|
|
ASSERT (String != NULL);
|
|
|
|
if (*(CHAR16*)String < 0x100) {
|
|
//Note: We could get issue if the string is an empty Ascii string...
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to detect if the given string is an ASCII or Unicode string
|
|
*
|
|
* There are actually few limitation to this function but it is mainly to give
|
|
* a user friendly output.
|
|
*
|
|
* Some limitations:
|
|
* - it only supports unicode string that use ASCII character (< 0x100)
|
|
* - single character ASCII strings are interpreted as Unicode string
|
|
* - string cannot be longer than BOOT_DEVICE_OPTION_MAX characters and
|
|
* thus (BOOT_DEVICE_OPTION_MAX*2) bytes for an Unicode string and
|
|
* BOOT_DEVICE_OPTION_MAX bytes for an ASCII string.
|
|
*
|
|
* @param String Buffer that might contain a Unicode or Ascii string
|
|
* @param IsUnicode If not NULL this boolean value returns if the string is an
|
|
* ASCII or Unicode string.
|
|
*/
|
|
BOOLEAN
|
|
IsPrintableString (
|
|
IN VOID* String,
|
|
OUT BOOLEAN *IsUnicode
|
|
)
|
|
{
|
|
BOOLEAN UnicodeDetected;
|
|
BOOLEAN IsPrintable;
|
|
UINTN Index;
|
|
CHAR16 Character;
|
|
|
|
// We do not support NULL pointer
|
|
ASSERT (String != NULL);
|
|
|
|
// Test empty string
|
|
if (*(CHAR16*)String == L'\0') {
|
|
if (IsUnicode) {
|
|
*IsUnicode = TRUE;
|
|
}
|
|
return TRUE;
|
|
} else if (*(CHAR16*)String == '\0') {
|
|
if (IsUnicode) {
|
|
*IsUnicode = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Limitation: if the string is an ASCII single character string. This comparison
|
|
// will assume it is a Unicode string.
|
|
if (*(CHAR16*)String < 0x100) {
|
|
UnicodeDetected = TRUE;
|
|
} else {
|
|
UnicodeDetected = FALSE;
|
|
}
|
|
|
|
IsPrintable = FALSE;
|
|
for (Index = 0; Index < BOOT_DEVICE_OPTION_MAX; Index++) {
|
|
if (UnicodeDetected) {
|
|
Character = ((CHAR16*)String)[Index];
|
|
} else {
|
|
Character = ((CHAR8*)String)[Index];
|
|
}
|
|
|
|
if (Character == '\0') {
|
|
// End of the string
|
|
IsPrintable = TRUE;
|
|
break;
|
|
} else if ((Character < 0x20) || (Character > 0x7f)) {
|
|
// We only support the range of printable ASCII character
|
|
IsPrintable = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsPrintable && IsUnicode) {
|
|
*IsUnicode = UnicodeDetected;
|
|
}
|
|
|
|
return IsPrintable;
|
|
}
|