]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BdsHelper.c
ArmPlatformPkg/Bds: Introduced helper function to detect if an Ascii/Unicode string...
[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 "BdsInternal.h"
16
17 EFI_STATUS
18 EditHIInputStr (
19 IN OUT CHAR16 *CmdLine,
20 IN UINTN MaxCmdLine
21 )
22 {
23 UINTN CmdLineIndex;
24 UINTN WaitIndex;
25 CHAR8 Char;
26 EFI_INPUT_KEY Key;
27 EFI_STATUS Status;
28
29 // The command line must be at least one character long
30 ASSERT (MaxCmdLine > 0);
31
32 // Ensure the last character of the buffer is the NULL character
33 CmdLine[MaxCmdLine - 1] = '\0';
34
35 Print (CmdLine);
36
37 // To prevent a buffer overflow, we only allow to enter (MaxCmdLine-1) characters
38 for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {
39 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
40 ASSERT_EFI_ERROR (Status);
41
42 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
43 ASSERT_EFI_ERROR (Status);
44
45 // Unicode character is valid when Scancode is NUll
46 if (Key.ScanCode == SCAN_NULL) {
47 // Scan code is NUll, hence read Unicode character
48 Char = (CHAR8)Key.UnicodeChar;
49 } else {
50 Char = CHAR_NULL;
51 }
52
53 if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {
54 CmdLine[CmdLineIndex] = '\0';
55 Print (L"\r\n");
56
57 return EFI_SUCCESS;
58 } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
59 if (CmdLineIndex != 0) {
60 CmdLineIndex--;
61 Print (L"\b \b");
62 }
63 } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {
64 return EFI_INVALID_PARAMETER;
65 } else if (CmdLineIndex < (MaxCmdLine-1)) {
66 CmdLine[CmdLineIndex++] = Key.UnicodeChar;
67 Print (L"%c", Key.UnicodeChar);
68 }
69 }
70
71 return EFI_SUCCESS;
72 }
73
74 EFI_STATUS
75 GetHIInputStr (
76 IN OUT CHAR16 *CmdLine,
77 IN UINTN MaxCmdLine
78 )
79 {
80 EFI_STATUS Status;
81
82 // For a new input just passed an empty string
83 CmdLine[0] = L'\0';
84
85 Status = EditHIInputStr (CmdLine, MaxCmdLine);
86
87 return Status;
88 }
89
90 EFI_STATUS
91 EditHIInputAscii (
92 IN OUT CHAR8 *CmdLine,
93 IN UINTN MaxCmdLine
94 )
95 {
96 CHAR16* Str;
97 EFI_STATUS Status;
98
99 Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16));
100 AsciiStrToUnicodeStr (CmdLine, Str);
101
102 Status = EditHIInputStr (Str, MaxCmdLine);
103 if (!EFI_ERROR(Status)) {
104 UnicodeStrToAsciiStr (Str, CmdLine);
105 }
106 FreePool (Str);
107
108 return Status;
109 }
110
111 EFI_STATUS
112 GetHIInputAscii (
113 IN OUT CHAR8 *CmdLine,
114 IN UINTN MaxCmdLine
115 )
116 {
117 // For a new input just passed an empty string
118 CmdLine[0] = '\0';
119
120 return EditHIInputAscii (CmdLine,MaxCmdLine);
121 }
122
123 EFI_STATUS
124 GetHIInputInteger (
125 OUT UINTN *Integer
126 )
127 {
128 CHAR16 CmdLine[255];
129 EFI_STATUS Status;
130
131 CmdLine[0] = '\0';
132 Status = EditHIInputStr (CmdLine, 255);
133 if (!EFI_ERROR(Status)) {
134 *Integer = StrDecimalToUintn (CmdLine);
135 }
136
137 return Status;
138 }
139
140 EFI_STATUS
141 GetHIInputIP (
142 OUT EFI_IP_ADDRESS *Ip
143 )
144 {
145 CHAR16 CmdLine[255];
146 CHAR16 *Str;
147 EFI_STATUS Status;
148
149 CmdLine[0] = '\0';
150 Status = EditHIInputStr (CmdLine,255);
151 if (!EFI_ERROR(Status)) {
152 Str = CmdLine;
153 Ip->v4.Addr[0] = (UINT8)StrDecimalToUintn (Str);
154
155 Str = StrStr (Str, L".");
156 if (Str == NULL) {
157 return EFI_INVALID_PARAMETER;
158 }
159
160 Ip->v4.Addr[1] = (UINT8)StrDecimalToUintn (++Str);
161
162 Str = StrStr (Str, L".");
163 if (Str == NULL) {
164 return EFI_INVALID_PARAMETER;
165 }
166
167 Ip->v4.Addr[2] = (UINT8)StrDecimalToUintn (++Str);
168
169 Str = StrStr (Str, L".");
170 if (Str == NULL) {
171 return EFI_INVALID_PARAMETER;
172 }
173
174 Ip->v4.Addr[3] = (UINT8)StrDecimalToUintn (++Str);
175 }
176
177 return Status;
178 }
179
180 EFI_STATUS
181 GetHIInputBoolean (
182 OUT BOOLEAN *Value
183 )
184 {
185 CHAR16 CmdBoolean[2];
186 EFI_STATUS Status;
187
188 while(1) {
189 Print (L"[y/n] ");
190 Status = GetHIInputStr (CmdBoolean, 2);
191 if (EFI_ERROR(Status)) {
192 return Status;
193 } else if ((CmdBoolean[0] == L'y') || (CmdBoolean[0] == L'Y')) {
194 if (Value) *Value = TRUE;
195 return EFI_SUCCESS;
196 } else if ((CmdBoolean[0] == L'n') || (CmdBoolean[0] == L'N')) {
197 if (Value) *Value = FALSE;
198 return EFI_SUCCESS;
199 }
200 }
201 }
202
203 BOOLEAN
204 HasFilePathEfiExtension (
205 IN CHAR16* FilePath
206 )
207 {
208 return (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".EFI") == 0) ||
209 (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".efi") == 0);
210 }
211
212 // Return the last non end-type Device Path Node from a Device Path
213 EFI_DEVICE_PATH*
214 GetLastDevicePathNode (
215 IN EFI_DEVICE_PATH* DevicePath
216 )
217 {
218 EFI_DEVICE_PATH* PrevDevicePathNode;
219
220 PrevDevicePathNode = DevicePath;
221 while (!IsDevicePathEndType (DevicePath)) {
222 PrevDevicePathNode = DevicePath;
223 DevicePath = NextDevicePathNode (DevicePath);
224 }
225
226 return PrevDevicePathNode;
227 }
228
229 EFI_STATUS
230 GenerateDeviceDescriptionName (
231 IN EFI_HANDLE Handle,
232 IN OUT CHAR16* Description
233 )
234 {
235 EFI_STATUS Status;
236 EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
237 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
238 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
239 CHAR16* DriverName;
240 CHAR16* DevicePathTxt;
241 EFI_DEVICE_PATH* DevicePathNode;
242
243 ComponentName2Protocol = NULL;
244 Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
245 if (!EFI_ERROR(Status)) {
246 //TODO: Fixme. we must find the best langague
247 Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
248 if (!EFI_ERROR(Status)) {
249 StrnCpy (Description, DriverName, BOOT_DEVICE_DESCRIPTION_MAX);
250 }
251 }
252
253 if (EFI_ERROR(Status)) {
254 // Use the lastest non null entry of the Device path as a description
255 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
256 if (EFI_ERROR(Status)) {
257 return Status;
258 }
259
260 // Convert the last non end-type Device Path Node in text for the description
261 DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
262 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
263 ASSERT_EFI_ERROR(Status);
264 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePathNode, TRUE, TRUE);
265 StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
266 FreePool (DevicePathTxt);
267 }
268
269 return EFI_SUCCESS;
270 }
271
272 EFI_STATUS
273 BdsStartBootOption (
274 IN CHAR16* BootOption
275 )
276 {
277 EFI_STATUS Status;
278 BDS_LOAD_OPTION *BdsLoadOption;
279
280 Status = BootOptionFromLoadOptionVariable (BootOption, &BdsLoadOption);
281 if (!EFI_ERROR(Status)) {
282 Status = BootOptionStart (BdsLoadOption);
283 FreePool (BdsLoadOption);
284
285 if (!EFI_ERROR(Status)) {
286 Status = EFI_SUCCESS;
287 } else {
288 Status = EFI_NOT_STARTED;
289 }
290 } else {
291 Status = EFI_NOT_FOUND;
292 }
293 return Status;
294 }
295
296 UINTN
297 GetUnalignedDevicePathSize (
298 IN EFI_DEVICE_PATH* DevicePath
299 )
300 {
301 UINTN Size;
302 EFI_DEVICE_PATH* AlignedDevicePath;
303
304 if ((UINTN)DevicePath & 0x1) {
305 AlignedDevicePath = DuplicateDevicePath (DevicePath);
306 Size = GetDevicePathSize (AlignedDevicePath);
307 FreePool (AlignedDevicePath);
308 } else {
309 Size = GetDevicePathSize (DevicePath);
310 }
311 return Size;
312 }
313
314 EFI_DEVICE_PATH*
315 GetAlignedDevicePath (
316 IN EFI_DEVICE_PATH* DevicePath
317 )
318 {
319 if ((UINTN)DevicePath & 0x1) {
320 return DuplicateDevicePath (DevicePath);
321 } else {
322 return DevicePath;
323 }
324 }
325
326 BOOLEAN
327 IsUnicodeString (
328 IN VOID* String
329 )
330 {
331 // We do not support NULL pointer
332 ASSERT (String != NULL);
333
334 if (*(CHAR16*)String < 0x100) {
335 //Note: We could get issue if the string is an empty Ascii string...
336 return TRUE;
337 } else {
338 return FALSE;
339 }
340 }
341
342 /*
343 * Try to detect if the given string is an ASCII or Unicode string
344 *
345 * There are actually few limitation to this function but it is mainly to give
346 * a user friendly output.
347 *
348 * Some limitations:
349 * - it only supports unicode string that use ASCII character (< 0x100)
350 * - single character ASCII strings are interpreted as Unicode string
351 * - string cannot be longer than 2 x BOOT_DEVICE_OPTION_MAX (600 bytes)
352 *
353 * @param String Buffer that might contain a Unicode or Ascii string
354 * @param IsUnicode If not NULL this boolean value returns if the string is an
355 * ASCII or Unicode string.
356 */
357 BOOLEAN
358 IsPrintableString (
359 IN VOID* String,
360 OUT BOOLEAN *IsUnicode
361 )
362 {
363 BOOLEAN UnicodeDetected;
364 BOOLEAN IsPrintable;
365 UINTN Index;
366 CHAR16 Character;
367
368 // We do not support NULL pointer
369 ASSERT (String != NULL);
370
371 // Test empty string
372 if (*(CHAR16*)String == L'\0') {
373 if (IsUnicode) {
374 *IsUnicode = TRUE;
375 }
376 return TRUE;
377 } else if (*(CHAR16*)String == '\0') {
378 if (IsUnicode) {
379 *IsUnicode = FALSE;
380 }
381 return TRUE;
382 }
383
384 // Limitation: if the string is an ASCII single character string. This comparison
385 // will assume it is a Unicode string.
386 if (*(CHAR16*)String < 0x100) {
387 UnicodeDetected = TRUE;
388 } else {
389 UnicodeDetected = FALSE;
390 }
391
392 IsPrintable = FALSE;
393 for (Index = 0; Index < BOOT_DEVICE_OPTION_MAX * 2; Index++) {
394 if (UnicodeDetected) {
395 Character = ((CHAR16*)String)[Index];
396 } else {
397 Character = ((CHAR8*)String)[Index];
398 }
399
400 if (Character == '\0') {
401 // End of the string
402 IsPrintable = TRUE;
403 break;
404 } else if ((Character < 0x20) || (Character > 0x7f)) {
405 // We only support the range of printable ASCII character
406 IsPrintable = FALSE;
407 break;
408 }
409 }
410
411 if (IsPrintable && IsUnicode) {
412 *IsUnicode = UnicodeDetected;
413 }
414
415 return IsPrintable;
416 }