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