]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2021, 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 Copyright (c) 2021, Semihalf All rights reserved.<BR>
9
10 SPDX-License-Identifier: BSD-2-Clause-Patent
11
12 **/
13
14 #include <IndustryStandard/Pci22.h>
15 #include <Library/BootLogoLib.h>
16 #include <Library/CapsuleLib.h>
17 #include <Library/DevicePathLib.h>
18 #include <Library/HobLib.h>
19 #include <Library/PcdLib.h>
20 #include <Library/UefiBootManagerLib.h>
21 #include <Library/UefiLib.h>
22 #include <Library/UefiRuntimeServicesTableLib.h>
23 #include <Protocol/BootManagerPolicy.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/EsrtManagement.h>
26 #include <Protocol/GraphicsOutput.h>
27 #include <Protocol/LoadedImage.h>
28 #include <Protocol/NonDiscoverableDevice.h>
29 #include <Protocol/PciIo.h>
30 #include <Protocol/PciRootBridgeIo.h>
31 #include <Protocol/PlatformBootManager.h>
32 #include <Guid/BootDiscoveryPolicy.h>
33 #include <Guid/EventGroup.h>
34 #include <Guid/NonDiscoverableDevice.h>
35 #include <Guid/TtyTerm.h>
36 #include <Guid/SerialPortLibVendor.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 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
52 //
53 // VENDOR_DEVICE_PATH SerialDxe
54 //
55 {
56 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
57 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
58 },
59
60 //
61 // UART_DEVICE_PATH Uart
62 //
63 {
64 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
65 0, // Reserved
66 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
67 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
68 FixedPcdGet8 (PcdUartDefaultParity), // Parity
69 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
70 },
71
72 //
73 // VENDOR_DEFINED_DEVICE_PATH TermType
74 //
75 {
76 {
77 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
78 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
79 }
80 //
81 // Guid to be filled in dynamically
82 //
83 },
84
85 //
86 // EFI_DEVICE_PATH_PROTOCOL End
87 //
88 {
89 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
90 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
91 }
92 };
93
94 #pragma pack (1)
95 typedef struct {
96 USB_CLASS_DEVICE_PATH Keyboard;
97 EFI_DEVICE_PATH_PROTOCOL End;
98 } PLATFORM_USB_KEYBOARD;
99 #pragma pack ()
100
101 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
102 //
103 // USB_CLASS_DEVICE_PATH Keyboard
104 //
105 {
106 {
107 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
108 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
109 },
110 0xFFFF, // VendorId: any
111 0xFFFF, // ProductId: any
112 3, // DeviceClass: HID
113 1, // DeviceSubClass: boot
114 1 // DeviceProtocol: keyboard
115 },
116
117 //
118 // EFI_DEVICE_PATH_PROTOCOL End
119 //
120 {
121 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
122 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
123 }
124 };
125
126 /**
127 Check if the handle satisfies a particular condition.
128
129 @param[in] Handle The handle to check.
130 @param[in] ReportText A caller-allocated string passed in for reporting
131 purposes. It must never be NULL.
132
133 @retval TRUE The condition is satisfied.
134 @retval FALSE Otherwise. This includes the case when the condition could not
135 be fully evaluated due to an error.
136 **/
137 typedef
138 BOOLEAN
139 (EFIAPI *FILTER_FUNCTION)(
140 IN EFI_HANDLE Handle,
141 IN CONST CHAR16 *ReportText
142 );
143
144 /**
145 Process a handle.
146
147 @param[in] Handle The handle to process.
148 @param[in] ReportText A caller-allocated string passed in for reporting
149 purposes. It must never be NULL.
150 **/
151 typedef
152 VOID
153 (EFIAPI *CALLBACK_FUNCTION)(
154 IN EFI_HANDLE Handle,
155 IN CONST CHAR16 *ReportText
156 );
157
158 /**
159 Locate all handles that carry the specified protocol, filter them with a
160 callback function, and pass each handle that passes the filter to another
161 callback.
162
163 @param[in] ProtocolGuid The protocol to look for.
164
165 @param[in] Filter The filter function to pass each handle to. If this
166 parameter is NULL, then all handles are processed.
167
168 @param[in] Process The callback function to pass each handle to that
169 clears the filter.
170 **/
171 STATIC
172 VOID
173 FilterAndProcess (
174 IN EFI_GUID *ProtocolGuid,
175 IN FILTER_FUNCTION Filter OPTIONAL,
176 IN CALLBACK_FUNCTION Process
177 )
178 {
179 EFI_STATUS Status;
180 EFI_HANDLE *Handles;
181 UINTN NoHandles;
182 UINTN Idx;
183
184 Status = gBS->LocateHandleBuffer (
185 ByProtocol,
186 ProtocolGuid,
187 NULL /* SearchKey */,
188 &NoHandles,
189 &Handles
190 );
191 if (EFI_ERROR (Status)) {
192 //
193 // This is not an error, just an informative condition.
194 //
195 DEBUG ((
196 DEBUG_VERBOSE,
197 "%a: %g: %r\n",
198 __FUNCTION__,
199 ProtocolGuid,
200 Status
201 ));
202 return;
203 }
204
205 ASSERT (NoHandles > 0);
206 for (Idx = 0; Idx < NoHandles; ++Idx) {
207 CHAR16 *DevicePathText;
208 STATIC CHAR16 Fallback[] = L"<device path unavailable>";
209
210 //
211 // The ConvertDevicePathToText() function handles NULL input transparently.
212 //
213 DevicePathText = ConvertDevicePathToText (
214 DevicePathFromHandle (Handles[Idx]),
215 FALSE, // DisplayOnly
216 FALSE // AllowShortcuts
217 );
218 if (DevicePathText == NULL) {
219 DevicePathText = Fallback;
220 }
221
222 if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
223 Process (Handles[Idx], DevicePathText);
224 }
225
226 if (DevicePathText != Fallback) {
227 FreePool (DevicePathText);
228 }
229 }
230
231 gBS->FreePool (Handles);
232 }
233
234 /**
235 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
236 **/
237 STATIC
238 BOOLEAN
239 EFIAPI
240 IsPciDisplay (
241 IN EFI_HANDLE Handle,
242 IN CONST CHAR16 *ReportText
243 )
244 {
245 EFI_STATUS Status;
246 EFI_PCI_IO_PROTOCOL *PciIo;
247 PCI_TYPE00 Pci;
248
249 Status = gBS->HandleProtocol (
250 Handle,
251 &gEfiPciIoProtocolGuid,
252 (VOID **)&PciIo
253 );
254 if (EFI_ERROR (Status)) {
255 //
256 // This is not an error worth reporting.
257 //
258 return FALSE;
259 }
260
261 Status = PciIo->Pci.Read (
262 PciIo,
263 EfiPciIoWidthUint32,
264 0 /* Offset */,
265 sizeof Pci / sizeof (UINT32),
266 &Pci
267 );
268 if (EFI_ERROR (Status)) {
269 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
270 return FALSE;
271 }
272
273 return IS_PCI_DISPLAY (&Pci);
274 }
275
276 /**
277 This FILTER_FUNCTION checks if a handle corresponds to a non-discoverable
278 USB host controller.
279 **/
280 STATIC
281 BOOLEAN
282 EFIAPI
283 IsUsbHost (
284 IN EFI_HANDLE Handle,
285 IN CONST CHAR16 *ReportText
286 )
287 {
288 NON_DISCOVERABLE_DEVICE *Device;
289 EFI_STATUS Status;
290
291 Status = gBS->HandleProtocol (
292 Handle,
293 &gEdkiiNonDiscoverableDeviceProtocolGuid,
294 (VOID **)&Device
295 );
296 if (EFI_ERROR (Status)) {
297 return FALSE;
298 }
299
300 if (CompareGuid (Device->Type, &gEdkiiNonDiscoverableUhciDeviceGuid) ||
301 CompareGuid (Device->Type, &gEdkiiNonDiscoverableEhciDeviceGuid) ||
302 CompareGuid (Device->Type, &gEdkiiNonDiscoverableXhciDeviceGuid))
303 {
304 return TRUE;
305 }
306
307 return FALSE;
308 }
309
310 /**
311 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
312 the matching driver to produce all first-level child handles.
313 **/
314 STATIC
315 VOID
316 EFIAPI
317 Connect (
318 IN EFI_HANDLE Handle,
319 IN CONST CHAR16 *ReportText
320 )
321 {
322 EFI_STATUS Status;
323
324 Status = gBS->ConnectController (
325 Handle, // ControllerHandle
326 NULL, // DriverImageHandle
327 NULL, // RemainingDevicePath -- produce all children
328 FALSE // Recursive
329 );
330 DEBUG ((
331 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
332 "%a: %s: %r\n",
333 __FUNCTION__,
334 ReportText,
335 Status
336 ));
337 }
338
339 /**
340 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
341 handle, and adds it to ConOut and ErrOut.
342 **/
343 STATIC
344 VOID
345 EFIAPI
346 AddOutput (
347 IN EFI_HANDLE Handle,
348 IN CONST CHAR16 *ReportText
349 )
350 {
351 EFI_STATUS Status;
352 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
353
354 DevicePath = DevicePathFromHandle (Handle);
355 if (DevicePath == NULL) {
356 DEBUG ((
357 DEBUG_ERROR,
358 "%a: %s: handle %p: device path not found\n",
359 __FUNCTION__,
360 ReportText,
361 Handle
362 ));
363 return;
364 }
365
366 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
367 if (EFI_ERROR (Status)) {
368 DEBUG ((
369 DEBUG_ERROR,
370 "%a: %s: adding to ConOut: %r\n",
371 __FUNCTION__,
372 ReportText,
373 Status
374 ));
375 return;
376 }
377
378 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
379 if (EFI_ERROR (Status)) {
380 DEBUG ((
381 DEBUG_ERROR,
382 "%a: %s: adding to ErrOut: %r\n",
383 __FUNCTION__,
384 ReportText,
385 Status
386 ));
387 return;
388 }
389
390 DEBUG ((
391 DEBUG_VERBOSE,
392 "%a: %s: added to ConOut and ErrOut\n",
393 __FUNCTION__,
394 ReportText
395 ));
396 }
397
398 STATIC
399 VOID
400 PlatformRegisterFvBootOption (
401 CONST EFI_GUID *FileGuid,
402 CHAR16 *Description,
403 UINT32 Attributes,
404 EFI_INPUT_KEY *Key
405 )
406 {
407 EFI_STATUS Status;
408 INTN OptionIndex;
409 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
410 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
411 UINTN BootOptionCount;
412 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
413 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
414 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
415
416 Status = gBS->HandleProtocol (
417 gImageHandle,
418 &gEfiLoadedImageProtocolGuid,
419 (VOID **)&LoadedImage
420 );
421 ASSERT_EFI_ERROR (Status);
422
423 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
424 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
425 ASSERT (DevicePath != NULL);
426 DevicePath = AppendDevicePathNode (
427 DevicePath,
428 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
429 );
430 ASSERT (DevicePath != NULL);
431
432 Status = EfiBootManagerInitializeLoadOption (
433 &NewOption,
434 LoadOptionNumberUnassigned,
435 LoadOptionTypeBoot,
436 Attributes,
437 Description,
438 DevicePath,
439 NULL,
440 0
441 );
442 ASSERT_EFI_ERROR (Status);
443 FreePool (DevicePath);
444
445 BootOptions = EfiBootManagerGetLoadOptions (
446 &BootOptionCount,
447 LoadOptionTypeBoot
448 );
449
450 OptionIndex = EfiBootManagerFindLoadOption (
451 &NewOption,
452 BootOptions,
453 BootOptionCount
454 );
455
456 if (OptionIndex == -1) {
457 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
458 ASSERT_EFI_ERROR (Status);
459 Status = EfiBootManagerAddKeyOptionVariable (
460 NULL,
461 (UINT16)NewOption.OptionNumber,
462 0,
463 Key,
464 NULL
465 );
466 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
467 }
468
469 EfiBootManagerFreeLoadOption (&NewOption);
470 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
471 }
472
473 STATIC
474 VOID
475 GetPlatformOptions (
476 VOID
477 )
478 {
479 EFI_STATUS Status;
480 EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;
481 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
482 EFI_INPUT_KEY *BootKeys;
483 PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;
484 UINTN CurrentBootOptionCount;
485 UINTN Index;
486 UINTN BootCount;
487
488 Status = gBS->LocateProtocol (
489 &gPlatformBootManagerProtocolGuid,
490 NULL,
491 (VOID **)&PlatformBootManager
492 );
493 if (EFI_ERROR (Status)) {
494 return;
495 }
496
497 Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (
498 &BootCount,
499 &BootOptions,
500 &BootKeys
501 );
502 if (EFI_ERROR (Status)) {
503 return;
504 }
505
506 //
507 // Fetch the existent boot options. If there are none, CurrentBootCount
508 // will be zeroed.
509 //
510 CurrentBootOptions = EfiBootManagerGetLoadOptions (
511 &CurrentBootOptionCount,
512 LoadOptionTypeBoot
513 );
514 //
515 // Process the platform boot options.
516 //
517 for (Index = 0; Index < BootCount; Index++) {
518 INTN Match;
519 UINTN BootOptionNumber;
520
521 //
522 // If there are any preexistent boot options, and the subject platform boot
523 // option is already among them, then don't try to add it. Just get its
524 // assigned boot option number so we can associate a hotkey with it. Note
525 // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions
526 // == NULL) if (CurrentBootCount == 0).
527 //
528 Match = EfiBootManagerFindLoadOption (
529 &BootOptions[Index],
530 CurrentBootOptions,
531 CurrentBootOptionCount
532 );
533 if (Match >= 0) {
534 BootOptionNumber = CurrentBootOptions[Match].OptionNumber;
535 } else {
536 //
537 // Add the platform boot options as a new one, at the end of the boot
538 // order. Note that if the platform provided this boot option with an
539 // unassigned option number, then the below function call will assign a
540 // number.
541 //
542 Status = EfiBootManagerAddLoadOptionVariable (
543 &BootOptions[Index],
544 MAX_UINTN
545 );
546 if (EFI_ERROR (Status)) {
547 DEBUG ((
548 DEBUG_ERROR,
549 "%a: failed to register \"%s\": %r\n",
550 __FUNCTION__,
551 BootOptions[Index].Description,
552 Status
553 ));
554 continue;
555 }
556
557 BootOptionNumber = BootOptions[Index].OptionNumber;
558 }
559
560 //
561 // Register a hotkey with the boot option, if requested.
562 //
563 if (BootKeys[Index].UnicodeChar == L'\0') {
564 continue;
565 }
566
567 Status = EfiBootManagerAddKeyOptionVariable (
568 NULL,
569 BootOptionNumber,
570 0,
571 &BootKeys[Index],
572 NULL
573 );
574 if (EFI_ERROR (Status)) {
575 DEBUG ((
576 DEBUG_ERROR,
577 "%a: failed to register hotkey for \"%s\": %r\n",
578 __FUNCTION__,
579 BootOptions[Index].Description,
580 Status
581 ));
582 }
583 }
584
585 EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);
586 EfiBootManagerFreeLoadOptions (BootOptions, BootCount);
587 FreePool (BootKeys);
588 }
589
590 STATIC
591 VOID
592 PlatformRegisterOptionsAndKeys (
593 VOID
594 )
595 {
596 EFI_STATUS Status;
597 EFI_INPUT_KEY Enter;
598 EFI_INPUT_KEY F2;
599 EFI_INPUT_KEY Esc;
600 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
601
602 GetPlatformOptions ();
603
604 //
605 // Register ENTER as CONTINUE key
606 //
607 Enter.ScanCode = SCAN_NULL;
608 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
609 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
610 ASSERT_EFI_ERROR (Status);
611
612 //
613 // Map F2 and ESC to Boot Manager Menu
614 //
615 F2.ScanCode = SCAN_F2;
616 F2.UnicodeChar = CHAR_NULL;
617 Esc.ScanCode = SCAN_ESC;
618 Esc.UnicodeChar = CHAR_NULL;
619 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
620 ASSERT_EFI_ERROR (Status);
621 Status = EfiBootManagerAddKeyOptionVariable (
622 NULL,
623 (UINT16)BootOption.OptionNumber,
624 0,
625 &F2,
626 NULL
627 );
628 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
629 Status = EfiBootManagerAddKeyOptionVariable (
630 NULL,
631 (UINT16)BootOption.OptionNumber,
632 0,
633 &Esc,
634 NULL
635 );
636 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
637 }
638
639 //
640 // BDS Platform Functions
641 //
642
643 /**
644 Do the platform init, can be customized by OEM/IBV
645 Possible things that can be done in PlatformBootManagerBeforeConsole:
646 > Update console variable: 1. include hot-plug devices;
647 > 2. Clear ConIn and add SOL for AMT
648 > Register new Driver#### or Boot####
649 > Register new Key####: e.g.: F12
650 > Signal ReadyToLock event
651 > Authentication action: 1. connect Auth devices;
652 > 2. Identify auto logon user.
653 **/
654 VOID
655 EFIAPI
656 PlatformBootManagerBeforeConsole (
657 VOID
658 )
659 {
660 //
661 // Signal EndOfDxe PI Event
662 //
663 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
664
665 //
666 // Dispatch deferred images after EndOfDxe event.
667 //
668 EfiBootManagerDispatchDeferredImages ();
669
670 //
671 // Locate the PCI root bridges and make the PCI bus driver connect each,
672 // non-recursively. This will produce a number of child handles with PciIo on
673 // them.
674 //
675 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
676
677 //
678 // Find all display class PCI devices (using the handles from the previous
679 // step), and connect them non-recursively. This should produce a number of
680 // child handles with GOPs on them.
681 //
682 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
683
684 //
685 // Now add the device path of all handles with GOP on them to ConOut and
686 // ErrOut.
687 //
688 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
689
690 //
691 // The core BDS code connects short-form USB device paths by explicitly
692 // looking for handles with PCI I/O installed, and checking the PCI class
693 // code whether it matches the one for a USB host controller. This means
694 // non-discoverable USB host controllers need to have the non-discoverable
695 // PCI driver attached first.
696 //
697 FilterAndProcess (&gEdkiiNonDiscoverableDeviceProtocolGuid, IsUsbHost, Connect);
698
699 //
700 // Add the hardcoded short-form USB keyboard device path to ConIn.
701 //
702 EfiBootManagerUpdateConsoleVariable (
703 ConIn,
704 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
705 NULL
706 );
707
708 //
709 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
710 //
711 STATIC_ASSERT (
712 FixedPcdGet8 (PcdDefaultTerminalType) == 4,
713 "PcdDefaultTerminalType must be TTYTERM"
714 );
715 STATIC_ASSERT (
716 FixedPcdGet8 (PcdUartDefaultParity) != 0,
717 "PcdUartDefaultParity must be set to an actual value, not 'default'"
718 );
719 STATIC_ASSERT (
720 FixedPcdGet8 (PcdUartDefaultStopBits) != 0,
721 "PcdUartDefaultStopBits must be set to an actual value, not 'default'"
722 );
723
724 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
725
726 EfiBootManagerUpdateConsoleVariable (
727 ConIn,
728 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
729 NULL
730 );
731 EfiBootManagerUpdateConsoleVariable (
732 ConOut,
733 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
734 NULL
735 );
736 EfiBootManagerUpdateConsoleVariable (
737 ErrOut,
738 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
739 NULL
740 );
741
742 //
743 // Register platform-specific boot options and keyboard shortcuts.
744 //
745 PlatformRegisterOptionsAndKeys ();
746 }
747
748 STATIC
749 VOID
750 HandleCapsules (
751 VOID
752 )
753 {
754 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
755 EFI_PEI_HOB_POINTERS HobPointer;
756 EFI_CAPSULE_HEADER *CapsuleHeader;
757 BOOLEAN NeedReset;
758 EFI_STATUS Status;
759
760 DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));
761
762 Status = gBS->LocateProtocol (
763 &gEsrtManagementProtocolGuid,
764 NULL,
765 (VOID **)&EsrtManagement
766 );
767 if (!EFI_ERROR (Status)) {
768 EsrtManagement->SyncEsrtFmp ();
769 }
770
771 //
772 // Find all capsule images from hob
773 //
774 HobPointer.Raw = GetHobList ();
775 NeedReset = FALSE;
776 while ((HobPointer.Raw = GetNextHob (
777 EFI_HOB_TYPE_UEFI_CAPSULE,
778 HobPointer.Raw
779 )) != NULL)
780 {
781 CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;
782
783 Status = ProcessCapsuleImage (CapsuleHeader);
784 if (EFI_ERROR (Status)) {
785 DEBUG ((
786 DEBUG_ERROR,
787 "%a: failed to process capsule %p - %r\n",
788 __FUNCTION__,
789 CapsuleHeader,
790 Status
791 ));
792 return;
793 }
794
795 NeedReset = TRUE;
796 HobPointer.Raw = GET_NEXT_HOB (HobPointer);
797 }
798
799 if (NeedReset) {
800 DEBUG ((
801 DEBUG_WARN,
802 "%a: capsule update successful, resetting ...\n",
803 __FUNCTION__
804 ));
805
806 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
807 CpuDeadLoop ();
808 }
809 }
810
811 #define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "
812
813 /**
814 This functions checks the value of BootDiscoverPolicy variable and
815 connect devices of class specified by that variable. Then it refreshes
816 Boot order for newly discovered boot device.
817
818 @retval EFI_SUCCESS Devices connected successfully or connection
819 not required.
820 @retval others Return values from GetVariable(), LocateProtocol()
821 and ConnectDeviceClass().
822 **/
823 STATIC
824 EFI_STATUS
825 BootDiscoveryPolicyHandler (
826 VOID
827 )
828 {
829 EFI_STATUS Status;
830 UINT32 DiscoveryPolicy;
831 UINT32 DiscoveryPolicyOld;
832 UINTN Size;
833 EFI_BOOT_MANAGER_POLICY_PROTOCOL *BMPolicy;
834 EFI_GUID *Class;
835
836 Size = sizeof (DiscoveryPolicy);
837 Status = gRT->GetVariable (
838 BOOT_DISCOVERY_POLICY_VAR,
839 &gBootDiscoveryPolicyMgrFormsetGuid,
840 NULL,
841 &Size,
842 &DiscoveryPolicy
843 );
844 if (Status == EFI_NOT_FOUND) {
845 DiscoveryPolicy = PcdGet32 (PcdBootDiscoveryPolicy);
846 Status = PcdSet32S (PcdBootDiscoveryPolicy, DiscoveryPolicy);
847 if (Status == EFI_NOT_FOUND) {
848 return EFI_SUCCESS;
849 } else if (EFI_ERROR (Status)) {
850 return Status;
851 }
852 } else if (EFI_ERROR (Status)) {
853 return Status;
854 }
855
856 if (DiscoveryPolicy == BDP_CONNECT_MINIMAL) {
857 return EFI_SUCCESS;
858 }
859
860 switch (DiscoveryPolicy) {
861 case BDP_CONNECT_NET:
862 Class = &gEfiBootManagerPolicyNetworkGuid;
863 break;
864 case BDP_CONNECT_ALL:
865 Class = &gEfiBootManagerPolicyConnectAllGuid;
866 break;
867 default:
868 DEBUG ((
869 DEBUG_INFO,
870 "%a - Unexpected DiscoveryPolicy (0x%x). Run Minimal Discovery Policy\n",
871 __FUNCTION__,
872 DiscoveryPolicy
873 ));
874 return EFI_SUCCESS;
875 }
876
877 Status = gBS->LocateProtocol (
878 &gEfiBootManagerPolicyProtocolGuid,
879 NULL,
880 (VOID **)&BMPolicy
881 );
882 if (EFI_ERROR (Status)) {
883 DEBUG ((
884 DEBUG_INFO,
885 "%a - Failed to locate gEfiBootManagerPolicyProtocolGuid."
886 "Driver connect will be skipped.\n",
887 __FUNCTION__
888 ));
889 return Status;
890 }
891
892 Status = BMPolicy->ConnectDeviceClass (BMPolicy, Class);
893 if (EFI_ERROR (Status)) {
894 DEBUG ((DEBUG_ERROR, "%a - ConnectDeviceClass returns - %r\n", __FUNCTION__, Status));
895 return Status;
896 }
897
898 //
899 // Refresh Boot Options if Boot Discovery Policy has been changed
900 //
901 Size = sizeof (DiscoveryPolicyOld);
902 Status = gRT->GetVariable (
903 BOOT_DISCOVERY_POLICY_OLD_VAR,
904 &gBootDiscoveryPolicyMgrFormsetGuid,
905 NULL,
906 &Size,
907 &DiscoveryPolicyOld
908 );
909 if ((Status == EFI_NOT_FOUND) || (DiscoveryPolicyOld != DiscoveryPolicy)) {
910 EfiBootManagerRefreshAllBootOption ();
911
912 Status = gRT->SetVariable (
913 BOOT_DISCOVERY_POLICY_OLD_VAR,
914 &gBootDiscoveryPolicyMgrFormsetGuid,
915 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
916 sizeof (DiscoveryPolicyOld),
917 &DiscoveryPolicy
918 );
919 }
920
921 return EFI_SUCCESS;
922 }
923
924 /**
925 Do the platform specific action after the console is ready
926 Possible things that can be done in PlatformBootManagerAfterConsole:
927 > Console post action:
928 > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
929 > Signal console ready platform customized event
930 > Run diagnostics like memory testing
931 > Connect certain devices
932 > Dispatch additional option roms
933 > Special boot: e.g.: USB boot, enter UI
934 **/
935 VOID
936 EFIAPI
937 PlatformBootManagerAfterConsole (
938 VOID
939 )
940 {
941 EFI_STATUS Status;
942 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
943 UINTN FirmwareVerLength;
944 UINTN PosX;
945 UINTN PosY;
946 EFI_INPUT_KEY Key;
947
948 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
949
950 //
951 // Show the splash screen.
952 //
953 Status = BootLogoEnableLogo ();
954 if (EFI_ERROR (Status)) {
955 if (FirmwareVerLength > 0) {
956 Print (
957 VERSION_STRING_PREFIX L"%s\n",
958 PcdGetPtr (PcdFirmwareVersionString)
959 );
960 }
961
962 Print (L"Press ESCAPE for boot options ");
963 } else if (FirmwareVerLength > 0) {
964 Status = gBS->HandleProtocol (
965 gST->ConsoleOutHandle,
966 &gEfiGraphicsOutputProtocolGuid,
967 (VOID **)&GraphicsOutput
968 );
969 if (!EFI_ERROR (Status)) {
970 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -
971 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *
972 EFI_GLYPH_WIDTH) / 2;
973 PosY = 0;
974
975 PrintXY (
976 PosX,
977 PosY,
978 NULL,
979 NULL,
980 VERSION_STRING_PREFIX L"%s",
981 PcdGetPtr (PcdFirmwareVersionString)
982 );
983 }
984 }
985
986 //
987 // Connect device specified by BootDiscoverPolicy variable and
988 // refresh Boot order for newly discovered boot devices
989 //
990 BootDiscoveryPolicyHandler ();
991
992 //
993 // On ARM, there is currently no reason to use the phased capsule
994 // update approach where some capsules are dispatched before EndOfDxe
995 // and some are dispatched after. So just handle all capsules here,
996 // when the console is up and we can actually give the user some
997 // feedback about what is going on.
998 //
999 HandleCapsules ();
1000
1001 //
1002 // Register UEFI Shell
1003 //
1004 Key.ScanCode = SCAN_NULL;
1005 Key.UnicodeChar = L's';
1006 PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", 0, &Key);
1007 }
1008
1009 /**
1010 This function is called each second during the boot manager waits the
1011 timeout.
1012
1013 @param TimeoutRemain The remaining timeout.
1014 **/
1015 VOID
1016 EFIAPI
1017 PlatformBootManagerWaitCallback (
1018 UINT16 TimeoutRemain
1019 )
1020 {
1021 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1022 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1023 UINT16 Timeout;
1024 EFI_STATUS Status;
1025
1026 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1027
1028 Black.Raw = 0x00000000;
1029 White.Raw = 0x00FFFFFF;
1030
1031 Status = BootLogoUpdateProgress (
1032 White.Pixel,
1033 Black.Pixel,
1034 L"Press ESCAPE for boot options",
1035 White.Pixel,
1036 (Timeout - TimeoutRemain) * 100 / Timeout,
1037 0
1038 );
1039 if (EFI_ERROR (Status)) {
1040 Print (L".");
1041 }
1042 }
1043
1044 /**
1045 The function is called when no boot option could be launched,
1046 including platform recovery options and options pointing to applications
1047 built into firmware volumes.
1048
1049 If this function returns, BDS attempts to enter an infinite loop.
1050 **/
1051 VOID
1052 EFIAPI
1053 PlatformBootManagerUnableToBoot (
1054 VOID
1055 )
1056 {
1057 EFI_STATUS Status;
1058 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
1059 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1060 UINTN OldBootOptionCount;
1061 UINTN NewBootOptionCount;
1062
1063 //
1064 // Record the total number of boot configured boot options
1065 //
1066 BootOptions = EfiBootManagerGetLoadOptions (
1067 &OldBootOptionCount,
1068 LoadOptionTypeBoot
1069 );
1070 EfiBootManagerFreeLoadOptions (BootOptions, OldBootOptionCount);
1071
1072 //
1073 // Connect all devices, and regenerate all boot options
1074 //
1075 EfiBootManagerConnectAll ();
1076 EfiBootManagerRefreshAllBootOption ();
1077
1078 //
1079 // Record the updated number of boot configured boot options
1080 //
1081 BootOptions = EfiBootManagerGetLoadOptions (
1082 &NewBootOptionCount,
1083 LoadOptionTypeBoot
1084 );
1085 EfiBootManagerFreeLoadOptions (BootOptions, NewBootOptionCount);
1086
1087 //
1088 // If the number of configured boot options has changed, reboot
1089 // the system so the new boot options will be taken into account
1090 // while executing the ordinary BDS bootflow sequence.
1091 // *Unless* persistent varstore is being emulated, since we would
1092 // then end up in an endless reboot loop.
1093 //
1094 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
1095 if (NewBootOptionCount != OldBootOptionCount) {
1096 DEBUG ((
1097 DEBUG_WARN,
1098 "%a: rebooting after refreshing all boot options\n",
1099 __FUNCTION__
1100 ));
1101 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
1102 }
1103 }
1104
1105 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
1106 if (EFI_ERROR (Status)) {
1107 return;
1108 }
1109
1110 for ( ; ;) {
1111 EfiBootManagerBoot (&BootManagerMenu);
1112 }
1113 }