]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
1e30f148b30cd2b5de1b1361aec7b45c96719216
[mirror_edk2.git] / ArmPkg / Library / PlatformBootManagerLib / PlatformBm.c
1 /** @file
2 Implementation for PlatformBootManagerLib library class interfaces.
3
4 Copyright (C) 2015-2016, Red Hat, Inc.
5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include <IndustryStandard/Pci22.h>
14 #include <Library/BootLogoLib.h>
15 #include <Library/CapsuleLib.h>
16 #include <Library/DevicePathLib.h>
17 #include <Library/HobLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootManagerLib.h>
20 #include <Library/UefiLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Protocol/DevicePath.h>
23 #include <Protocol/EsrtManagement.h>
24 #include <Protocol/GraphicsOutput.h>
25 #include <Protocol/LoadedImage.h>
26 #include <Protocol/PciIo.h>
27 #include <Protocol/PciRootBridgeIo.h>
28 #include <Protocol/PlatformBootManager.h>
29 #include <Guid/EventGroup.h>
30 #include <Guid/TtyTerm.h>
31 #include <Guid/SerialPortLibVendor.h>
32
33 #include "PlatformBm.h"
34
35 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
36
37 #pragma pack (1)
38 typedef struct {
39 VENDOR_DEVICE_PATH SerialDxe;
40 UART_DEVICE_PATH Uart;
41 VENDOR_DEFINED_DEVICE_PATH TermType;
42 EFI_DEVICE_PATH_PROTOCOL End;
43 } PLATFORM_SERIAL_CONSOLE;
44 #pragma pack ()
45
46 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
47 //
48 // VENDOR_DEVICE_PATH SerialDxe
49 //
50 {
51 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
52 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
53 },
54
55 //
56 // UART_DEVICE_PATH Uart
57 //
58 {
59 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
60 0, // Reserved
61 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
62 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
63 FixedPcdGet8 (PcdUartDefaultParity), // Parity
64 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
65 },
66
67 //
68 // VENDOR_DEFINED_DEVICE_PATH TermType
69 //
70 {
71 {
72 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
73 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
74 }
75 //
76 // Guid to be filled in dynamically
77 //
78 },
79
80 //
81 // EFI_DEVICE_PATH_PROTOCOL End
82 //
83 {
84 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
85 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
86 }
87 };
88
89
90 #pragma pack (1)
91 typedef struct {
92 USB_CLASS_DEVICE_PATH Keyboard;
93 EFI_DEVICE_PATH_PROTOCOL End;
94 } PLATFORM_USB_KEYBOARD;
95 #pragma pack ()
96
97 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
98 //
99 // USB_CLASS_DEVICE_PATH Keyboard
100 //
101 {
102 {
103 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
104 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
105 },
106 0xFFFF, // VendorId: any
107 0xFFFF, // ProductId: any
108 3, // DeviceClass: HID
109 1, // DeviceSubClass: boot
110 1 // DeviceProtocol: keyboard
111 },
112
113 //
114 // EFI_DEVICE_PATH_PROTOCOL End
115 //
116 {
117 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
118 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
119 }
120 };
121
122
123 /**
124 Check if the handle satisfies a particular condition.
125
126 @param[in] Handle The handle to check.
127 @param[in] ReportText A caller-allocated string passed in for reporting
128 purposes. It must never be NULL.
129
130 @retval TRUE The condition is satisfied.
131 @retval FALSE Otherwise. This includes the case when the condition could not
132 be fully evaluated due to an error.
133 **/
134 typedef
135 BOOLEAN
136 (EFIAPI *FILTER_FUNCTION) (
137 IN EFI_HANDLE Handle,
138 IN CONST CHAR16 *ReportText
139 );
140
141
142 /**
143 Process a handle.
144
145 @param[in] Handle The handle to process.
146 @param[in] ReportText A caller-allocated string passed in for reporting
147 purposes. It must never be NULL.
148 **/
149 typedef
150 VOID
151 (EFIAPI *CALLBACK_FUNCTION) (
152 IN EFI_HANDLE Handle,
153 IN CONST CHAR16 *ReportText
154 );
155
156 /**
157 Locate all handles that carry the specified protocol, filter them with a
158 callback function, and pass each handle that passes the filter to another
159 callback.
160
161 @param[in] ProtocolGuid The protocol to look for.
162
163 @param[in] Filter The filter function to pass each handle to. If this
164 parameter is NULL, then all handles are processed.
165
166 @param[in] Process The callback function to pass each handle to that
167 clears the filter.
168 **/
169 STATIC
170 VOID
171 FilterAndProcess (
172 IN EFI_GUID *ProtocolGuid,
173 IN FILTER_FUNCTION Filter OPTIONAL,
174 IN CALLBACK_FUNCTION Process
175 )
176 {
177 EFI_STATUS Status;
178 EFI_HANDLE *Handles;
179 UINTN NoHandles;
180 UINTN Idx;
181
182 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
183 NULL /* SearchKey */, &NoHandles, &Handles);
184 if (EFI_ERROR (Status)) {
185 //
186 // This is not an error, just an informative condition.
187 //
188 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
189 Status));
190 return;
191 }
192
193 ASSERT (NoHandles > 0);
194 for (Idx = 0; Idx < NoHandles; ++Idx) {
195 CHAR16 *DevicePathText;
196 STATIC CHAR16 Fallback[] = L"<device path unavailable>";
197
198 //
199 // The ConvertDevicePathToText() function handles NULL input transparently.
200 //
201 DevicePathText = ConvertDevicePathToText (
202 DevicePathFromHandle (Handles[Idx]),
203 FALSE, // DisplayOnly
204 FALSE // AllowShortcuts
205 );
206 if (DevicePathText == NULL) {
207 DevicePathText = Fallback;
208 }
209
210 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
211 Process (Handles[Idx], DevicePathText);
212 }
213
214 if (DevicePathText != Fallback) {
215 FreePool (DevicePathText);
216 }
217 }
218 gBS->FreePool (Handles);
219 }
220
221
222 /**
223 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
224 **/
225 STATIC
226 BOOLEAN
227 EFIAPI
228 IsPciDisplay (
229 IN EFI_HANDLE Handle,
230 IN CONST CHAR16 *ReportText
231 )
232 {
233 EFI_STATUS Status;
234 EFI_PCI_IO_PROTOCOL *PciIo;
235 PCI_TYPE00 Pci;
236
237 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
238 (VOID**)&PciIo);
239 if (EFI_ERROR (Status)) {
240 //
241 // This is not an error worth reporting.
242 //
243 return FALSE;
244 }
245
246 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
247 sizeof Pci / sizeof (UINT32), &Pci);
248 if (EFI_ERROR (Status)) {
249 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
250 return FALSE;
251 }
252
253 return IS_PCI_DISPLAY (&Pci);
254 }
255
256
257 /**
258 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
259 the matching driver to produce all first-level child handles.
260 **/
261 STATIC
262 VOID
263 EFIAPI
264 Connect (
265 IN EFI_HANDLE Handle,
266 IN CONST CHAR16 *ReportText
267 )
268 {
269 EFI_STATUS Status;
270
271 Status = gBS->ConnectController (
272 Handle, // ControllerHandle
273 NULL, // DriverImageHandle
274 NULL, // RemainingDevicePath -- produce all children
275 FALSE // Recursive
276 );
277 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
278 __FUNCTION__, ReportText, Status));
279 }
280
281
282 /**
283 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
284 handle, and adds it to ConOut and ErrOut.
285 **/
286 STATIC
287 VOID
288 EFIAPI
289 AddOutput (
290 IN EFI_HANDLE Handle,
291 IN CONST CHAR16 *ReportText
292 )
293 {
294 EFI_STATUS Status;
295 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
296
297 DevicePath = DevicePathFromHandle (Handle);
298 if (DevicePath == NULL) {
299 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
300 __FUNCTION__, ReportText, Handle));
301 return;
302 }
303
304 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
305 if (EFI_ERROR (Status)) {
306 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
307 ReportText, Status));
308 return;
309 }
310
311 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
312 if (EFI_ERROR (Status)) {
313 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
314 ReportText, Status));
315 return;
316 }
317
318 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
319 ReportText));
320 }
321
322 STATIC
323 VOID
324 PlatformRegisterFvBootOption (
325 CONST EFI_GUID *FileGuid,
326 CHAR16 *Description,
327 UINT32 Attributes
328 )
329 {
330 EFI_STATUS Status;
331 INTN OptionIndex;
332 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
333 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
334 UINTN BootOptionCount;
335 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
336 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
337 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
338
339 Status = gBS->HandleProtocol (
340 gImageHandle,
341 &gEfiLoadedImageProtocolGuid,
342 (VOID **) &LoadedImage
343 );
344 ASSERT_EFI_ERROR (Status);
345
346 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
347 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
348 ASSERT (DevicePath != NULL);
349 DevicePath = AppendDevicePathNode (
350 DevicePath,
351 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
352 );
353 ASSERT (DevicePath != NULL);
354
355 Status = EfiBootManagerInitializeLoadOption (
356 &NewOption,
357 LoadOptionNumberUnassigned,
358 LoadOptionTypeBoot,
359 Attributes,
360 Description,
361 DevicePath,
362 NULL,
363 0
364 );
365 ASSERT_EFI_ERROR (Status);
366 FreePool (DevicePath);
367
368 BootOptions = EfiBootManagerGetLoadOptions (
369 &BootOptionCount, LoadOptionTypeBoot
370 );
371
372 OptionIndex = EfiBootManagerFindLoadOption (
373 &NewOption, BootOptions, BootOptionCount
374 );
375
376 if (OptionIndex == -1) {
377 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
378 ASSERT_EFI_ERROR (Status);
379 }
380 EfiBootManagerFreeLoadOption (&NewOption);
381 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
382 }
383
384
385 STATIC
386 VOID
387 GetPlatformOptions (
388 VOID
389 )
390 {
391 EFI_STATUS Status;
392 EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;
393 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
394 EFI_INPUT_KEY *BootKeys;
395 PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;
396 UINTN CurrentBootOptionCount;
397 UINTN Index;
398 UINTN BootCount;
399
400 Status = gBS->LocateProtocol (&gPlatformBootManagerProtocolGuid, NULL,
401 (VOID **)&PlatformBootManager);
402 if (EFI_ERROR (Status)) {
403 return;
404 }
405 Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (
406 &BootCount,
407 &BootOptions,
408 &BootKeys
409 );
410 if (EFI_ERROR (Status)) {
411 return;
412 }
413 //
414 // Fetch the existent boot options. If there are none, CurrentBootCount
415 // will be zeroed.
416 //
417 CurrentBootOptions = EfiBootManagerGetLoadOptions (
418 &CurrentBootOptionCount,
419 LoadOptionTypeBoot
420 );
421 //
422 // Process the platform boot options.
423 //
424 for (Index = 0; Index < BootCount; Index++) {
425 INTN Match;
426 UINTN BootOptionNumber;
427
428 //
429 // If there are any preexistent boot options, and the subject platform boot
430 // option is already among them, then don't try to add it. Just get its
431 // assigned boot option number so we can associate a hotkey with it. Note
432 // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions
433 // == NULL) if (CurrentBootCount == 0).
434 //
435 Match = EfiBootManagerFindLoadOption (
436 &BootOptions[Index],
437 CurrentBootOptions,
438 CurrentBootOptionCount
439 );
440 if (Match >= 0) {
441 BootOptionNumber = CurrentBootOptions[Match].OptionNumber;
442 } else {
443 //
444 // Add the platform boot options as a new one, at the end of the boot
445 // order. Note that if the platform provided this boot option with an
446 // unassigned option number, then the below function call will assign a
447 // number.
448 //
449 Status = EfiBootManagerAddLoadOptionVariable (
450 &BootOptions[Index],
451 MAX_UINTN
452 );
453 if (EFI_ERROR (Status)) {
454 DEBUG ((DEBUG_ERROR, "%a: failed to register \"%s\": %r\n",
455 __FUNCTION__, BootOptions[Index].Description, Status));
456 continue;
457 }
458 BootOptionNumber = BootOptions[Index].OptionNumber;
459 }
460
461 //
462 // Register a hotkey with the boot option, if requested.
463 //
464 if (BootKeys[Index].UnicodeChar == L'\0') {
465 continue;
466 }
467
468 Status = EfiBootManagerAddKeyOptionVariable (
469 NULL,
470 BootOptionNumber,
471 0,
472 &BootKeys[Index],
473 NULL
474 );
475 if (EFI_ERROR (Status)) {
476 DEBUG ((DEBUG_ERROR, "%a: failed to register hotkey for \"%s\": %r\n",
477 __FUNCTION__, BootOptions[Index].Description, Status));
478 }
479 }
480 EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);
481 EfiBootManagerFreeLoadOptions (BootOptions, BootCount);
482 FreePool (BootKeys);
483 }
484
485 STATIC
486 VOID
487 PlatformRegisterOptionsAndKeys (
488 VOID
489 )
490 {
491 EFI_STATUS Status;
492 EFI_INPUT_KEY Enter;
493 EFI_INPUT_KEY F2;
494 EFI_INPUT_KEY Esc;
495 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
496
497 GetPlatformOptions ();
498
499 //
500 // Register ENTER as CONTINUE key
501 //
502 Enter.ScanCode = SCAN_NULL;
503 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
504 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
505 ASSERT_EFI_ERROR (Status);
506
507 //
508 // Map F2 and ESC to Boot Manager Menu
509 //
510 F2.ScanCode = SCAN_F2;
511 F2.UnicodeChar = CHAR_NULL;
512 Esc.ScanCode = SCAN_ESC;
513 Esc.UnicodeChar = CHAR_NULL;
514 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
515 ASSERT_EFI_ERROR (Status);
516 Status = EfiBootManagerAddKeyOptionVariable (
517 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
518 );
519 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
520 Status = EfiBootManagerAddKeyOptionVariable (
521 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
522 );
523 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
524 }
525
526
527 //
528 // BDS Platform Functions
529 //
530 /**
531 Do the platform init, can be customized by OEM/IBV
532 Possible things that can be done in PlatformBootManagerBeforeConsole:
533 > Update console variable: 1. include hot-plug devices;
534 > 2. Clear ConIn and add SOL for AMT
535 > Register new Driver#### or Boot####
536 > Register new Key####: e.g.: F12
537 > Signal ReadyToLock event
538 > Authentication action: 1. connect Auth devices;
539 > 2. Identify auto logon user.
540 **/
541 VOID
542 EFIAPI
543 PlatformBootManagerBeforeConsole (
544 VOID
545 )
546 {
547 //
548 // Signal EndOfDxe PI Event
549 //
550 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
551
552 //
553 // Locate the PCI root bridges and make the PCI bus driver connect each,
554 // non-recursively. This will produce a number of child handles with PciIo on
555 // them.
556 //
557 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
558
559 //
560 // Find all display class PCI devices (using the handles from the previous
561 // step), and connect them non-recursively. This should produce a number of
562 // child handles with GOPs on them.
563 //
564 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
565
566 //
567 // Now add the device path of all handles with GOP on them to ConOut and
568 // ErrOut.
569 //
570 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
571
572 //
573 // Add the hardcoded short-form USB keyboard device path to ConIn.
574 //
575 EfiBootManagerUpdateConsoleVariable (ConIn,
576 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
577
578 //
579 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
580 //
581 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);
582 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
583
584 EfiBootManagerUpdateConsoleVariable (ConIn,
585 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
586 EfiBootManagerUpdateConsoleVariable (ConOut,
587 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
588 EfiBootManagerUpdateConsoleVariable (ErrOut,
589 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
590
591 //
592 // Register platform-specific boot options and keyboard shortcuts.
593 //
594 PlatformRegisterOptionsAndKeys ();
595 }
596
597 STATIC
598 VOID
599 HandleCapsules (
600 VOID
601 )
602 {
603 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
604 EFI_PEI_HOB_POINTERS HobPointer;
605 EFI_CAPSULE_HEADER *CapsuleHeader;
606 BOOLEAN NeedReset;
607 EFI_STATUS Status;
608
609 DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));
610
611 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,
612 (VOID **)&EsrtManagement);
613 if (!EFI_ERROR (Status)) {
614 EsrtManagement->SyncEsrtFmp ();
615 }
616
617 //
618 // Find all capsule images from hob
619 //
620 HobPointer.Raw = GetHobList ();
621 NeedReset = FALSE;
622 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,
623 HobPointer.Raw)) != NULL) {
624 CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;
625
626 Status = ProcessCapsuleImage (CapsuleHeader);
627 if (EFI_ERROR (Status)) {
628 DEBUG ((DEBUG_ERROR, "%a: failed to process capsule %p - %r\n",
629 __FUNCTION__, CapsuleHeader, Status));
630 return;
631 }
632
633 NeedReset = TRUE;
634 HobPointer.Raw = GET_NEXT_HOB (HobPointer);
635 }
636
637 if (NeedReset) {
638 DEBUG ((DEBUG_WARN, "%a: capsule update successful, resetting ...\n",
639 __FUNCTION__));
640
641 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
642 CpuDeadLoop();
643 }
644 }
645
646
647 #define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "
648
649 /**
650 Do the platform specific action after the console is ready
651 Possible things that can be done in PlatformBootManagerAfterConsole:
652 > Console post action:
653 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
654 > Signal console ready platform customized event
655 > Run diagnostics like memory testing
656 > Connect certain devices
657 > Dispatch aditional option roms
658 > Special boot: e.g.: USB boot, enter UI
659 **/
660 VOID
661 EFIAPI
662 PlatformBootManagerAfterConsole (
663 VOID
664 )
665 {
666 EFI_STATUS Status;
667 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
668 UINTN FirmwareVerLength;
669 UINTN PosX;
670 UINTN PosY;
671
672 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
673
674 //
675 // Show the splash screen.
676 //
677 Status = BootLogoEnableLogo ();
678 if (EFI_ERROR (Status)) {
679 if (FirmwareVerLength > 0) {
680 Print (VERSION_STRING_PREFIX L"%s\n",
681 PcdGetPtr (PcdFirmwareVersionString));
682 }
683 Print (L"Press ESCAPE for boot options ");
684 } else if (FirmwareVerLength > 0) {
685 Status = gBS->HandleProtocol (gST->ConsoleOutHandle,
686 &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
687 if (!EFI_ERROR (Status)) {
688 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -
689 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *
690 EFI_GLYPH_WIDTH) / 2;
691 PosY = 0;
692
693 PrintXY (PosX, PosY, NULL, NULL, VERSION_STRING_PREFIX L"%s",
694 PcdGetPtr (PcdFirmwareVersionString));
695 }
696 }
697
698 //
699 // Connect the rest of the devices.
700 //
701 EfiBootManagerConnectAll ();
702
703 //
704 // On ARM, there is currently no reason to use the phased capsule
705 // update approach where some capsules are dispatched before EndOfDxe
706 // and some are dispatched after. So just handle all capsules here,
707 // when the console is up and we can actually give the user some
708 // feedback about what is going on.
709 //
710 HandleCapsules ();
711
712 //
713 // Enumerate all possible boot options.
714 //
715 EfiBootManagerRefreshAllBootOption ();
716
717 //
718 // Register UEFI Shell
719 //
720 PlatformRegisterFvBootOption (
721 &gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE
722 );
723 }
724
725 /**
726 This function is called each second during the boot manager waits the
727 timeout.
728
729 @param TimeoutRemain The remaining timeout.
730 **/
731 VOID
732 EFIAPI
733 PlatformBootManagerWaitCallback (
734 UINT16 TimeoutRemain
735 )
736 {
737 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
738 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
739 UINT16 Timeout;
740 EFI_STATUS Status;
741
742 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
743
744 Black.Raw = 0x00000000;
745 White.Raw = 0x00FFFFFF;
746
747 Status = BootLogoUpdateProgress (
748 White.Pixel,
749 Black.Pixel,
750 L"Press ESCAPE for boot options",
751 White.Pixel,
752 (Timeout - TimeoutRemain) * 100 / Timeout,
753 0
754 );
755 if (EFI_ERROR (Status)) {
756 Print (L".");
757 }
758 }
759
760 /**
761 The function is called when no boot option could be launched,
762 including platform recovery options and options pointing to applications
763 built into firmware volumes.
764
765 If this function returns, BDS attempts to enter an infinite loop.
766 **/
767 VOID
768 EFIAPI
769 PlatformBootManagerUnableToBoot (
770 VOID
771 )
772 {
773 return;
774 }