]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmVirtPkg / Library / PlatformBootManagerLib / PlatformBm.c
1 /** @file
2 Implementation for PlatformBootManagerLib library class interfaces.
3
4 Copyright (C) 2015-2016, Red Hat, Inc.
5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <IndustryStandard/Pci22.h>
13 #include <IndustryStandard/Virtio095.h>
14 #include <Library/BootLogoLib.h>
15 #include <Library/DevicePathLib.h>
16 #include <Library/PcdLib.h>
17 #include <Library/PlatformBmPrintScLib.h>
18 #include <Library/QemuBootOrderLib.h>
19 #include <Library/TpmPlatformHierarchyLib.h>
20 #include <Library/UefiBootManagerLib.h>
21 #include <Protocol/DevicePath.h>
22 #include <Protocol/FirmwareVolume2.h>
23 #include <Protocol/GraphicsOutput.h>
24 #include <Protocol/LoadedImage.h>
25 #include <Protocol/PciIo.h>
26 #include <Protocol/PciRootBridgeIo.h>
27 #include <Protocol/VirtioDevice.h>
28 #include <Guid/EventGroup.h>
29 #include <Guid/GlobalVariable.h>
30 #include <Guid/RootBridgesConnectedEventGroup.h>
31 #include <Guid/SerialPortLibVendor.h>
32
33 #include "PlatformBm.h"
34
35 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
36
37 #pragma pack (1)
38 typedef struct {
39 VENDOR_DEVICE_PATH SerialDxe;
40 UART_DEVICE_PATH Uart;
41 VENDOR_DEFINED_DEVICE_PATH TermType;
42 EFI_DEVICE_PATH_PROTOCOL End;
43 } PLATFORM_SERIAL_CONSOLE;
44 #pragma pack ()
45
46 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
47 //
48 // VENDOR_DEVICE_PATH SerialDxe
49 //
50 {
51 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
52 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
53 },
54
55 //
56 // UART_DEVICE_PATH Uart
57 //
58 {
59 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
60 0, // Reserved
61 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
62 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
63 FixedPcdGet8 (PcdUartDefaultParity), // Parity
64 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
65 },
66
67 //
68 // VENDOR_DEFINED_DEVICE_PATH TermType
69 //
70 {
71 {
72 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
73 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
74 }
75 //
76 // Guid to be filled in dynamically
77 //
78 },
79
80 //
81 // EFI_DEVICE_PATH_PROTOCOL End
82 //
83 {
84 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
85 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
86 }
87 };
88
89 #pragma pack (1)
90 typedef struct {
91 USB_CLASS_DEVICE_PATH Keyboard;
92 EFI_DEVICE_PATH_PROTOCOL End;
93 } PLATFORM_USB_KEYBOARD;
94 #pragma pack ()
95
96 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
97 //
98 // USB_CLASS_DEVICE_PATH Keyboard
99 //
100 {
101 {
102 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
103 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
104 },
105 0xFFFF, // VendorId: any
106 0xFFFF, // ProductId: any
107 3, // DeviceClass: HID
108 1, // DeviceSubClass: boot
109 1 // DeviceProtocol: keyboard
110 },
111
112 //
113 // EFI_DEVICE_PATH_PROTOCOL End
114 //
115 {
116 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
117 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
118 }
119 };
120
121 /**
122 Check if the handle satisfies a particular condition.
123
124 @param[in] Handle The handle to check.
125 @param[in] ReportText A caller-allocated string passed in for reporting
126 purposes. It must never be NULL.
127
128 @retval TRUE The condition is satisfied.
129 @retval FALSE Otherwise. This includes the case when the condition could not
130 be fully evaluated due to an error.
131 **/
132 typedef
133 BOOLEAN
134 (EFIAPI *FILTER_FUNCTION)(
135 IN EFI_HANDLE Handle,
136 IN CONST CHAR16 *ReportText
137 );
138
139 /**
140 Process a handle.
141
142 @param[in] Handle The handle to process.
143 @param[in] ReportText A caller-allocated string passed in for reporting
144 purposes. It must never be NULL.
145 **/
146 typedef
147 VOID
148 (EFIAPI *CALLBACK_FUNCTION)(
149 IN EFI_HANDLE Handle,
150 IN CONST CHAR16 *ReportText
151 );
152
153 /**
154 Locate all handles that carry the specified protocol, filter them with a
155 callback function, and pass each handle that passes the filter to another
156 callback.
157
158 @param[in] ProtocolGuid The protocol to look for.
159
160 @param[in] Filter The filter function to pass each handle to. If this
161 parameter is NULL, then all handles are processed.
162
163 @param[in] Process The callback function to pass each handle to that
164 clears the filter.
165 **/
166 STATIC
167 VOID
168 FilterAndProcess (
169 IN EFI_GUID *ProtocolGuid,
170 IN FILTER_FUNCTION Filter OPTIONAL,
171 IN CALLBACK_FUNCTION Process
172 )
173 {
174 EFI_STATUS Status;
175 EFI_HANDLE *Handles;
176 UINTN NoHandles;
177 UINTN Idx;
178
179 Status = gBS->LocateHandleBuffer (
180 ByProtocol,
181 ProtocolGuid,
182 NULL /* SearchKey */,
183 &NoHandles,
184 &Handles
185 );
186 if (EFI_ERROR (Status)) {
187 //
188 // This is not an error, just an informative condition.
189 //
190 DEBUG ((
191 DEBUG_VERBOSE,
192 "%a: %g: %r\n",
193 __FUNCTION__,
194 ProtocolGuid,
195 Status
196 ));
197 return;
198 }
199
200 ASSERT (NoHandles > 0);
201 for (Idx = 0; Idx < NoHandles; ++Idx) {
202 CHAR16 *DevicePathText;
203 STATIC CHAR16 Fallback[] = L"<device path unavailable>";
204
205 //
206 // The ConvertDevicePathToText() function handles NULL input transparently.
207 //
208 DevicePathText = ConvertDevicePathToText (
209 DevicePathFromHandle (Handles[Idx]),
210 FALSE, // DisplayOnly
211 FALSE // AllowShortcuts
212 );
213 if (DevicePathText == NULL) {
214 DevicePathText = Fallback;
215 }
216
217 if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
218 Process (Handles[Idx], DevicePathText);
219 }
220
221 if (DevicePathText != Fallback) {
222 FreePool (DevicePathText);
223 }
224 }
225
226 gBS->FreePool (Handles);
227 }
228
229 /**
230 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
231 **/
232 STATIC
233 BOOLEAN
234 EFIAPI
235 IsPciDisplay (
236 IN EFI_HANDLE Handle,
237 IN CONST CHAR16 *ReportText
238 )
239 {
240 EFI_STATUS Status;
241 EFI_PCI_IO_PROTOCOL *PciIo;
242 PCI_TYPE00 Pci;
243
244 Status = gBS->HandleProtocol (
245 Handle,
246 &gEfiPciIoProtocolGuid,
247 (VOID **)&PciIo
248 );
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 (
257 PciIo,
258 EfiPciIoWidthUint32,
259 0 /* Offset */,
260 sizeof Pci / sizeof (UINT32),
261 &Pci
262 );
263 if (EFI_ERROR (Status)) {
264 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
265 return FALSE;
266 }
267
268 return IS_PCI_DISPLAY (&Pci);
269 }
270
271 /**
272 This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
273 the VIRTIO_DEVICE_PROTOCOL level.
274 **/
275 STATIC
276 BOOLEAN
277 EFIAPI
278 IsVirtioRng (
279 IN EFI_HANDLE Handle,
280 IN CONST CHAR16 *ReportText
281 )
282 {
283 EFI_STATUS Status;
284 VIRTIO_DEVICE_PROTOCOL *VirtIo;
285
286 Status = gBS->HandleProtocol (
287 Handle,
288 &gVirtioDeviceProtocolGuid,
289 (VOID **)&VirtIo
290 );
291 if (EFI_ERROR (Status)) {
292 return FALSE;
293 }
294
295 return (BOOLEAN)(VirtIo->SubSystemDeviceId ==
296 VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);
297 }
298
299 /**
300 This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
301 the EFI_PCI_IO_PROTOCOL level.
302 **/
303 STATIC
304 BOOLEAN
305 EFIAPI
306 IsVirtioPciRng (
307 IN EFI_HANDLE Handle,
308 IN CONST CHAR16 *ReportText
309 )
310 {
311 EFI_STATUS Status;
312 EFI_PCI_IO_PROTOCOL *PciIo;
313 UINT16 VendorId;
314 UINT16 DeviceId;
315 UINT8 RevisionId;
316 BOOLEAN Virtio10;
317 UINT16 SubsystemId;
318
319 Status = gBS->HandleProtocol (
320 Handle,
321 &gEfiPciIoProtocolGuid,
322 (VOID **)&PciIo
323 );
324 if (EFI_ERROR (Status)) {
325 return FALSE;
326 }
327
328 //
329 // Read and check VendorId.
330 //
331 Status = PciIo->Pci.Read (
332 PciIo,
333 EfiPciIoWidthUint16,
334 PCI_VENDOR_ID_OFFSET,
335 1,
336 &VendorId
337 );
338 if (EFI_ERROR (Status)) {
339 goto PciError;
340 }
341
342 if (VendorId != VIRTIO_VENDOR_ID) {
343 return FALSE;
344 }
345
346 //
347 // Read DeviceId and RevisionId.
348 //
349 Status = PciIo->Pci.Read (
350 PciIo,
351 EfiPciIoWidthUint16,
352 PCI_DEVICE_ID_OFFSET,
353 1,
354 &DeviceId
355 );
356 if (EFI_ERROR (Status)) {
357 goto PciError;
358 }
359
360 Status = PciIo->Pci.Read (
361 PciIo,
362 EfiPciIoWidthUint8,
363 PCI_REVISION_ID_OFFSET,
364 1,
365 &RevisionId
366 );
367 if (EFI_ERROR (Status)) {
368 goto PciError;
369 }
370
371 //
372 // From DeviceId and RevisionId, determine whether the device is a
373 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
374 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
375 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
376 // only be sanity-checked, and SubsystemId will decide.
377 //
378 if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
379 (RevisionId >= 0x01))
380 {
381 Virtio10 = TRUE;
382 } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
383 Virtio10 = FALSE;
384 } else {
385 return FALSE;
386 }
387
388 //
389 // Read and check SubsystemId as dictated by Virtio10.
390 //
391 Status = PciIo->Pci.Read (
392 PciIo,
393 EfiPciIoWidthUint16,
394 PCI_SUBSYSTEM_ID_OFFSET,
395 1,
396 &SubsystemId
397 );
398 if (EFI_ERROR (Status)) {
399 goto PciError;
400 }
401
402 if (Virtio10 && (SubsystemId >= 0x40)) {
403 return TRUE;
404 }
405
406 if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
407 return TRUE;
408 }
409
410 return FALSE;
411
412 PciError:
413 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
414 return FALSE;
415 }
416
417 /**
418 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
419 the matching driver to produce all first-level child handles.
420 **/
421 STATIC
422 VOID
423 EFIAPI
424 Connect (
425 IN EFI_HANDLE Handle,
426 IN CONST CHAR16 *ReportText
427 )
428 {
429 EFI_STATUS Status;
430
431 Status = gBS->ConnectController (
432 Handle, // ControllerHandle
433 NULL, // DriverImageHandle
434 NULL, // RemainingDevicePath -- produce all children
435 FALSE // Recursive
436 );
437 DEBUG ((
438 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
439 "%a: %s: %r\n",
440 __FUNCTION__,
441 ReportText,
442 Status
443 ));
444 }
445
446 /**
447 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
448 handle, and adds it to ConOut and ErrOut.
449 **/
450 STATIC
451 VOID
452 EFIAPI
453 AddOutput (
454 IN EFI_HANDLE Handle,
455 IN CONST CHAR16 *ReportText
456 )
457 {
458 EFI_STATUS Status;
459 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
460
461 DevicePath = DevicePathFromHandle (Handle);
462 if (DevicePath == NULL) {
463 DEBUG ((
464 DEBUG_ERROR,
465 "%a: %s: handle %p: device path not found\n",
466 __FUNCTION__,
467 ReportText,
468 Handle
469 ));
470 return;
471 }
472
473 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
474 if (EFI_ERROR (Status)) {
475 DEBUG ((
476 DEBUG_ERROR,
477 "%a: %s: adding to ConOut: %r\n",
478 __FUNCTION__,
479 ReportText,
480 Status
481 ));
482 return;
483 }
484
485 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
486 if (EFI_ERROR (Status)) {
487 DEBUG ((
488 DEBUG_ERROR,
489 "%a: %s: adding to ErrOut: %r\n",
490 __FUNCTION__,
491 ReportText,
492 Status
493 ));
494 return;
495 }
496
497 DEBUG ((
498 DEBUG_VERBOSE,
499 "%a: %s: added to ConOut and ErrOut\n",
500 __FUNCTION__,
501 ReportText
502 ));
503 }
504
505 STATIC
506 VOID
507 PlatformRegisterFvBootOption (
508 EFI_GUID *FileGuid,
509 CHAR16 *Description,
510 UINT32 Attributes
511 )
512 {
513 EFI_STATUS Status;
514 INTN OptionIndex;
515 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
516 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
517 UINTN BootOptionCount;
518 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
519 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
520 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
521
522 Status = gBS->HandleProtocol (
523 gImageHandle,
524 &gEfiLoadedImageProtocolGuid,
525 (VOID **)&LoadedImage
526 );
527 ASSERT_EFI_ERROR (Status);
528
529 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
530 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
531 ASSERT (DevicePath != NULL);
532 DevicePath = AppendDevicePathNode (
533 DevicePath,
534 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
535 );
536 ASSERT (DevicePath != NULL);
537
538 Status = EfiBootManagerInitializeLoadOption (
539 &NewOption,
540 LoadOptionNumberUnassigned,
541 LoadOptionTypeBoot,
542 Attributes,
543 Description,
544 DevicePath,
545 NULL,
546 0
547 );
548 ASSERT_EFI_ERROR (Status);
549 FreePool (DevicePath);
550
551 BootOptions = EfiBootManagerGetLoadOptions (
552 &BootOptionCount,
553 LoadOptionTypeBoot
554 );
555
556 OptionIndex = EfiBootManagerFindLoadOption (
557 &NewOption,
558 BootOptions,
559 BootOptionCount
560 );
561
562 if (OptionIndex == -1) {
563 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
564 ASSERT_EFI_ERROR (Status);
565 }
566
567 EfiBootManagerFreeLoadOption (&NewOption);
568 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
569 }
570
571 /**
572 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
573 whose device paths do not resolve exactly to an FvFile in the system.
574
575 This removes any boot options that point to binaries built into the firmware
576 and have become stale due to any of the following:
577 - FvMain's base address or size changed (historical),
578 - FvMain's FvNameGuid changed,
579 - the FILE_GUID of the pointed-to binary changed,
580 - the referenced binary is no longer built into the firmware.
581
582 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
583 avoids exact duplicates.
584 **/
585 STATIC
586 VOID
587 RemoveStaleFvFileOptions (
588 VOID
589 )
590 {
591 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
592 UINTN BootOptionCount;
593 UINTN Index;
594
595 BootOptions = EfiBootManagerGetLoadOptions (
596 &BootOptionCount,
597 LoadOptionTypeBoot
598 );
599
600 for (Index = 0; Index < BootOptionCount; ++Index) {
601 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
602 EFI_STATUS Status;
603 EFI_HANDLE FvHandle;
604
605 //
606 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
607 // then keep the boot option.
608 //
609 Node1 = BootOptions[Index].FilePath;
610 if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
611 (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
612 !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
613 (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
614 {
615 continue;
616 }
617
618 //
619 // If the second device path node is not FvFile(...), then keep the boot
620 // option.
621 //
622 Node2 = NextDevicePathNode (Node1);
623 if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
624 (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
625 {
626 continue;
627 }
628
629 //
630 // Locate the Firmware Volume2 protocol instance that is denoted by the
631 // boot option. If this lookup fails (i.e., the boot option references a
632 // firmware volume that doesn't exist), then we'll proceed to delete the
633 // boot option.
634 //
635 SearchNode = Node1;
636 Status = gBS->LocateDevicePath (
637 &gEfiFirmwareVolume2ProtocolGuid,
638 &SearchNode,
639 &FvHandle
640 );
641
642 if (!EFI_ERROR (Status)) {
643 //
644 // The firmware volume was found; now let's see if it contains the FvFile
645 // identified by GUID.
646 //
647 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
648 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
649 UINTN BufferSize;
650 EFI_FV_FILETYPE FoundType;
651 EFI_FV_FILE_ATTRIBUTES FileAttributes;
652 UINT32 AuthenticationStatus;
653
654 Status = gBS->HandleProtocol (
655 FvHandle,
656 &gEfiFirmwareVolume2ProtocolGuid,
657 (VOID **)&FvProtocol
658 );
659 ASSERT_EFI_ERROR (Status);
660
661 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
662 //
663 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
664 // FileAttributes.
665 //
666 Status = FvProtocol->ReadFile (
667 FvProtocol,
668 &FvFileNode->FvFileName, // NameGuid
669 NULL, // Buffer
670 &BufferSize,
671 &FoundType,
672 &FileAttributes,
673 &AuthenticationStatus
674 );
675 if (!EFI_ERROR (Status)) {
676 //
677 // The FvFile was found. Keep the boot option.
678 //
679 continue;
680 }
681 }
682
683 //
684 // Delete the boot option.
685 //
686 Status = EfiBootManagerDeleteLoadOptionVariable (
687 BootOptions[Index].OptionNumber,
688 LoadOptionTypeBoot
689 );
690 DEBUG_CODE_BEGIN ();
691 CHAR16 *DevicePathString;
692
693 DevicePathString = ConvertDevicePathToText (
694 BootOptions[Index].FilePath,
695 FALSE,
696 FALSE
697 );
698 DEBUG ((
699 EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
700 "%a: removing stale Boot#%04x %s: %r\n",
701 __FUNCTION__,
702 (UINT32)BootOptions[Index].OptionNumber,
703 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
704 Status
705 ));
706 if (DevicePathString != NULL) {
707 FreePool (DevicePathString);
708 }
709
710 DEBUG_CODE_END ();
711 }
712
713 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
714 }
715
716 STATIC
717 VOID
718 PlatformRegisterOptionsAndKeys (
719 VOID
720 )
721 {
722 EFI_STATUS Status;
723 EFI_INPUT_KEY Enter;
724 EFI_INPUT_KEY F2;
725 EFI_INPUT_KEY Esc;
726 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
727
728 //
729 // Register ENTER as CONTINUE key
730 //
731 Enter.ScanCode = SCAN_NULL;
732 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
733 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
734 ASSERT_EFI_ERROR (Status);
735
736 //
737 // Map F2 and ESC to Boot Manager Menu
738 //
739 F2.ScanCode = SCAN_F2;
740 F2.UnicodeChar = CHAR_NULL;
741 Esc.ScanCode = SCAN_ESC;
742 Esc.UnicodeChar = CHAR_NULL;
743 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
744 ASSERT_EFI_ERROR (Status);
745 Status = EfiBootManagerAddKeyOptionVariable (
746 NULL,
747 (UINT16)BootOption.OptionNumber,
748 0,
749 &F2,
750 NULL
751 );
752 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
753 Status = EfiBootManagerAddKeyOptionVariable (
754 NULL,
755 (UINT16)BootOption.OptionNumber,
756 0,
757 &Esc,
758 NULL
759 );
760 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
761 }
762
763 //
764 // BDS Platform Functions
765 //
766
767 /**
768 Do the platform init, can be customized by OEM/IBV
769 Possible things that can be done in PlatformBootManagerBeforeConsole:
770 > Update console variable: 1. include hot-plug devices;
771 > 2. Clear ConIn and add SOL for AMT
772 > Register new Driver#### or Boot####
773 > Register new Key####: e.g.: F12
774 > Signal ReadyToLock event
775 > Authentication action: 1. connect Auth devices;
776 > 2. Identify auto logon user.
777 **/
778 VOID
779 EFIAPI
780 PlatformBootManagerBeforeConsole (
781 VOID
782 )
783 {
784 UINT16 FrontPageTimeout;
785 RETURN_STATUS PcdStatus;
786 EFI_STATUS Status;
787
788 //
789 // Signal EndOfDxe PI Event
790 //
791 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
792
793 //
794 // Disable the TPM 2 platform hierarchy
795 //
796 ConfigureTpmPlatformHierarchy ();
797
798 //
799 // Dispatch deferred images after EndOfDxe event.
800 //
801 EfiBootManagerDispatchDeferredImages ();
802
803 //
804 // Locate the PCI root bridges and make the PCI bus driver connect each,
805 // non-recursively. This will produce a number of child handles with PciIo on
806 // them.
807 //
808 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
809
810 //
811 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
812 //
813 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
814
815 //
816 // Find all display class PCI devices (using the handles from the previous
817 // step), and connect them non-recursively. This should produce a number of
818 // child handles with GOPs on them.
819 //
820 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
821
822 //
823 // Now add the device path of all handles with GOP on them to ConOut and
824 // ErrOut.
825 //
826 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
827
828 //
829 // Add the hardcoded short-form USB keyboard device path to ConIn.
830 //
831 EfiBootManagerUpdateConsoleVariable (
832 ConIn,
833 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
834 NULL
835 );
836
837 //
838 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
839 //
840 CopyGuid (
841 &mSerialConsole.TermType.Guid,
842 PcdGetPtr (PcdTerminalTypeGuidBuffer)
843 );
844 EfiBootManagerUpdateConsoleVariable (
845 ConIn,
846 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
847 NULL
848 );
849 EfiBootManagerUpdateConsoleVariable (
850 ConOut,
851 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
852 NULL
853 );
854 EfiBootManagerUpdateConsoleVariable (
855 ErrOut,
856 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
857 NULL
858 );
859
860 //
861 // Set the front page timeout from the QEMU configuration.
862 //
863 FrontPageTimeout = GetFrontPageTimeoutFromQemu ();
864 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);
865 ASSERT_RETURN_ERROR (PcdStatus);
866 //
867 // Reflect the PCD in the standard Timeout variable.
868 //
869 Status = gRT->SetVariable (
870 EFI_TIME_OUT_VARIABLE_NAME,
871 &gEfiGlobalVariableGuid,
872 (EFI_VARIABLE_NON_VOLATILE |
873 EFI_VARIABLE_BOOTSERVICE_ACCESS |
874 EFI_VARIABLE_RUNTIME_ACCESS),
875 sizeof FrontPageTimeout,
876 &FrontPageTimeout
877 );
878 DEBUG ((
879 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
880 "%a: SetVariable(%s, %u): %r\n",
881 __FUNCTION__,
882 EFI_TIME_OUT_VARIABLE_NAME,
883 FrontPageTimeout,
884 Status
885 ));
886
887 //
888 // Register platform-specific boot options and keyboard shortcuts.
889 //
890 PlatformRegisterOptionsAndKeys ();
891
892 //
893 // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO
894 // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.
895 //
896 FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);
897
898 //
899 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
900 // instances on Virtio PCI RNG devices.
901 //
902 FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
903 }
904
905 /**
906 Do the platform specific action after the console is ready
907 Possible things that can be done in PlatformBootManagerAfterConsole:
908 > Console post action:
909 > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
910 > Signal console ready platform customized event
911 > Run diagnostics like memory testing
912 > Connect certain devices
913 > Dispatch additional option roms
914 > Special boot: e.g.: USB boot, enter UI
915 **/
916 VOID
917 EFIAPI
918 PlatformBootManagerAfterConsole (
919 VOID
920 )
921 {
922 RETURN_STATUS Status;
923
924 //
925 // Show the splash screen.
926 //
927 BootLogoEnableLogo ();
928
929 //
930 // Process QEMU's -kernel command line option. The kernel booted this way
931 // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we
932 // connected any and all PCI root bridges, and then signaled the ACPI
933 // platform driver.
934 //
935 TryRunningQemuKernel ();
936
937 //
938 // Connect the purported boot devices.
939 //
940 Status = ConnectDevicesFromQemu ();
941 if (RETURN_ERROR (Status)) {
942 //
943 // Connect the rest of the devices.
944 //
945 EfiBootManagerConnectAll ();
946 }
947
948 //
949 // Enumerate all possible boot options, then filter and reorder them based on
950 // the QEMU configuration.
951 //
952 EfiBootManagerRefreshAllBootOption ();
953
954 //
955 // Register UEFI Shell
956 //
957 PlatformRegisterFvBootOption (
958 &gUefiShellFileGuid,
959 L"EFI Internal Shell",
960 LOAD_OPTION_ACTIVE
961 );
962
963 RemoveStaleFvFileOptions ();
964 SetBootOrderFromQemu ();
965
966 PlatformBmPrintScRegisterHandler ();
967 }
968
969 /**
970 This function is called each second during the boot manager waits the
971 timeout.
972
973 @param TimeoutRemain The remaining timeout.
974 **/
975 VOID
976 EFIAPI
977 PlatformBootManagerWaitCallback (
978 UINT16 TimeoutRemain
979 )
980 {
981 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
982 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
983 UINT16 TimeoutInitial;
984
985 TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
986
987 //
988 // If PcdPlatformBootTimeOut is set to zero, then we consider
989 // that no progress update should be enacted.
990 //
991 if (TimeoutInitial == 0) {
992 return;
993 }
994
995 Black.Raw = 0x00000000;
996 White.Raw = 0x00FFFFFF;
997
998 BootLogoUpdateProgress (
999 White.Pixel,
1000 Black.Pixel,
1001 L"Start boot option",
1002 White.Pixel,
1003 (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
1004 0
1005 );
1006 }
1007
1008 /**
1009 The function is called when no boot option could be launched,
1010 including platform recovery options and options pointing to applications
1011 built into firmware volumes.
1012
1013 If this function returns, BDS attempts to enter an infinite loop.
1014 **/
1015 VOID
1016 EFIAPI
1017 PlatformBootManagerUnableToBoot (
1018 VOID
1019 )
1020 {
1021 EFI_STATUS Status;
1022 EFI_INPUT_KEY Key;
1023 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
1024 UINTN Index;
1025
1026 //
1027 // BootManagerMenu doesn't contain the correct information when return status
1028 // is EFI_NOT_FOUND.
1029 //
1030 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
1031 if (EFI_ERROR (Status)) {
1032 return;
1033 }
1034
1035 //
1036 // Normally BdsDxe does not print anything to the system console, but this is
1037 // a last resort -- the end-user will likely not see any DEBUG messages
1038 // logged in this situation.
1039 //
1040 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1041 // here to see if it makes sense to request and wait for a keypress.
1042 //
1043 if (gST->ConIn != NULL) {
1044 AsciiPrint (
1045 "%a: No bootable option or device was found.\n"
1046 "%a: Press any key to enter the Boot Manager Menu.\n",
1047 gEfiCallerBaseName,
1048 gEfiCallerBaseName
1049 );
1050 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
1051 ASSERT_EFI_ERROR (Status);
1052 ASSERT (Index == 0);
1053
1054 //
1055 // Drain any queued keys.
1056 //
1057 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
1058 //
1059 // just throw away Key
1060 //
1061 }
1062 }
1063
1064 for ( ; ;) {
1065 EfiBootManagerBoot (&BootManagerMenu);
1066 }
1067 }