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