1 /** @file 2 * 3 * Copyright (c) 2011 - 2014, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include <Library/NetLib.h> 16 #include "BdsInternal.h" 17 18 EFI_STATUS 19 EditHIInputStr ( 20 IN OUT CHAR16 *CmdLine, 21 IN UINTN MaxCmdLine 22 ) 23 { 24 UINTN CmdLineIndex; 25 UINTN WaitIndex; 26 CHAR8 Char; 27 EFI_INPUT_KEY Key; 28 EFI_STATUS Status; 29 30 // The command line must be at least one character long 31 ASSERT (MaxCmdLine > 0); 32 33 // Ensure the last character of the buffer is the NULL character 34 CmdLine[MaxCmdLine - 1] = '\0'; 35 36 Print (CmdLine); 37 38 // To prevent a buffer overflow, we only allow to enter (MaxCmdLine-1) characters 39 for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) { 40 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex); 41 ASSERT_EFI_ERROR (Status); 42 43 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 44 ASSERT_EFI_ERROR (Status); 45 46 // Unicode character is valid when Scancode is NUll 47 if (Key.ScanCode == SCAN_NULL) { 48 // Scan code is NUll, hence read Unicode character 49 Char = (CHAR8)Key.UnicodeChar; 50 } else { 51 Char = CHAR_NULL; 52 } 53 54 if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) { 55 CmdLine[CmdLineIndex] = '\0'; 56 Print (L"\r\n"); 57 58 return EFI_SUCCESS; 59 } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){ 60 if (CmdLineIndex != 0) { 61 CmdLineIndex--; 62 Print (L"\b \b"); 63 } 64 } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) { 65 return EFI_INVALID_PARAMETER; 66 } else if (CmdLineIndex < (MaxCmdLine-1)) { 67 CmdLine[CmdLineIndex++] = Key.UnicodeChar; 68 Print (L"%c", Key.UnicodeChar); 69 } 70 } 71 72 return EFI_SUCCESS; 73 } 74 75 EFI_STATUS 76 GetHIInputStr ( 77 IN OUT CHAR16 *CmdLine, 78 IN UINTN MaxCmdLine 79 ) 80 { 81 EFI_STATUS Status; 82 83 // For a new input just passed an empty string 84 CmdLine[0] = L'\0'; 85 86 Status = EditHIInputStr (CmdLine, MaxCmdLine); 87 88 return Status; 89 } 90 91 EFI_STATUS 92 EditHIInputAscii ( 93 IN OUT CHAR8 *CmdLine, 94 IN UINTN MaxCmdLine 95 ) 96 { 97 CHAR16* Str; 98 EFI_STATUS Status; 99 100 Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16)); 101 AsciiStrToUnicodeStr (CmdLine, Str); 102 103 Status = EditHIInputStr (Str, MaxCmdLine); 104 if (!EFI_ERROR(Status)) { 105 UnicodeStrToAsciiStr (Str, CmdLine); 106 } 107 FreePool (Str); 108 109 return Status; 110 } 111 112 EFI_STATUS 113 GetHIInputAscii ( 114 IN OUT CHAR8 *CmdLine, 115 IN UINTN MaxCmdLine 116 ) 117 { 118 // For a new input just passed an empty string 119 CmdLine[0] = '\0'; 120 121 return EditHIInputAscii (CmdLine,MaxCmdLine); 122 } 123 124 EFI_STATUS 125 GetHIInputInteger ( 126 OUT UINTN *Integer 127 ) 128 { 129 CHAR16 CmdLine[255]; 130 EFI_STATUS Status; 131 132 CmdLine[0] = '\0'; 133 Status = EditHIInputStr (CmdLine, 255); 134 if (!EFI_ERROR(Status)) { 135 *Integer = StrDecimalToUintn (CmdLine); 136 } 137 138 return Status; 139 } 140 141 /** 142 Get an IPv4 address 143 144 The function asks the user for an IPv4 address. If the input 145 string defines a valid IPv4 address, the four bytes of the 146 corresponding IPv4 address are extracted from the string and returned by 147 the function. As long as the user does not define a valid IP 148 address, he is asked for one. He can always escape by 149 pressing ESC. 150 151 @param[out] EFI_IP_ADDRESS OutIpAddr Returned IPv4 address. Valid if 152 and only if the returned value 153 is equal to EFI_SUCCESS 154 155 @retval EFI_SUCCESS Input completed 156 @retval EFI_ABORTED Editing aborted by the user 157 @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to 158 lack of resource 159 **/ 160 EFI_STATUS 161 GetHIInputIP ( 162 OUT EFI_IP_ADDRESS *OutIpAddr 163 ) 164 { 165 EFI_STATUS Status; 166 CHAR16 CmdLine[48]; 167 168 while (TRUE) { 169 CmdLine[0] = '\0'; 170 Status = EditHIInputStr (CmdLine, 48); 171 if (EFI_ERROR (Status)) { 172 return EFI_ABORTED; 173 } 174 175 Status = NetLibStrToIp4 (CmdLine, &OutIpAddr->v4); 176 if (Status == EFI_INVALID_PARAMETER) { 177 Print (L"Invalid address\n"); 178 } else { 179 return Status; 180 } 181 } 182 } 183 184 /** 185 Edit an IPv4 address 186 187 The function displays as a string following the "%d.%d.%d.%d" format the 188 IPv4 address that is passed in and asks the user to modify it. If the 189 resulting string defines a valid IPv4 address, the four bytes of the 190 corresponding IPv4 address are extracted from the string and returned by 191 the function. As long as the user does not define a valid IP 192 address, he is asked for one. He can always escape by 193 pressing ESC. 194 195 @param[in ] EFI_IP_ADDRESS InIpAddr Input IPv4 address 196 @param[out] EFI_IP_ADDRESS OutIpAddr Returned IPv4 address. Valid if 197 and only if the returned value 198 is equal to EFI_SUCCESS 199 200 @retval EFI_SUCCESS Update completed 201 @retval EFI_ABORTED Editing aborted by the user 202 @retval EFI_INVALID_PARAMETER The string returned by the user is 203 mal-formated 204 @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to 205 lack of resource 206 **/ 207 EFI_STATUS 208 EditHIInputIP ( 209 IN EFI_IP_ADDRESS *InIpAddr, 210 OUT EFI_IP_ADDRESS *OutIpAddr 211 ) 212 { 213 EFI_STATUS Status; 214 CHAR16 CmdLine[48]; 215 216 while (TRUE) { 217 UnicodeSPrint ( 218 CmdLine, 48, L"%d.%d.%d.%d", 219 InIpAddr->v4.Addr[0], InIpAddr->v4.Addr[1], 220 InIpAddr->v4.Addr[2], InIpAddr->v4.Addr[3] 221 ); 222 223 Status = EditHIInputStr (CmdLine, 48); 224 if (EFI_ERROR (Status)) { 225 return EFI_ABORTED; 226 } 227 Status = NetLibStrToIp4 (CmdLine, &OutIpAddr->v4); 228 if (Status == EFI_INVALID_PARAMETER) { 229 Print (L"Invalid address\n"); 230 } else { 231 return Status; 232 } 233 } 234 } 235 236 EFI_STATUS 237 GetHIInputBoolean ( 238 OUT BOOLEAN *Value 239 ) 240 { 241 CHAR16 CmdBoolean[2]; 242 EFI_STATUS Status; 243 244 while(1) { 245 Print (L"[y/n] "); 246 Status = GetHIInputStr (CmdBoolean, 2); 247 if (EFI_ERROR(Status)) { 248 return Status; 249 } else if ((CmdBoolean[0] == L'y') || (CmdBoolean[0] == L'Y')) { 250 if (Value) *Value = TRUE; 251 return EFI_SUCCESS; 252 } else if ((CmdBoolean[0] == L'n') || (CmdBoolean[0] == L'N')) { 253 if (Value) *Value = FALSE; 254 return EFI_SUCCESS; 255 } 256 } 257 } 258 259 // Return the last non end-type Device Path Node from a Device Path 260 EFI_DEVICE_PATH* 261 GetLastDevicePathNode ( 262 IN EFI_DEVICE_PATH* DevicePath 263 ) 264 { 265 EFI_DEVICE_PATH* PrevDevicePathNode; 266 267 PrevDevicePathNode = DevicePath; 268 while (!IsDevicePathEndType (DevicePath)) { 269 PrevDevicePathNode = DevicePath; 270 DevicePath = NextDevicePathNode (DevicePath); 271 } 272 273 return PrevDevicePathNode; 274 } 275 276 EFI_STATUS 277 GenerateDeviceDescriptionName ( 278 IN EFI_HANDLE Handle, 279 IN OUT CHAR16* Description 280 ) 281 { 282 EFI_STATUS Status; 283 EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol; 284 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; 285 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; 286 CHAR16* DriverName; 287 CHAR16* DevicePathTxt; 288 EFI_DEVICE_PATH* DevicePathNode; 289 290 ComponentName2Protocol = NULL; 291 Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol); 292 if (!EFI_ERROR(Status)) { 293 //TODO: Fixme. we must find the best langague 294 Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName); 295 if (!EFI_ERROR(Status)) { 296 StrnCpy (Description, DriverName, BOOT_DEVICE_DESCRIPTION_MAX); 297 } 298 } 299 300 if (EFI_ERROR(Status)) { 301 // Use the lastest non null entry of the Device path as a description 302 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); 303 if (EFI_ERROR(Status)) { 304 return Status; 305 } 306 307 // Convert the last non end-type Device Path Node in text for the description 308 DevicePathNode = GetLastDevicePathNode (DevicePathProtocol); 309 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); 310 ASSERT_EFI_ERROR(Status); 311 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePathNode, TRUE, TRUE); 312 StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX); 313 FreePool (DevicePathTxt); 314 } 315 316 return EFI_SUCCESS; 317 } 318 319 EFI_STATUS 320 BdsStartBootOption ( 321 IN CHAR16* BootOption 322 ) 323 { 324 EFI_STATUS Status; 325 BDS_LOAD_OPTION *BdsLoadOption; 326 327 Status = BootOptionFromLoadOptionVariable (BootOption, &BdsLoadOption); 328 if (!EFI_ERROR(Status)) { 329 Status = BootOptionStart (BdsLoadOption); 330 FreePool (BdsLoadOption); 331 332 if (!EFI_ERROR(Status)) { 333 Status = EFI_SUCCESS; 334 } else { 335 Status = EFI_NOT_STARTED; 336 } 337 } else { 338 Status = EFI_NOT_FOUND; 339 } 340 return Status; 341 } 342 343 UINTN 344 GetUnalignedDevicePathSize ( 345 IN EFI_DEVICE_PATH* DevicePath 346 ) 347 { 348 UINTN Size; 349 EFI_DEVICE_PATH* AlignedDevicePath; 350 351 if ((UINTN)DevicePath & 0x1) { 352 AlignedDevicePath = DuplicateDevicePath (DevicePath); 353 Size = GetDevicePathSize (AlignedDevicePath); 354 FreePool (AlignedDevicePath); 355 } else { 356 Size = GetDevicePathSize (DevicePath); 357 } 358 return Size; 359 } 360 361 EFI_DEVICE_PATH* 362 GetAlignedDevicePath ( 363 IN EFI_DEVICE_PATH* DevicePath 364 ) 365 { 366 if ((UINTN)DevicePath & 0x1) { 367 return DuplicateDevicePath (DevicePath); 368 } else { 369 return DevicePath; 370 } 371 } 372 373 BOOLEAN 374 IsUnicodeString ( 375 IN VOID* String 376 ) 377 { 378 // We do not support NULL pointer 379 ASSERT (String != NULL); 380 381 if (*(CHAR16*)String < 0x100) { 382 //Note: We could get issue if the string is an empty Ascii string... 383 return TRUE; 384 } else { 385 return FALSE; 386 } 387 } 388 389 /* 390 * Try to detect if the given string is an ASCII or Unicode string 391 * 392 * There are actually few limitation to this function but it is mainly to give 393 * a user friendly output. 394 * 395 * Some limitations: 396 * - it only supports unicode string that use ASCII character (< 0x100) 397 * - single character ASCII strings are interpreted as Unicode string 398 * - string cannot be longer than BOOT_DEVICE_OPTION_MAX characters and 399 * thus (BOOT_DEVICE_OPTION_MAX*2) bytes for an Unicode string and 400 * BOOT_DEVICE_OPTION_MAX bytes for an ASCII string. 401 * 402 * @param String Buffer that might contain a Unicode or Ascii string 403 * @param IsUnicode If not NULL this boolean value returns if the string is an 404 * ASCII or Unicode string. 405 */ 406 BOOLEAN 407 IsPrintableString ( 408 IN VOID* String, 409 OUT BOOLEAN *IsUnicode 410 ) 411 { 412 BOOLEAN UnicodeDetected; 413 BOOLEAN IsPrintable; 414 UINTN Index; 415 CHAR16 Character; 416 417 // We do not support NULL pointer 418 ASSERT (String != NULL); 419 420 // Test empty string 421 if (*(CHAR16*)String == L'\0') { 422 if (IsUnicode) { 423 *IsUnicode = TRUE; 424 } 425 return TRUE; 426 } else if (*(CHAR16*)String == '\0') { 427 if (IsUnicode) { 428 *IsUnicode = FALSE; 429 } 430 return TRUE; 431 } 432 433 // Limitation: if the string is an ASCII single character string. This comparison 434 // will assume it is a Unicode string. 435 if (*(CHAR16*)String < 0x100) { 436 UnicodeDetected = TRUE; 437 } else { 438 UnicodeDetected = FALSE; 439 } 440 441 IsPrintable = FALSE; 442 for (Index = 0; Index < BOOT_DEVICE_OPTION_MAX; Index++) { 443 if (UnicodeDetected) { 444 Character = ((CHAR16*)String)[Index]; 445 } else { 446 Character = ((CHAR8*)String)[Index]; 447 } 448 449 if (Character == '\0') { 450 // End of the string 451 IsPrintable = TRUE; 452 break; 453 } else if ((Character < 0x20) || (Character > 0x7f)) { 454 // We only support the range of printable ASCII character 455 IsPrintable = FALSE; 456 break; 457 } 458 } 459 460 if (IsPrintable && IsUnicode) { 461 *IsUnicode = UnicodeDetected; 462 } 463 464 return IsPrintable; 465 } 466