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