]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BdsHelper.c
ArmVExpressPkg: restrict ArmVExpressSysConfigLib to SEC and DXE_DRIVER
[mirror_edk2.git] / ArmPlatformPkg / Bds / BdsHelper.c
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 BOOLEAN
260 HasFilePathEfiExtension (
261 IN CHAR16* FilePath
262 )
263 {
264 return (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".EFI") == 0) ||
265 (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".efi") == 0);
266 }
267
268 // Return the last non end-type Device Path Node from a Device Path
269 EFI_DEVICE_PATH*
270 GetLastDevicePathNode (
271 IN EFI_DEVICE_PATH* DevicePath
272 )
273 {
274 EFI_DEVICE_PATH* PrevDevicePathNode;
275
276 PrevDevicePathNode = DevicePath;
277 while (!IsDevicePathEndType (DevicePath)) {
278 PrevDevicePathNode = DevicePath;
279 DevicePath = NextDevicePathNode (DevicePath);
280 }
281
282 return PrevDevicePathNode;
283 }
284
285 EFI_STATUS
286 GenerateDeviceDescriptionName (
287 IN EFI_HANDLE Handle,
288 IN OUT CHAR16* Description
289 )
290 {
291 EFI_STATUS Status;
292 EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
293 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
294 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
295 CHAR16* DriverName;
296 CHAR16* DevicePathTxt;
297 EFI_DEVICE_PATH* DevicePathNode;
298
299 ComponentName2Protocol = NULL;
300 Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
301 if (!EFI_ERROR(Status)) {
302 //TODO: Fixme. we must find the best langague
303 Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
304 if (!EFI_ERROR(Status)) {
305 StrnCpy (Description, DriverName, BOOT_DEVICE_DESCRIPTION_MAX);
306 }
307 }
308
309 if (EFI_ERROR(Status)) {
310 // Use the lastest non null entry of the Device path as a description
311 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
312 if (EFI_ERROR(Status)) {
313 return Status;
314 }
315
316 // Convert the last non end-type Device Path Node in text for the description
317 DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
318 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
319 ASSERT_EFI_ERROR(Status);
320 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePathNode, TRUE, TRUE);
321 StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
322 FreePool (DevicePathTxt);
323 }
324
325 return EFI_SUCCESS;
326 }
327
328 EFI_STATUS
329 BdsStartBootOption (
330 IN CHAR16* BootOption
331 )
332 {
333 EFI_STATUS Status;
334 BDS_LOAD_OPTION *BdsLoadOption;
335
336 Status = BootOptionFromLoadOptionVariable (BootOption, &BdsLoadOption);
337 if (!EFI_ERROR(Status)) {
338 Status = BootOptionStart (BdsLoadOption);
339 FreePool (BdsLoadOption);
340
341 if (!EFI_ERROR(Status)) {
342 Status = EFI_SUCCESS;
343 } else {
344 Status = EFI_NOT_STARTED;
345 }
346 } else {
347 Status = EFI_NOT_FOUND;
348 }
349 return Status;
350 }
351
352 UINTN
353 GetUnalignedDevicePathSize (
354 IN EFI_DEVICE_PATH* DevicePath
355 )
356 {
357 UINTN Size;
358 EFI_DEVICE_PATH* AlignedDevicePath;
359
360 if ((UINTN)DevicePath & 0x1) {
361 AlignedDevicePath = DuplicateDevicePath (DevicePath);
362 Size = GetDevicePathSize (AlignedDevicePath);
363 FreePool (AlignedDevicePath);
364 } else {
365 Size = GetDevicePathSize (DevicePath);
366 }
367 return Size;
368 }
369
370 EFI_DEVICE_PATH*
371 GetAlignedDevicePath (
372 IN EFI_DEVICE_PATH* DevicePath
373 )
374 {
375 if ((UINTN)DevicePath & 0x1) {
376 return DuplicateDevicePath (DevicePath);
377 } else {
378 return DevicePath;
379 }
380 }
381
382 BOOLEAN
383 IsUnicodeString (
384 IN VOID* String
385 )
386 {
387 // We do not support NULL pointer
388 ASSERT (String != NULL);
389
390 if (*(CHAR16*)String < 0x100) {
391 //Note: We could get issue if the string is an empty Ascii string...
392 return TRUE;
393 } else {
394 return FALSE;
395 }
396 }
397
398 /*
399 * Try to detect if the given string is an ASCII or Unicode string
400 *
401 * There are actually few limitation to this function but it is mainly to give
402 * a user friendly output.
403 *
404 * Some limitations:
405 * - it only supports unicode string that use ASCII character (< 0x100)
406 * - single character ASCII strings are interpreted as Unicode string
407 * - string cannot be longer than BOOT_DEVICE_OPTION_MAX characters and
408 * thus (BOOT_DEVICE_OPTION_MAX*2) bytes for an Unicode string and
409 * BOOT_DEVICE_OPTION_MAX bytes for an ASCII string.
410 *
411 * @param String Buffer that might contain a Unicode or Ascii string
412 * @param IsUnicode If not NULL this boolean value returns if the string is an
413 * ASCII or Unicode string.
414 */
415 BOOLEAN
416 IsPrintableString (
417 IN VOID* String,
418 OUT BOOLEAN *IsUnicode
419 )
420 {
421 BOOLEAN UnicodeDetected;
422 BOOLEAN IsPrintable;
423 UINTN Index;
424 CHAR16 Character;
425
426 // We do not support NULL pointer
427 ASSERT (String != NULL);
428
429 // Test empty string
430 if (*(CHAR16*)String == L'\0') {
431 if (IsUnicode) {
432 *IsUnicode = TRUE;
433 }
434 return TRUE;
435 } else if (*(CHAR16*)String == '\0') {
436 if (IsUnicode) {
437 *IsUnicode = FALSE;
438 }
439 return TRUE;
440 }
441
442 // Limitation: if the string is an ASCII single character string. This comparison
443 // will assume it is a Unicode string.
444 if (*(CHAR16*)String < 0x100) {
445 UnicodeDetected = TRUE;
446 } else {
447 UnicodeDetected = FALSE;
448 }
449
450 IsPrintable = FALSE;
451 for (Index = 0; Index < BOOT_DEVICE_OPTION_MAX; Index++) {
452 if (UnicodeDetected) {
453 Character = ((CHAR16*)String)[Index];
454 } else {
455 Character = ((CHAR8*)String)[Index];
456 }
457
458 if (Character == '\0') {
459 // End of the string
460 IsPrintable = TRUE;
461 break;
462 } else if ((Character < 0x20) || (Character > 0x7f)) {
463 // We only support the range of printable ASCII character
464 IsPrintable = FALSE;
465 break;
466 }
467 }
468
469 if (IsPrintable && IsUnicode) {
470 *IsUnicode = UnicodeDetected;
471 }
472
473 return IsPrintable;
474 }