ArmPlatformPkg/Bds: Corrected boot type detection
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.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 #include <Guid/ArmGlobalVariableHob.h>
18
19 extern EFI_HANDLE mImageHandle;
20 extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;
21
22
23 EFI_STATUS
24 SelectBootDevice (
25 OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice
26 )
27 {
28 EFI_STATUS Status;
29 LIST_ENTRY SupportedDeviceList;
30 UINTN SupportedDeviceCount;
31 LIST_ENTRY* Entry;
32 UINTN SupportedDeviceSelected;
33 UINTN Index;
34
35 //
36 // List the Boot Devices supported
37 //
38
39 // Start all the drivers first
40 BdsConnectAllDrivers ();
41
42 // List the supported devices
43 Status = BootDeviceListSupportedInit (&SupportedDeviceList);
44 ASSERT_EFI_ERROR(Status);
45
46 SupportedDeviceCount = 0;
47 for (Entry = GetFirstNode (&SupportedDeviceList);
48 !IsNull (&SupportedDeviceList,Entry);
49 Entry = GetNextNode (&SupportedDeviceList,Entry)
50 )
51 {
52 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
53 Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);
54
55 DEBUG_CODE_BEGIN();
56 CHAR16* DevicePathTxt;
57 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
58
59 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
60 ASSERT_EFI_ERROR(Status);
61 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);
62
63 Print(L"\t- %s\n",DevicePathTxt);
64
65 FreePool(DevicePathTxt);
66 DEBUG_CODE_END();
67
68 SupportedDeviceCount++;
69 }
70
71 if (SupportedDeviceCount == 0) {
72 Print(L"There is no supported device.\n");
73 Status = EFI_ABORTED;
74 goto EXIT;
75 }
76
77 //
78 // Select the Boot Device
79 //
80 SupportedDeviceSelected = 0;
81 while (SupportedDeviceSelected == 0) {
82 Print(L"Select the Boot Device: ");
83 Status = GetHIInputInteger (&SupportedDeviceSelected);
84 if (EFI_ERROR(Status)) {
85 Status = EFI_ABORTED;
86 goto EXIT;
87 } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {
88 Print(L"Invalid input (max %d)\n",SupportedDeviceCount);
89 SupportedDeviceSelected = 0;
90 }
91 }
92
93 //
94 // Get the Device Path for the selected boot device
95 //
96 Index = 1;
97 for (Entry = GetFirstNode (&SupportedDeviceList);
98 !IsNull (&SupportedDeviceList,Entry);
99 Entry = GetNextNode (&SupportedDeviceList,Entry)
100 )
101 {
102 if (Index == SupportedDeviceSelected) {
103 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
104 break;
105 }
106 Index++;
107 }
108
109 EXIT:
110 BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);
111 return Status;
112 }
113
114 EFI_STATUS
115 BootMenuAddBootOption (
116 IN LIST_ENTRY *BootOptionsList
117 )
118 {
119 EFI_STATUS Status;
120 BDS_SUPPORTED_DEVICE* SupportedBootDevice;
121 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
122 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
123 CHAR8 AsciiCmdLine[BOOT_DEVICE_OPTION_MAX];
124 CHAR16 CmdLine[BOOT_DEVICE_OPTION_MAX];
125 UINT32 Attributes;
126 ARM_BDS_LOADER_TYPE BootType;
127 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;
128 EFI_DEVICE_PATH *DevicePath;
129 EFI_DEVICE_PATH_PROTOCOL *DevicePathNodes;
130 EFI_DEVICE_PATH_PROTOCOL *InitrdPathNodes;
131 EFI_DEVICE_PATH_PROTOCOL *InitrdPath;
132 UINTN CmdLineSize;
133 BOOLEAN InitrdSupport;
134 UINTN InitrdSize;
135 UINT8* OptionalData;
136 UINTN OptionalDataSize;
137
138 Attributes = 0;
139 SupportedBootDevice = NULL;
140
141 // List the Boot Devices supported
142 Status = SelectBootDevice (&SupportedBootDevice);
143 if (EFI_ERROR(Status)) {
144 Status = EFI_ABORTED;
145 goto EXIT;
146 }
147
148 // Create the specific device path node
149 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);
150 if (EFI_ERROR(Status)) {
151 Status = EFI_ABORTED;
152 goto EXIT;
153 }
154 // Append the Device Path to the selected device path
155 DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);
156 if (DevicePath == NULL) {
157 Status = EFI_OUT_OF_RESOURCES;
158 goto EXIT;
159 }
160
161 if (SupportedBootDevice->Support->RequestBootType) {
162 Status = BootDeviceGetType (DevicePath, &BootType, &Attributes);
163 if (EFI_ERROR(Status)) {
164 Status = EFI_ABORTED;
165 goto EXIT;
166 }
167 } else {
168 BootType = BDS_LOADER_EFI_APPLICATION;
169 }
170
171 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
172 Print(L"Add an initrd: ");
173 Status = GetHIInputBoolean (&InitrdSupport);
174 if (EFI_ERROR(Status)) {
175 Status = EFI_ABORTED;
176 goto EXIT;
177 }
178
179 if (InitrdSupport) {
180 // Create the specific device path node
181 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNodes);
182 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
183 Status = EFI_ABORTED;
184 goto EXIT;
185 }
186
187 if (InitrdPathNodes != NULL) {
188 // Append the Device Path to the selected device path
189 InitrdPath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);
190 if (InitrdPath == NULL) {
191 Status = EFI_OUT_OF_RESOURCES;
192 goto EXIT;
193 }
194 } else {
195 InitrdPath = NULL;
196 }
197 } else {
198 InitrdPath = NULL;
199 }
200
201 Print(L"Arguments to pass to the binary: ");
202 Status = GetHIInputAscii (AsciiCmdLine, BOOT_DEVICE_OPTION_MAX);
203 if (EFI_ERROR(Status)) {
204 Status = EFI_ABORTED;
205 goto FREE_DEVICE_PATH;
206 }
207
208 CmdLineSize = AsciiStrSize (AsciiCmdLine);
209 InitrdSize = GetDevicePathSize (InitrdPath);
210
211 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;
212 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);
213
214 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
215 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
216 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), AsciiCmdLine, CmdLineSize);
217 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
218
219 OptionalData = (UINT8*)BootArguments;
220 } else {
221 Print (L"Arguments to pass to the EFI Application: ");
222 Status = GetHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);
223 if (EFI_ERROR (Status)) {
224 Status = EFI_ABORTED;
225 goto EXIT;
226 }
227
228 OptionalData = (UINT8*)CmdLine;
229 OptionalDataSize = StrSize (CmdLine);
230 }
231
232 Print(L"Description for this new Entry: ");
233 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
234 if (EFI_ERROR(Status)) {
235 Status = EFI_ABORTED;
236 goto FREE_DEVICE_PATH;
237 }
238
239 // Create new entry
240 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));
241 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);
242 if (!EFI_ERROR(Status)) {
243 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);
244 }
245
246 FREE_DEVICE_PATH:
247 FreePool (DevicePath);
248
249 EXIT:
250 if (Status == EFI_ABORTED) {
251 Print(L"\n");
252 }
253 FreePool(SupportedBootDevice);
254 return Status;
255 }
256
257 STATIC
258 EFI_STATUS
259 BootMenuSelectBootOption (
260 IN LIST_ENTRY* BootOptionsList,
261 IN CONST CHAR16* InputStatement,
262 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry
263 )
264 {
265 EFI_STATUS Status;
266 LIST_ENTRY* Entry;
267 BDS_LOAD_OPTION* BdsLoadOption;
268 UINTN BootOptionSelected;
269 UINTN BootOptionCount;
270 UINTN Index;
271 BOOLEAN IsUnicode;
272
273 // Display the list of supported boot devices
274 BootOptionCount = 0;
275 for (Entry = GetFirstNode (BootOptionsList);
276 !IsNull (BootOptionsList,Entry);
277 Entry = GetNextNode (BootOptionsList, Entry)
278 )
279 {
280 BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
281
282 Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);
283
284 DEBUG_CODE_BEGIN();
285 CHAR16* DevicePathTxt;
286 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
287 ARM_BDS_LOADER_TYPE LoaderType;
288 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
289
290 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
291 ASSERT_EFI_ERROR(Status);
292 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);
293
294 Print(L"\t- %s\n",DevicePathTxt);
295 OptionalData = BdsLoadOption->OptionalData;
296 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {
297 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
298 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
299 Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);
300 }
301 } else if (OptionalData != NULL) {
302 if (IsPrintableString (OptionalData, &IsUnicode)) {
303 if (IsUnicode) {
304 Print (L"\t- Arguments: %s\n", OptionalData);
305 } else {
306 AsciiPrint ("\t- Arguments: %a\n", OptionalData);
307 }
308 }
309 }
310
311 FreePool(DevicePathTxt);
312 DEBUG_CODE_END();
313
314 BootOptionCount++;
315 }
316
317 // Check if a valid boot option(s) is found
318 if (BootOptionCount == 0) {
319 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {
320 Print (L"Nothing to remove!\n");
321 } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {
322 Print (L"Couldn't find valid boot entries\n");
323 } else{
324 Print (L"No supported Boot Entry.\n");
325 }
326
327 return EFI_NOT_FOUND;
328 }
329
330 // Get the index of the boot device to delete
331 BootOptionSelected = 0;
332 while (BootOptionSelected == 0) {
333 Print(InputStatement);
334 Status = GetHIInputInteger (&BootOptionSelected);
335 if (EFI_ERROR(Status)) {
336 return Status;
337 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {
338 Print(L"Invalid input (max %d)\n",BootOptionCount);
339 BootOptionSelected = 0;
340 }
341 }
342
343 // Get the structure of the Boot device to delete
344 Index = 1;
345 for (Entry = GetFirstNode (BootOptionsList);
346 !IsNull (BootOptionsList, Entry);
347 Entry = GetNextNode (BootOptionsList,Entry)
348 )
349 {
350 if (Index == BootOptionSelected) {
351 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);
352 break;
353 }
354 Index++;
355 }
356
357 return EFI_SUCCESS;
358 }
359
360 EFI_STATUS
361 BootMenuRemoveBootOption (
362 IN LIST_ENTRY *BootOptionsList
363 )
364 {
365 EFI_STATUS Status;
366 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
367
368 Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);
369 if (EFI_ERROR(Status)) {
370 return Status;
371 }
372
373 // If the Boot Option was attached to a list remove it
374 if (!IsListEmpty (&BootOptionEntry->Link)) {
375 // Remove the entry from the list
376 RemoveEntryList (&BootOptionEntry->Link);
377 }
378
379 // Delete the BDS Load option structures
380 BootOptionDelete (BootOptionEntry->BdsLoadOption);
381
382 return EFI_SUCCESS;
383 }
384
385 EFI_STATUS
386 BootMenuUpdateBootOption (
387 IN LIST_ENTRY *BootOptionsList
388 )
389 {
390 EFI_STATUS Status;
391 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;
392 BDS_LOAD_OPTION *BootOption;
393 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
394 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
395 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
396 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];
397 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];
398 EFI_DEVICE_PATH *DevicePath;
399 EFI_DEVICE_PATH *TempInitrdPath;
400 ARM_BDS_LOADER_TYPE BootType;
401 ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData;
402 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
403 EFI_DEVICE_PATH *InitrdPathNodes;
404 EFI_DEVICE_PATH *InitrdPath;
405 UINTN InitrdSize;
406 UINTN CmdLineSize;
407 BOOLEAN InitrdSupport;
408 UINT8* OptionalData;
409 UINTN OptionalDataSize;
410 BOOLEAN IsPrintable;
411 BOOLEAN IsUnicode;
412
413 Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);
414 if (EFI_ERROR(Status)) {
415 return Status;
416 }
417 BootOption = BootOptionEntry->BdsLoadOption;
418
419 // Get the device support for this Boot Option
420 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);
421 if (EFI_ERROR(Status)) {
422 Print(L"Not possible to retrieve the supported device for the update\n");
423 return EFI_UNSUPPORTED;
424 }
425
426 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);
427 if (EFI_ERROR(Status)) {
428 Status = EFI_ABORTED;
429 goto EXIT;
430 }
431
432 if (DeviceSupport->RequestBootType) {
433 Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes);
434 if (EFI_ERROR(Status)) {
435 Status = EFI_ABORTED;
436 goto EXIT;
437 }
438 }
439
440 LoaderOptionalData = BootOption->OptionalData;
441 if (LoaderOptionalData != NULL) {
442 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType));
443 } else {
444 BootType = BDS_LOADER_EFI_APPLICATION;
445 }
446
447 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
448 LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments;
449
450 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
451
452 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
453 if (InitrdSize > 0) {
454 Print(L"Keep the initrd: ");
455 } else {
456 Print(L"Add an initrd: ");
457 }
458 Status = GetHIInputBoolean (&InitrdSupport);
459 if (EFI_ERROR(Status)) {
460 Status = EFI_ABORTED;
461 goto EXIT;
462 }
463
464 if (InitrdSupport) {
465 if (InitrdSize > 0) {
466 // Case we update the initrd device path
467 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath);
468 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
469 Status = EFI_ABORTED;
470 goto EXIT;
471 }
472 InitrdSize = GetDevicePathSize (InitrdPath);
473 } else {
474 // Case we create the initrd device path
475
476 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes);
477 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
478 Status = EFI_ABORTED;
479 goto EXIT;
480 }
481
482 if (InitrdPathNodes != NULL) {
483 // Duplicate Linux kernel Device Path
484 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);
485 // Replace Linux kernel Node by EndNode
486 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));
487 // Append the Device Path to the selected device path
488 InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);
489 FreePool (TempInitrdPath);
490 if (InitrdPath == NULL) {
491 Status = EFI_OUT_OF_RESOURCES;
492 goto EXIT;
493 }
494 InitrdSize = GetDevicePathSize (InitrdPath);
495 } else {
496 InitrdPath = NULL;
497 }
498 }
499 } else {
500 InitrdSize = 0;
501 }
502
503 Print(L"Arguments to pass to the binary: ");
504 if (CmdLineSize > 0) {
505 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);
506 } else {
507 CmdLine[0] = '\0';
508 }
509 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
510 if (EFI_ERROR(Status)) {
511 Status = EFI_ABORTED;
512 goto FREE_DEVICE_PATH;
513 }
514
515 CmdLineSize = AsciiStrSize (CmdLine);
516
517 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;
518 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);
519 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
520 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
521 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);
522 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
523
524 OptionalData = (UINT8*)BootArguments;
525 } else {
526 Print (L"Arguments to pass to the EFI Application: ");
527
528 if (BootOption->OptionalDataSize > 0) {
529 IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);
530 if (IsPrintable) {
531 if (IsUnicode) {
532 StrnCpy (UnicodeCmdLine, BootOption->OptionalData, BootOption->OptionalDataSize / 2);
533 } else {
534 AsciiStrnCpy (CmdLine, BootOption->OptionalData, BootOption->OptionalDataSize);
535 }
536 }
537 } else {
538 UnicodeCmdLine[0] = L'\0';
539 IsPrintable = TRUE;
540 IsUnicode = TRUE;
541 }
542
543 // We do not request arguments for OptionalData that cannot be printed
544 if (IsPrintable) {
545 if (IsUnicode) {
546 Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);
547 if (EFI_ERROR (Status)) {
548 Status = EFI_ABORTED;
549 goto FREE_DEVICE_PATH;
550 }
551
552 OptionalData = (UINT8*)UnicodeCmdLine;
553 OptionalDataSize = StrSize (UnicodeCmdLine);
554 } else {
555 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
556 if (EFI_ERROR (Status)) {
557 Status = EFI_ABORTED;
558 goto FREE_DEVICE_PATH;
559 }
560
561 OptionalData = (UINT8*)CmdLine;
562 OptionalDataSize = AsciiStrSize (CmdLine);
563 }
564 } else {
565 // We keep the former OptionalData
566 OptionalData = BootOption->OptionalData;
567 OptionalDataSize = BootOption->OptionalDataSize;
568 }
569 }
570
571 Print(L"Description for this new Entry: ");
572 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);
573 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
574 if (EFI_ERROR(Status)) {
575 Status = EFI_ABORTED;
576 goto FREE_DEVICE_PATH;
577 }
578
579 // Update the entry
580 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);
581
582 FREE_DEVICE_PATH:
583 FreePool (DevicePath);
584
585 EXIT:
586 if (Status == EFI_ABORTED) {
587 Print(L"\n");
588 }
589 return Status;
590 }
591
592 EFI_STATUS
593 UpdateFdtPath (
594 IN LIST_ENTRY *BootOptionsList
595 )
596 {
597 EFI_STATUS Status;
598 UINTN FdtDevicePathSize;
599 BDS_SUPPORTED_DEVICE *SupportedBootDevice;
600 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;
601 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;
602
603 Status = SelectBootDevice (&SupportedBootDevice);
604 if (EFI_ERROR(Status)) {
605 Status = EFI_ABORTED;
606 goto EXIT;
607 }
608
609 // Create the specific device path node
610 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);
611 if (EFI_ERROR(Status)) {
612 Status = EFI_ABORTED;
613 goto EXIT;
614 }
615
616 if (FdtDevicePathNodes != NULL) {
617 // Append the Device Path node to the select device path
618 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);
619 FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);
620 Status = gRT->SetVariable (
621 (CHAR16*)L"Fdt",
622 &gArmGlobalVariableGuid,
623 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
624 FdtDevicePathSize,
625 FdtDevicePath
626 );
627 ASSERT_EFI_ERROR(Status);
628 } else {
629 gRT->SetVariable (
630 (CHAR16*)L"Fdt",
631 &gArmGlobalVariableGuid,
632 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
633 0,
634 NULL
635 );
636 ASSERT_EFI_ERROR(Status);
637 }
638
639 EXIT:
640 if (Status == EFI_ABORTED) {
641 Print(L"\n");
642 }
643 FreePool(SupportedBootDevice);
644 return Status;
645 }
646
647 /**
648 Set boot timeout
649
650 Ask for the boot timeout in seconds and if the input succeeds assign the
651 input value to the UEFI global variable "Timeout". This function is called
652 when the user selects the "Set Boot Timeout" of the boot manager menu.
653
654 @param[in] BootOptionsList List of the boot devices, not used here
655
656 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
657 input and assigned to the UEFI "Timeout" global
658 variable
659 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
660 variable "Timeout" has failed.
661 **/
662 EFI_STATUS
663 STATIC
664 BootMenuSetBootTimeout (
665 IN LIST_ENTRY *BootOptionsList
666 )
667 {
668 EFI_STATUS Status;
669 UINTN Input;
670 UINT16 Timeout;
671
672 Print (L"Timeout duration (in seconds): ");
673 Status = GetHIInputInteger (&Input);
674 if (EFI_ERROR (Status)) {
675 Print (L"\n");
676 goto ErrorExit;
677 }
678
679 Timeout = Input;
680 Status = gRT->SetVariable (
681 (CHAR16*)L"Timeout",
682 &gEfiGlobalVariableGuid,
683 EFI_VARIABLE_NON_VOLATILE |
684 EFI_VARIABLE_BOOTSERVICE_ACCESS |
685 EFI_VARIABLE_RUNTIME_ACCESS,
686 sizeof (UINT16),
687 &Timeout
688 );
689 ASSERT_EFI_ERROR (Status);
690
691 ErrorExit:
692 return Status;
693 }
694
695 struct BOOT_MANAGER_ENTRY {
696 CONST CHAR16* Description;
697 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
698 } BootManagerEntries[] = {
699 { L"Add Boot Device Entry", BootMenuAddBootOption },
700 { L"Update Boot Device Entry", BootMenuUpdateBootOption },
701 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },
702 { L"Update FDT path", UpdateFdtPath },
703 { L"Set Boot Timeout", BootMenuSetBootTimeout },
704 };
705
706 EFI_STATUS
707 BootMenuManager (
708 IN LIST_ENTRY *BootOptionsList
709 )
710 {
711 UINTN Index;
712 UINTN OptionSelected;
713 UINTN BootManagerEntryCount;
714 EFI_STATUS Status;
715
716 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
717
718 while (TRUE) {
719 // Display Boot Manager menu
720 for (Index = 0; Index < BootManagerEntryCount; Index++) {
721 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
722 }
723 Print(L"[%d] Return to main menu\n",Index+1);
724
725 // Select which entry to call
726 Print(L"Choice: ");
727 Status = GetHIInputInteger (&OptionSelected);
728 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
729 if (EFI_ERROR(Status)) {
730 Print(L"\n");
731 }
732 return EFI_SUCCESS;
733 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
734 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
735 }
736 }
737 // Should never go here
738 }
739
740 EFI_STATUS
741 BootShell (
742 IN LIST_ENTRY *BootOptionsList
743 )
744 {
745 EFI_STATUS Status;
746
747 // Start EFI Shell
748 Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);
749 if (Status == EFI_NOT_FOUND) {
750 Print (L"Error: EFI Application not found.\n");
751 } else if (EFI_ERROR(Status)) {
752 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
753 }
754
755 return Status;
756 }
757
758 struct BOOT_MAIN_ENTRY {
759 CONST CHAR16* Description;
760 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
761 } BootMainEntries[] = {
762 { L"Shell", BootShell },
763 { L"Boot Manager", BootMenuManager },
764 };
765
766
767 EFI_STATUS
768 BootMenuMain (
769 VOID
770 )
771 {
772 LIST_ENTRY BootOptionsList;
773 UINTN OptionCount;
774 UINTN BootOptionCount;
775 EFI_STATUS Status;
776 LIST_ENTRY* Entry;
777 BDS_LOAD_OPTION* BootOption;
778 UINTN BootOptionSelected;
779 UINTN Index;
780 UINTN BootMainEntryCount;
781 BOOLEAN IsUnicode;
782
783 BootOption = NULL;
784 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
785
786 while (TRUE) {
787 // Get Boot#### list
788 BootOptionList (&BootOptionsList);
789
790 OptionCount = 1;
791
792 // Display the Boot options
793 for (Entry = GetFirstNode (&BootOptionsList);
794 !IsNull (&BootOptionsList,Entry);
795 Entry = GetNextNode (&BootOptionsList,Entry)
796 )
797 {
798 BootOption = LOAD_OPTION_FROM_LINK(Entry);
799
800 Print(L"[%d] %s\n", OptionCount, BootOption->Description);
801
802 DEBUG_CODE_BEGIN();
803 CHAR16* DevicePathTxt;
804 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
805 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
806 UINTN CmdLineSize;
807 ARM_BDS_LOADER_TYPE LoaderType;
808
809 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
810 if (EFI_ERROR(Status)) {
811 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
812 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));
813 return Status;
814 }
815 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);
816
817 Print(L"\t- %s\n",DevicePathTxt);
818
819 // If it is a supported BootEntry then print its details
820 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
821 OptionalData = BootOption->OptionalData;
822 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
823 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
824 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {
825 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);
826 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
827 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);
828 Print(L"\t- Initrd: %s\n", DevicePathTxt);
829 }
830 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) {
831 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));
832 }
833 }
834
835 switch (LoaderType) {
836 case BDS_LOADER_EFI_APPLICATION:
837 Print(L"\t- LoaderType: EFI Application\n");
838 break;
839
840 case BDS_LOADER_KERNEL_LINUX_ATAG:
841 Print(L"\t- LoaderType: Linux kernel with ATAG support\n");
842 break;
843
844 case BDS_LOADER_KERNEL_LINUX_FDT:
845 Print(L"\t- LoaderType: Linux kernel with FDT support\n");
846 break;
847
848 default:
849 Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType);
850 }
851 } else if (BootOption->OptionalData != NULL) {
852 if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {
853 if (IsUnicode) {
854 Print (L"\t- Arguments: %s\n", BootOption->OptionalData);
855 } else {
856 AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);
857 }
858 }
859 }
860 FreePool(DevicePathTxt);
861 DEBUG_CODE_END();
862
863 OptionCount++;
864 }
865 BootOptionCount = OptionCount-1;
866
867 // Display the hardcoded Boot entries
868 for (Index = 0; Index < BootMainEntryCount; Index++) {
869 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);
870 OptionCount++;
871 }
872
873 // Request the boot entry from the user
874 BootOptionSelected = 0;
875 while (BootOptionSelected == 0) {
876 Print(L"Start: ");
877 Status = GetHIInputInteger (&BootOptionSelected);
878 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {
879 Print(L"Invalid input (max %d)\n",(OptionCount-1));
880 BootOptionSelected = 0;
881 }
882 }
883
884 // Start the selected entry
885 if (BootOptionSelected > BootOptionCount) {
886 // Start the hardcoded entry
887 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);
888 } else {
889 // Find the selected entry from the Boot#### list
890 Index = 1;
891 for (Entry = GetFirstNode (&BootOptionsList);
892 !IsNull (&BootOptionsList,Entry);
893 Entry = GetNextNode (&BootOptionsList,Entry)
894 )
895 {
896 if (Index == BootOptionSelected) {
897 BootOption = LOAD_OPTION_FROM_LINK(Entry);
898 break;
899 }
900 Index++;
901 }
902
903 Status = BootOptionStart (BootOption);
904 }
905 }
906 // Should never go here
907 }