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