/** @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; | |
} |