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