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