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