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