VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c

Last change on this file was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 56.0 KB
Line 
1/** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include "BdsPlatform.h"
10#include <Guid/RootBridgesConnectedEventGroup.h>
11#include <Guid/SerialPortLibVendor.h>
12#include <Protocol/FirmwareVolume2.h>
13#include <Protocol/VirtioDevice.h>
14#include <Library/PlatformBmPrintScLib.h>
15#include <Library/Tcg2PhysicalPresenceLib.h>
16#include <Library/XenPlatformLib.h>
17#ifdef VBOX
18# include <Library/IoLib.h>
19# include "../../../../DevEFI.h"
20#endif
21
22#include <Library/QemuFwCfgSimpleParserLib.h>
23
24//
25// Global data
26//
27
28VOID *mEfiDevPathNotifyReg;
29EFI_EVENT mEfiDevPathEvent;
30VOID *mEmuVariableEventReg;
31EFI_EVENT mEmuVariableEvent;
32UINT16 mHostBridgeDevId;
33
34//
35// Table of host IRQs matching PCI IRQs A-D
36// (for configuring PCI Interrupt Line register)
37//
38CONST UINT8 PciHostIrqs[] = {
39 0x0a, // LNKA, LNKE
40 0x0a, // LNKB, LNKF
41 0x0b, // LNKC, LNKG
42 0x0b // LNKD, LNKH
43};
44
45//
46// Type definitions
47//
48
49typedef
50EFI_STATUS
51(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
52 IN EFI_HANDLE Handle,
53 IN VOID *Instance,
54 IN VOID *Context
55 );
56
57/**
58 @param[in] Handle - Handle of PCI device instance
59 @param[in] PciIo - PCI IO protocol instance
60 @param[in] Pci - PCI Header register block
61**/
62typedef
63EFI_STATUS
64(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
65 IN EFI_HANDLE Handle,
66 IN EFI_PCI_IO_PROTOCOL *PciIo,
67 IN PCI_TYPE00 *Pci
68 );
69
70//
71// Function prototypes
72//
73
74EFI_STATUS
75VisitAllInstancesOfProtocol (
76 IN EFI_GUID *Id,
77 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
78 IN VOID *Context
79 );
80
81EFI_STATUS
82VisitAllPciInstancesOfProtocol (
83 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
84 );
85
86VOID
87InstallDevicePathCallback (
88 VOID
89 );
90
91/**
92This function checks whether a File exists within the firmware volume.
93
94 @param[in] FilePath Path of the file.
95
96 @return TRUE if the file exists within the volume, false
97 otherwise.
98**/
99BOOLEAN
100FileIsInFv (
101 EFI_DEVICE_PATH_PROTOCOL *FilePath
102 )
103{
104 UINT32 AuthenticationStatus;
105 EFI_FV_FILE_ATTRIBUTES FileAttributes;
106 EFI_DEVICE_PATH_PROTOCOL *SearchNode;
107 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
108 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
109 UINTN BufferSize;
110 EFI_FV_FILETYPE FoundType;
111 EFI_HANDLE FvHandle;
112 EFI_STATUS Status;
113
114 //
115 // Locate the Firmware Volume2 protocol instance that is denoted by the
116 // boot option. If this lookup fails (i.e., the boot option references a
117 // firmware volume that doesn't exist), then we'll proceed to delete the
118 // boot option.
119 //
120 SearchNode = FilePath;
121 Status = gBS->LocateDevicePath (
122 &gEfiFirmwareVolume2ProtocolGuid,
123 &SearchNode,
124 &FvHandle
125 );
126
127 //
128 // File not Found
129 //
130 if (EFI_ERROR (Status)) {
131 return FALSE;
132 }
133
134 //
135 // The firmware volume was found; now let's see if it contains the FvFile
136 // identified by GUID.
137 //
138 Status = gBS->HandleProtocol (
139 FvHandle,
140 &gEfiFirmwareVolume2ProtocolGuid,
141 (VOID **)&FvProtocol
142 );
143 ASSERT_EFI_ERROR (Status);
144
145 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (FilePath);
146 //
147 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
148 // FileAttributes.
149 //
150 Status = FvProtocol->ReadFile (
151 FvProtocol,
152 &FvFileNode->FvFileName, // NameGuid
153 NULL, // Buffer
154 &BufferSize,
155 &FoundType,
156 &FileAttributes,
157 &AuthenticationStatus
158 );
159
160 //
161 // File not Found
162 //
163 if (EFI_ERROR (Status)) {
164 return FALSE;
165 }
166
167 //
168 // The FvFile was found.
169 //
170 return TRUE;
171}
172
173VOID
174PlatformRegisterFvBootOption (
175 EFI_GUID *FileGuid,
176 CHAR16 *Description,
177 UINT32 Attributes,
178 BOOLEAN Enabled
179 )
180{
181 EFI_STATUS Status;
182 INTN OptionIndex;
183 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
184 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
185 UINTN BootOptionCount;
186 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
187 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
188 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
189
190 Status = gBS->HandleProtocol (
191 gImageHandle,
192 &gEfiLoadedImageProtocolGuid,
193 (VOID **)&LoadedImage
194 );
195 ASSERT_EFI_ERROR (Status);
196
197 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
198 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
199 ASSERT (DevicePath != NULL);
200 DevicePath = AppendDevicePathNode (
201 DevicePath,
202 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
203 );
204 ASSERT (DevicePath != NULL);
205
206 //
207 // File is not in firmware, so it is going to be deleted anyway by
208 // RemoveStaleFvFileOptions, let's not add it.
209 //
210 if (!FileIsInFv (DevicePath)) {
211 FreePool (DevicePath);
212 return;
213 }
214
215 Status = EfiBootManagerInitializeLoadOption (
216 &NewOption,
217 LoadOptionNumberUnassigned,
218 LoadOptionTypeBoot,
219 Attributes,
220 Description,
221 DevicePath,
222 NULL,
223 0
224 );
225 ASSERT_EFI_ERROR (Status);
226 FreePool (DevicePath);
227
228 BootOptions = EfiBootManagerGetLoadOptions (
229 &BootOptionCount,
230 LoadOptionTypeBoot
231 );
232
233 OptionIndex = EfiBootManagerFindLoadOption (
234 &NewOption,
235 BootOptions,
236 BootOptionCount
237 );
238
239 if ((OptionIndex == -1) && Enabled) {
240 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
241 ASSERT_EFI_ERROR (Status);
242 } else if ((OptionIndex != -1) && !Enabled) {
243 Status = EfiBootManagerDeleteLoadOptionVariable (
244 BootOptions[OptionIndex].OptionNumber,
245 LoadOptionTypeBoot
246 );
247 ASSERT_EFI_ERROR (Status);
248 }
249
250 EfiBootManagerFreeLoadOption (&NewOption);
251 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
252}
253
254/**
255 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
256 whose device paths do not resolve exactly to an FvFile in the system.
257
258 This removes any boot options that point to binaries built into the firmware
259 and have become stale due to any of the following:
260 - DXEFV's base address or size changed (historical),
261 - DXEFV's FvNameGuid changed,
262 - the FILE_GUID of the pointed-to binary changed,
263 - the referenced binary is no longer built into the firmware.
264
265 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
266 avoids exact duplicates.
267**/
268VOID
269RemoveStaleFvFileOptions (
270 VOID
271 )
272{
273 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
274 UINTN BootOptionCount;
275 UINTN Index;
276
277 BootOptions = EfiBootManagerGetLoadOptions (
278 &BootOptionCount,
279 LoadOptionTypeBoot
280 );
281
282 for (Index = 0; Index < BootOptionCount; ++Index) {
283 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2;
284 EFI_STATUS Status;
285
286 //
287 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
288 // then keep the boot option.
289 //
290
291 Node1 = BootOptions[Index].FilePath;
292 if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
293 (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
294 !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
295 (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
296 {
297 continue;
298 }
299
300 //
301 // If the second device path node is not FvFile(...), then keep the boot
302 // option.
303 //
304 Node2 = NextDevicePathNode (Node1);
305 if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
306 (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
307 {
308 continue;
309 }
310
311 // If file is in firmware then keep the entry
312 if (FileIsInFv (BootOptions[Index].FilePath)) {
313 continue;
314 }
315
316 //
317 // Delete the boot option.
318 //
319 Status = EfiBootManagerDeleteLoadOptionVariable (
320 BootOptions[Index].OptionNumber,
321 LoadOptionTypeBoot
322 );
323 DEBUG_CODE_BEGIN ();
324 CHAR16 *DevicePathString;
325
326 DevicePathString = ConvertDevicePathToText (
327 BootOptions[Index].FilePath,
328 FALSE,
329 FALSE
330 );
331 DEBUG ((
332 EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
333 "%a: removing stale Boot#%04x %s: %r\n",
334 __func__,
335 (UINT32)BootOptions[Index].OptionNumber,
336 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
337 Status
338 ));
339 if (DevicePathString != NULL) {
340 FreePool (DevicePathString);
341 }
342
343 DEBUG_CODE_END ();
344 }
345
346 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
347}
348
349VOID
350RestrictBootOptionsToFirmware (
351 VOID
352 )
353{
354 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
355 UINTN BootOptionCount;
356 UINTN Index;
357
358 BootOptions = EfiBootManagerGetLoadOptions (
359 &BootOptionCount,
360 LoadOptionTypeBoot
361 );
362
363 for (Index = 0; Index < BootOptionCount; ++Index) {
364 EFI_DEVICE_PATH_PROTOCOL *Node1;
365
366 //
367 // If the device path starts with Fv(...),
368 // then keep the boot option.
369 //
370 Node1 = BootOptions[Index].FilePath;
371 if (((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
372 (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
373 {
374 continue;
375 }
376
377 //
378 // Delete the boot option.
379 //
380 EfiBootManagerDeleteLoadOptionVariable (
381 BootOptions[Index].OptionNumber,
382 LoadOptionTypeBoot
383 );
384 }
385
386 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
387}
388
389VOID
390PlatformRegisterOptionsAndKeys (
391 VOID
392 )
393{
394 EFI_STATUS Status;
395 EFI_INPUT_KEY Enter;
396 EFI_INPUT_KEY F2;
397 EFI_INPUT_KEY Esc;
398 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
399
400 //
401 // Register ENTER as CONTINUE key
402 //
403 Enter.ScanCode = SCAN_NULL;
404 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
405 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
406 ASSERT_EFI_ERROR (Status);
407
408 //
409 // Map F2 to Boot Manager Menu
410 //
411 F2.ScanCode = SCAN_F2;
412 F2.UnicodeChar = CHAR_NULL;
413 Esc.ScanCode = SCAN_ESC;
414 Esc.UnicodeChar = CHAR_NULL;
415 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
416 ASSERT_EFI_ERROR (Status);
417 Status = EfiBootManagerAddKeyOptionVariable (
418 NULL,
419 (UINT16)BootOption.OptionNumber,
420 0,
421 &F2,
422 NULL
423 );
424 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
425 Status = EfiBootManagerAddKeyOptionVariable (
426 NULL,
427 (UINT16)BootOption.OptionNumber,
428 0,
429 &Esc,
430 NULL
431 );
432 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
433}
434
435EFI_STATUS
436EFIAPI
437ConnectRootBridge (
438 IN EFI_HANDLE RootBridgeHandle,
439 IN VOID *Instance,
440 IN VOID *Context
441 );
442
443STATIC
444EFI_STATUS
445EFIAPI
446ConnectVirtioPciRng (
447 IN EFI_HANDLE Handle,
448 IN VOID *Instance,
449 IN VOID *Context
450 );
451
452STATIC
453VOID
454SaveS3BootScript (
455 VOID
456 );
457
458//
459// BDS Platform Functions
460//
461
462/**
463 Do the platform init, can be customized by OEM/IBV
464
465 Possible things that can be done in PlatformBootManagerBeforeConsole:
466
467 > Update console variable: 1. include hot-plug devices;
468 > 2. Clear ConIn and add SOL for AMT
469 > Register new Driver#### or Boot####
470 > Register new Key####: e.g.: F12
471 > Signal ReadyToLock event
472 > Authentication action: 1. connect Auth devices;
473 > 2. Identify auto logon user.
474**/
475VOID
476EFIAPI
477PlatformBootManagerBeforeConsole (
478 VOID
479 )
480{
481 EFI_HANDLE Handle;
482 EFI_STATUS Status;
483 UINT16 FrontPageTimeout;
484 RETURN_STATUS PcdStatus;
485
486 DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));
487 InstallDevicePathCallback ();
488
489 VisitAllInstancesOfProtocol (
490 &gEfiPciRootBridgeIoProtocolGuid,
491 ConnectRootBridge,
492 NULL
493 );
494
495 //
496 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
497 //
498 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
499
500 //
501 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
502 // the preparation of S3 system information. That logic has a hard dependency
503 // on the presence of the FACS ACPI table. Since our ACPI tables are only
504 // installed after PCI enumeration completes, we must not trigger the S3 save
505 // earlier, hence we can't signal End-of-Dxe earlier.
506 //
507 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
508
509 if (PcdGetBool (PcdAcpiS3Enable)) {
510 //
511 // Save the boot script too. Note that this will require us to emit the
512 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
513 //
514 SaveS3BootScript ();
515 }
516
517 //
518 // We need to connect all trusted consoles for TCG PP. Here we treat all
519 // consoles in OVMF to be trusted consoles.
520 //
521 // Cloud Hypervisor doesn't emulate any LPC bridge, which is why it must
522 // rely on the serial I/O port to be connected as a console. It reuses the
523 // definition from Xen as it is very generic.
524 //
525 PlatformInitializeConsole (
526 (XenDetected () || PcdGet16 (PcdOvmfHostBridgePciDevId) == CLOUDHV_DEVICE_ID) ? gXenPlatformConsole : gPlatformConsole
527 );
528
529 //
530 // Process TPM PPI request; this may require keyboard input
531 //
532 Tcg2PhysicalPresenceLibProcessRequest (NULL);
533
534 //
535 // Prevent further changes to LockBoxes or SMRAM.
536 // Any TPM 2 Physical Presence Interface opcode must be handled before.
537 //
538 Handle = NULL;
539 Status = gBS->InstallProtocolInterface (
540 &Handle,
541 &gEfiDxeSmmReadyToLockProtocolGuid,
542 EFI_NATIVE_INTERFACE,
543 NULL
544 );
545 ASSERT_EFI_ERROR (Status);
546
547 //
548 // Dispatch deferred images after EndOfDxe event and ReadyToLock
549 // installation.
550 //
551 EfiBootManagerDispatchDeferredImages ();
552
553 //
554 // GPU passthrough only allows Console enablement after ROM image load
555 //
556 PlatformInitializeConsole (
557 XenDetected () ? gXenPlatformConsole : gPlatformConsole
558 );
559
560 FrontPageTimeout = GetFrontPageTimeoutFromQemu ();
561 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);
562 ASSERT_RETURN_ERROR (PcdStatus);
563 //
564 // Reflect the PCD in the standard Timeout variable.
565 //
566 Status = gRT->SetVariable (
567 EFI_TIME_OUT_VARIABLE_NAME,
568 &gEfiGlobalVariableGuid,
569 (EFI_VARIABLE_NON_VOLATILE |
570 EFI_VARIABLE_BOOTSERVICE_ACCESS |
571 EFI_VARIABLE_RUNTIME_ACCESS),
572 sizeof FrontPageTimeout,
573 &FrontPageTimeout
574 );
575 DEBUG ((
576 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
577 "%a: SetVariable(%s, %u): %r\n",
578 __func__,
579 EFI_TIME_OUT_VARIABLE_NAME,
580 FrontPageTimeout,
581 Status
582 ));
583
584 if (!FeaturePcdGet (PcdBootRestrictToFirmware)) {
585 PlatformRegisterOptionsAndKeys ();
586 }
587
588 //
589 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
590 // instances on Virtio PCI RNG devices.
591 //
592 VisitAllInstancesOfProtocol (
593 &gEfiPciIoProtocolGuid,
594 ConnectVirtioPciRng,
595 NULL
596 );
597}
598
599EFI_STATUS
600EFIAPI
601ConnectRootBridge (
602 IN EFI_HANDLE RootBridgeHandle,
603 IN VOID *Instance,
604 IN VOID *Context
605 )
606{
607 EFI_STATUS Status;
608
609 //
610 // Make the PCI bus driver connect the root bridge, non-recursively. This
611 // will produce a number of child handles with PciIo on them.
612 //
613 Status = gBS->ConnectController (
614 RootBridgeHandle, // ControllerHandle
615 NULL, // DriverImageHandle
616 NULL, // RemainingDevicePath -- produce all
617 // children
618 FALSE // Recursive
619 );
620 return Status;
621}
622
623STATIC
624EFI_STATUS
625EFIAPI
626ConnectVirtioPciRng (
627 IN EFI_HANDLE Handle,
628 IN VOID *Instance,
629 IN VOID *Context
630 )
631{
632 EFI_PCI_IO_PROTOCOL *PciIo;
633 EFI_STATUS Status;
634 UINT16 VendorId;
635 UINT16 DeviceId;
636 UINT8 RevisionId;
637 BOOLEAN Virtio10;
638 UINT16 SubsystemId;
639
640 PciIo = Instance;
641
642 //
643 // Read and check VendorId.
644 //
645 Status = PciIo->Pci.Read (
646 PciIo,
647 EfiPciIoWidthUint16,
648 PCI_VENDOR_ID_OFFSET,
649 1,
650 &VendorId
651 );
652 if (EFI_ERROR (Status)) {
653 goto Error;
654 }
655
656 if (VendorId != VIRTIO_VENDOR_ID) {
657 return EFI_SUCCESS;
658 }
659
660 //
661 // Read DeviceId and RevisionId.
662 //
663 Status = PciIo->Pci.Read (
664 PciIo,
665 EfiPciIoWidthUint16,
666 PCI_DEVICE_ID_OFFSET,
667 1,
668 &DeviceId
669 );
670 if (EFI_ERROR (Status)) {
671 goto Error;
672 }
673
674 Status = PciIo->Pci.Read (
675 PciIo,
676 EfiPciIoWidthUint8,
677 PCI_REVISION_ID_OFFSET,
678 1,
679 &RevisionId
680 );
681 if (EFI_ERROR (Status)) {
682 goto Error;
683 }
684
685 //
686 // From DeviceId and RevisionId, determine whether the device is a
687 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
688 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
689 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
690 // only be sanity-checked, and SubsystemId will decide.
691 //
692 if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
693 (RevisionId >= 0x01))
694 {
695 Virtio10 = TRUE;
696 } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
697 Virtio10 = FALSE;
698 } else {
699 return EFI_SUCCESS;
700 }
701
702 //
703 // Read and check SubsystemId as dictated by Virtio10.
704 //
705 Status = PciIo->Pci.Read (
706 PciIo,
707 EfiPciIoWidthUint16,
708 PCI_SUBSYSTEM_ID_OFFSET,
709 1,
710 &SubsystemId
711 );
712 if (EFI_ERROR (Status)) {
713 goto Error;
714 }
715
716 if ((Virtio10 && (SubsystemId >= 0x40)) ||
717 (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)))
718 {
719 Status = gBS->ConnectController (
720 Handle, // ControllerHandle
721 NULL, // DriverImageHandle -- connect all drivers
722 NULL, // RemainingDevicePath -- produce all child handles
723 FALSE // Recursive -- don't follow child handles
724 );
725 if (EFI_ERROR (Status)) {
726 goto Error;
727 }
728
729 gDS->Dispatch ();
730 }
731
732 return EFI_SUCCESS;
733
734Error:
735 DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, Status));
736 return Status;
737}
738
739/**
740 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
741
742 @param[in] DeviceHandle Handle of the LPC Bridge device.
743
744 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
745 ConOut, ConIn, and ErrOut.
746
747 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
748 from DeviceHandle.
749**/
750EFI_STATUS
751PrepareLpcBridgeDevicePath (
752 IN EFI_HANDLE DeviceHandle
753 )
754{
755 EFI_STATUS Status;
756 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
757 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
758 CHAR16 *DevPathStr;
759
760 DevicePath = NULL;
761 Status = gBS->HandleProtocol (
762 DeviceHandle,
763 &gEfiDevicePathProtocolGuid,
764 (VOID *)&DevicePath
765 );
766 if (EFI_ERROR (Status)) {
767 return Status;
768 }
769
770 TempDevicePath = DevicePath;
771
772 //
773 // Register Keyboard
774 //
775 DevicePath = AppendDevicePathNode (
776 DevicePath,
777 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode
778 );
779
780 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
781
782 //
783 // Register COM1
784 //
785 DevicePath = TempDevicePath;
786 gPnp16550ComPortDeviceNode.UID = 0;
787
788 DevicePath = AppendDevicePathNode (
789 DevicePath,
790 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode
791 );
792 DevicePath = AppendDevicePathNode (
793 DevicePath,
794 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
795 );
796 DevicePath = AppendDevicePathNode (
797 DevicePath,
798 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
799 );
800
801 //
802 // Print Device Path
803 //
804 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
805 if (DevPathStr != NULL) {
806 DEBUG ((
807 DEBUG_INFO,
808 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
809 DEBUG_LINE_NUMBER,
810 gPnp16550ComPortDeviceNode.UID + 1,
811 DevPathStr
812 ));
813 FreePool (DevPathStr);
814 }
815
816 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
817 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
818 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
819
820 //
821 // Register COM2
822 //
823 DevicePath = TempDevicePath;
824 gPnp16550ComPortDeviceNode.UID = 1;
825
826 DevicePath = AppendDevicePathNode (
827 DevicePath,
828 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode
829 );
830 DevicePath = AppendDevicePathNode (
831 DevicePath,
832 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
833 );
834 DevicePath = AppendDevicePathNode (
835 DevicePath,
836 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
837 );
838
839 //
840 // Print Device Path
841 //
842 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
843 if (DevPathStr != NULL) {
844 DEBUG ((
845 DEBUG_INFO,
846 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
847 DEBUG_LINE_NUMBER,
848 gPnp16550ComPortDeviceNode.UID + 1,
849 DevPathStr
850 ));
851 FreePool (DevPathStr);
852 }
853
854 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
855 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
856 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
857
858 return EFI_SUCCESS;
859}
860
861typedef struct {
862 VENDOR_DEVICE_PATH Guid;
863 EFI_DEVICE_PATH_PROTOCOL End;
864} SERIAL_DEVICE_PATH;
865
866SERIAL_DEVICE_PATH serialDevicePath = {
867 {
868 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }
869 },
870 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
871 },
872 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
873 }
874};
875
876VOID
877PrepareMicrovmDevicePath (
878 VOID
879 )
880{
881 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
882 UINT16 HostBridgeDevId;
883
884 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
885 if (HostBridgeDevId != MICROVM_PSEUDO_DEVICE_ID) {
886 return;
887 }
888
889 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&serialDevicePath;
890 DevicePath = AppendDevicePathNode (
891 DevicePath,
892 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
893 );
894 DevicePath = AppendDevicePathNode (
895 DevicePath,
896 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
897 );
898
899 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
900 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
901 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
902}
903
904EFI_STATUS
905GetGopDevicePath (
906 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
907 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
908 )
909{
910 UINTN Index;
911 EFI_STATUS Status;
912 EFI_HANDLE PciDeviceHandle;
913 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
914 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
915 UINTN GopHandleCount;
916 EFI_HANDLE *GopHandleBuffer;
917
918 if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) {
919 return EFI_INVALID_PARAMETER;
920 }
921
922 //
923 // Initialize the GopDevicePath to be PciDevicePath
924 //
925 *GopDevicePath = PciDevicePath;
926 TempPciDevicePath = PciDevicePath;
927
928 Status = gBS->LocateDevicePath (
929 &gEfiDevicePathProtocolGuid,
930 &TempPciDevicePath,
931 &PciDeviceHandle
932 );
933 if (EFI_ERROR (Status)) {
934 return Status;
935 }
936
937 //
938 // Try to connect this handle, so that GOP driver could start on this
939 // device and create child handles with GraphicsOutput Protocol installed
940 // on them, then we get device paths of these child handles and select
941 // them as possible console device.
942 //
943 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
944
945 Status = gBS->LocateHandleBuffer (
946 ByProtocol,
947 &gEfiGraphicsOutputProtocolGuid,
948 NULL,
949 &GopHandleCount,
950 &GopHandleBuffer
951 );
952 if (!EFI_ERROR (Status)) {
953 //
954 // Add all the child handles as possible Console Device
955 //
956 for (Index = 0; Index < GopHandleCount; Index++) {
957 Status = gBS->HandleProtocol (
958 GopHandleBuffer[Index],
959 &gEfiDevicePathProtocolGuid,
960 (VOID *)&TempDevicePath
961 );
962 if (EFI_ERROR (Status)) {
963 continue;
964 }
965
966 if (CompareMem (
967 PciDevicePath,
968 TempDevicePath,
969 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
970 ) == 0)
971 {
972 //
973 // In current implementation, we only enable one of the child handles
974 // as console device, i.e. sotre one of the child handle's device
975 // path to variable "ConOut"
976 // In future, we could select all child handles to be console device
977 //
978
979 *GopDevicePath = TempDevicePath;
980
981 //
982 // Delete the PCI device's path that added by
983 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
984 //
985 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
986 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
987 }
988 }
989
990 gBS->FreePool (GopHandleBuffer);
991 }
992
993 return EFI_SUCCESS;
994}
995
996/**
997 Add PCI display to ConOut.
998
999 @param[in] DeviceHandle Handle of the PCI display device.
1000
1001 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
1002
1003 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
1004 from DeviceHandle.
1005**/
1006EFI_STATUS
1007PreparePciDisplayDevicePath (
1008 IN EFI_HANDLE DeviceHandle
1009 )
1010{
1011 EFI_STATUS Status;
1012 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1013 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
1014
1015 DevicePath = NULL;
1016 GopDevicePath = NULL;
1017 Status = gBS->HandleProtocol (
1018 DeviceHandle,
1019 &gEfiDevicePathProtocolGuid,
1020 (VOID *)&DevicePath
1021 );
1022 if (EFI_ERROR (Status)) {
1023 return Status;
1024 }
1025
1026 GetGopDevicePath (DevicePath, &GopDevicePath);
1027 DevicePath = GopDevicePath;
1028
1029 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
1030
1031 return EFI_SUCCESS;
1032}
1033
1034/**
1035 Add PCI Serial to ConOut, ConIn, ErrOut.
1036
1037 @param[in] DeviceHandle Handle of the PCI serial device.
1038
1039 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
1040 ErrOut.
1041
1042 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
1043 from DeviceHandle.
1044**/
1045EFI_STATUS
1046PreparePciSerialDevicePath (
1047 IN EFI_HANDLE DeviceHandle
1048 )
1049{
1050 EFI_STATUS Status;
1051 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1052
1053 DevicePath = NULL;
1054 Status = gBS->HandleProtocol (
1055 DeviceHandle,
1056 &gEfiDevicePathProtocolGuid,
1057 (VOID *)&DevicePath
1058 );
1059 if (EFI_ERROR (Status)) {
1060 return Status;
1061 }
1062
1063 DevicePath = AppendDevicePathNode (
1064 DevicePath,
1065 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
1066 );
1067 DevicePath = AppendDevicePathNode (
1068 DevicePath,
1069 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
1070 );
1071
1072 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
1073 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
1074 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
1075
1076 return EFI_SUCCESS;
1077}
1078
1079EFI_STATUS
1080PrepareVirtioSerialDevicePath (
1081 IN EFI_HANDLE DeviceHandle
1082 )
1083{
1084 EFI_STATUS Status;
1085 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1086
1087 DevicePath = NULL;
1088 Status = gBS->HandleProtocol (
1089 DeviceHandle,
1090 &gEfiDevicePathProtocolGuid,
1091 (VOID *)&DevicePath
1092 );
1093 if (EFI_ERROR (Status)) {
1094 return Status;
1095 }
1096
1097 gPnp16550ComPortDeviceNode.UID = 0;
1098 DevicePath = AppendDevicePathNode (
1099 DevicePath,
1100 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode
1101 );
1102 DevicePath = AppendDevicePathNode (
1103 DevicePath,
1104 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
1105 );
1106 DevicePath = AppendDevicePathNode (
1107 DevicePath,
1108 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
1109 );
1110
1111 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
1112 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
1113 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
1114
1115 return EFI_SUCCESS;
1116}
1117
1118EFI_STATUS
1119PrepareVirtioKeyboardDevicePath (
1120 IN EFI_HANDLE DeviceHandle
1121 )
1122{
1123 EFI_STATUS Status;
1124 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1125
1126 DevicePath = NULL;
1127 Status = gBS->HandleProtocol (
1128 DeviceHandle,
1129 &gEfiDevicePathProtocolGuid,
1130 (VOID *)&DevicePath
1131 );
1132 if (EFI_ERROR (Status)) {
1133 return Status;
1134 }
1135
1136 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
1137 return EFI_SUCCESS;
1138}
1139
1140EFI_STATUS
1141VisitAllInstancesOfProtocol (
1142 IN EFI_GUID *Id,
1143 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
1144 IN VOID *Context
1145 )
1146{
1147 EFI_STATUS Status;
1148 UINTN HandleCount;
1149 EFI_HANDLE *HandleBuffer;
1150 UINTN Index;
1151 VOID *Instance;
1152
1153 //
1154 // Start to check all the PciIo to find all possible device
1155 //
1156 HandleCount = 0;
1157 HandleBuffer = NULL;
1158 Status = gBS->LocateHandleBuffer (
1159 ByProtocol,
1160 Id,
1161 NULL,
1162 &HandleCount,
1163 &HandleBuffer
1164 );
1165 if (EFI_ERROR (Status)) {
1166 return Status;
1167 }
1168
1169 for (Index = 0; Index < HandleCount; Index++) {
1170 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
1171 if (EFI_ERROR (Status)) {
1172 continue;
1173 }
1174
1175 Status = (*CallBackFunction)(
1176 HandleBuffer[Index],
1177 Instance,
1178 Context
1179 );
1180 }
1181
1182 gBS->FreePool (HandleBuffer);
1183
1184 return EFI_SUCCESS;
1185}
1186
1187EFI_STATUS
1188EFIAPI
1189VisitingAPciInstance (
1190 IN EFI_HANDLE Handle,
1191 IN VOID *Instance,
1192 IN VOID *Context
1193 )
1194{
1195 EFI_STATUS Status;
1196 EFI_PCI_IO_PROTOCOL *PciIo;
1197 PCI_TYPE00 Pci;
1198
1199 PciIo = (EFI_PCI_IO_PROTOCOL *)Instance;
1200
1201 //
1202 // Check for all PCI device
1203 //
1204 Status = PciIo->Pci.Read (
1205 PciIo,
1206 EfiPciIoWidthUint32,
1207 0,
1208 sizeof (Pci) / sizeof (UINT32),
1209 &Pci
1210 );
1211 if (EFI_ERROR (Status)) {
1212 return Status;
1213 }
1214
1215 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN)Context)(
1216 Handle,
1217 PciIo,
1218 &Pci
1219 );
1220}
1221
1222EFI_STATUS
1223VisitAllPciInstances (
1224 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
1225 )
1226{
1227 return VisitAllInstancesOfProtocol (
1228 &gEfiPciIoProtocolGuid,
1229 VisitingAPciInstance,
1230 (VOID *)(UINTN)CallBackFunction
1231 );
1232}
1233
1234/**
1235 Do platform specific PCI Device check and add them to
1236 ConOut, ConIn, ErrOut.
1237
1238 @param[in] Handle - Handle of PCI device instance
1239 @param[in] PciIo - PCI IO protocol instance
1240 @param[in] Pci - PCI Header register block
1241
1242 @retval EFI_SUCCESS - PCI Device check and Console variable update
1243 successfully.
1244 @retval EFI_STATUS - PCI Device check or Console variable update fail.
1245
1246**/
1247EFI_STATUS
1248EFIAPI
1249DetectAndPreparePlatformPciDevicePath (
1250 IN EFI_HANDLE Handle,
1251 IN EFI_PCI_IO_PROTOCOL *PciIo,
1252 IN PCI_TYPE00 *Pci
1253 )
1254{
1255 EFI_STATUS Status;
1256
1257 Status = PciIo->Attributes (
1258 PciIo,
1259 EfiPciIoAttributeOperationEnable,
1260 EFI_PCI_DEVICE_ENABLE,
1261 NULL
1262 );
1263 ASSERT_EFI_ERROR (Status);
1264
1265 //
1266 // Here we decide whether it is LPC Bridge
1267 //
1268 if ((IS_PCI_LPC (Pci)) ||
1269 ((IS_PCI_ISA_PDECODE (Pci)) &&
1270 (Pci->Hdr.VendorId == 0x8086) &&
1271 (Pci->Hdr.DeviceId == 0x7000)
1272 )
1273 )
1274 {
1275 //
1276 // Add IsaKeyboard to ConIn,
1277 // add IsaSerial to ConOut, ConIn, ErrOut
1278 //
1279 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));
1280 PrepareLpcBridgeDevicePath (Handle);
1281 return EFI_SUCCESS;
1282 }
1283
1284 //
1285 // Here we decide which Serial device to enable in PCI bus
1286 //
1287 if (IS_PCI_16550SERIAL (Pci)) {
1288 //
1289 // Add them to ConOut, ConIn, ErrOut.
1290 //
1291 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));
1292 PreparePciSerialDevicePath (Handle);
1293 return EFI_SUCCESS;
1294 }
1295
1296 //
1297 // Here we decide which display device to enable in PCI bus
1298 //
1299 if (IS_PCI_DISPLAY (Pci)) {
1300 //
1301 // Add them to ConOut.
1302 //
1303 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));
1304 PreparePciDisplayDevicePath (Handle);
1305 return EFI_SUCCESS;
1306 }
1307
1308 if (((Pci->Hdr.VendorId == 0x1af4) && (Pci->Hdr.DeviceId == 0x1003)) ||
1309 ((Pci->Hdr.VendorId == 0x1af4) && (Pci->Hdr.DeviceId == 0x1043)))
1310 {
1311 DEBUG ((DEBUG_INFO, "Found virtio serial device\n"));
1312 PrepareVirtioSerialDevicePath (Handle);
1313 return EFI_SUCCESS;
1314 }
1315
1316 if ((Pci->Hdr.VendorId == 0x1af4) && (Pci->Hdr.DeviceId == 0x1052)) {
1317 DEBUG ((DEBUG_INFO, "Found virtio keyboard device\n"));
1318 PrepareVirtioKeyboardDevicePath (Handle);
1319 return EFI_SUCCESS;
1320 }
1321
1322 return Status;
1323}
1324
1325EFI_STATUS
1326EFIAPI
1327DetectAndPreparePlatformVirtioDevicePath (
1328 IN EFI_HANDLE Handle,
1329 IN VOID *Instance,
1330 IN VOID *Context
1331 )
1332{
1333 VIRTIO_DEVICE_PROTOCOL *VirtIo = (VIRTIO_DEVICE_PROTOCOL *)Instance;
1334
1335 DEBUG ((DEBUG_INFO, "%a:%d: id %d\n", __func__, __LINE__, VirtIo->SubSystemDeviceId));
1336
1337 switch (VirtIo->SubSystemDeviceId) {
1338 case VIRTIO_SUBSYSTEM_CONSOLE:
1339 PrepareVirtioSerialDevicePath (Handle);
1340 break;
1341 default:
1342 /* nothing */
1343 break;
1344 }
1345
1346 return EFI_SUCCESS;
1347}
1348
1349/**
1350 Connect the predefined platform default console device.
1351
1352 Always try to find and enable PCI display devices.
1353
1354 @param[in] PlatformConsole Predefined platform default console device array.
1355**/
1356VOID
1357PlatformInitializeConsole (
1358 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
1359 )
1360{
1361 UINTN Index;
1362
1363 //
1364 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1365 // ErrOut
1366 //
1367 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
1368
1369 VisitAllInstancesOfProtocol (
1370 &gVirtioDeviceProtocolGuid,
1371 DetectAndPreparePlatformVirtioDevicePath,
1372 NULL
1373 );
1374
1375 PrepareMicrovmDevicePath ();
1376
1377 //
1378 // Have chance to connect the platform default console,
1379 // the platform default console is the minimum device group
1380 // the platform should support
1381 //
1382 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
1383 //
1384 // Update the console variable with the connect type
1385 //
1386 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
1387 EfiBootManagerUpdateConsoleVariable (
1388 ConIn,
1389 PlatformConsole[Index].DevicePath,
1390 NULL
1391 );
1392 }
1393
1394 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
1395 EfiBootManagerUpdateConsoleVariable (
1396 ConOut,
1397 PlatformConsole[Index].DevicePath,
1398 NULL
1399 );
1400 }
1401
1402 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
1403 EfiBootManagerUpdateConsoleVariable (
1404 ErrOut,
1405 PlatformConsole[Index].DevicePath,
1406 NULL
1407 );
1408 }
1409 }
1410}
1411
1412/**
1413 Configure PCI Interrupt Line register for applicable devices
1414 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1415
1416 @param[in] Handle - Handle of PCI device instance
1417 @param[in] PciIo - PCI IO protocol instance
1418 @param[in] PciHdr - PCI Header register block
1419
1420 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1421
1422**/
1423EFI_STATUS
1424EFIAPI
1425SetPciIntLine (
1426 IN EFI_HANDLE Handle,
1427 IN EFI_PCI_IO_PROTOCOL *PciIo,
1428 IN PCI_TYPE00 *PciHdr
1429 )
1430{
1431 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1432 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1433 UINTN RootSlot;
1434 UINTN Idx;
1435 UINT8 IrqLine;
1436 EFI_STATUS Status;
1437 UINT32 RootBusNumber;
1438
1439 Status = EFI_SUCCESS;
1440
1441 if (PciHdr->Device.InterruptPin != 0) {
1442 DevPathNode = DevicePathFromHandle (Handle);
1443 ASSERT (DevPathNode != NULL);
1444 DevPath = DevPathNode;
1445
1446 RootBusNumber = 0;
1447 if ((DevicePathType (DevPathNode) == ACPI_DEVICE_PATH) &&
1448 (DevicePathSubType (DevPathNode) == ACPI_DP) &&
1449 (((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID (0x0A03)))
1450 {
1451 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1452 }
1453
1454 //
1455 // Compute index into PciHostIrqs[] table by walking
1456 // the device path and adding up all device numbers
1457 //
1458 Status = EFI_NOT_FOUND;
1459 RootSlot = 0;
1460 Idx = PciHdr->Device.InterruptPin - 1;
1461 while (!IsDevicePathEnd (DevPathNode)) {
1462 if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&
1463 (DevicePathSubType (DevPathNode) == HW_PCI_DP))
1464 {
1465 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1466
1467 //
1468 // Unlike SeaBIOS, which starts climbing from the leaf device
1469 // up toward the root, we traverse the device path starting at
1470 // the root moving toward the leaf node.
1471 // The slot number of the top-level parent bridge is needed for
1472 // Q35 cases with more than 24 slots on the root bus.
1473 //
1474 if (Status != EFI_SUCCESS) {
1475 Status = EFI_SUCCESS;
1476 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1477 }
1478 }
1479
1480 DevPathNode = NextDevicePathNode (DevPathNode);
1481 }
1482
1483 if (EFI_ERROR (Status)) {
1484 return Status;
1485 }
1486
1487 if ((RootBusNumber == 0) && (RootSlot == 0)) {
1488 DEBUG ((
1489 DEBUG_ERROR,
1490 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1491 __func__
1492 ));
1493 ASSERT (FALSE);
1494 }
1495
1496 //
1497 // Final PciHostIrqs[] index calculation depends on the platform
1498 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1499 //
1500 switch (mHostBridgeDevId) {
1501 case INTEL_82441_DEVICE_ID:
1502 Idx -= 1;
1503 break;
1504 case INTEL_Q35_MCH_DEVICE_ID:
1505 //
1506 // SeaBIOS contains the following comment:
1507 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1508 // with a different starting index - see q35-acpi-dsdt.dsl.
1509 //
1510 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1511 //
1512 if (RootSlot > 24) {
1513 //
1514 // in this case, subtract back out RootSlot from Idx
1515 // (SeaBIOS never adds it to begin with, but that would make our
1516 // device path traversal loop above too awkward)
1517 //
1518 Idx -= RootSlot;
1519 }
1520
1521 break;
1522 default:
1523 ASSERT (FALSE); // should never get here
1524 }
1525
1526 Idx %= ARRAY_SIZE (PciHostIrqs);
1527 IrqLine = PciHostIrqs[Idx];
1528
1529 DEBUG_CODE_BEGIN ();
1530 {
1531 CHAR16 *DevPathString;
1532 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1533 UINTN Segment, Bus, Device, Function;
1534
1535 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1536 if (DevPathString == NULL) {
1537 DevPathString = Fallback;
1538 }
1539
1540 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1541 ASSERT_EFI_ERROR (Status);
1542
1543 DEBUG ((
1544 DEBUG_VERBOSE,
1545 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",
1546 __func__,
1547 (UINT32)Bus,
1548 (UINT32)Device,
1549 (UINT32)Function,
1550 DevPathString,
1551 IrqLine
1552 ));
1553
1554 if (DevPathString != Fallback) {
1555 FreePool (DevPathString);
1556 }
1557 }
1558 DEBUG_CODE_END ();
1559
1560 //
1561 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1562 //
1563 Status = PciIo->Pci.Write (
1564 PciIo,
1565 EfiPciIoWidthUint8,
1566 PCI_INT_LINE_OFFSET,
1567 1,
1568 &IrqLine
1569 );
1570 }
1571
1572 return Status;
1573}
1574
1575VOID
1576PciAcpiInitialization (
1577 )
1578{
1579 UINTN Pmba;
1580
1581 //
1582 // Query Host Bridge DID to determine platform type
1583 //
1584 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1585 switch (mHostBridgeDevId) {
1586 case INTEL_82441_DEVICE_ID:
1587 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1588 //
1589 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1590 //
1591 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // A
1592 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // B
1593 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // C
1594 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // D
1595 break;
1596 case INTEL_Q35_MCH_DEVICE_ID:
1597 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1598 //
1599 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1600 //
1601 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // A
1602 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // B
1603 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // C
1604 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // D
1605 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // E
1606 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // F
1607 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // G
1608 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // H
1609 break;
1610 case MICROVM_PSEUDO_DEVICE_ID:
1611 case CLOUDHV_DEVICE_ID:
1612 return;
1613 default:
1614 if (XenDetected ()) {
1615 //
1616 // There is no PCI bus in this case.
1617 //
1618 return;
1619 }
1620
1621 DEBUG ((
1622 DEBUG_ERROR,
1623 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1624 __func__,
1625 mHostBridgeDevId
1626 ));
1627 ASSERT (FALSE);
1628 return;
1629 }
1630
1631 //
1632 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1633 //
1634 VisitAllPciInstances (SetPciIntLine);
1635
1636 //
1637 // Set ACPI SCI_EN bit in PMCNTRL
1638 //
1639 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1640}
1641
1642EFI_STATUS
1643EFIAPI
1644ConnectRecursivelyIfPciMassStorage (
1645 IN EFI_HANDLE Handle,
1646 IN EFI_PCI_IO_PROTOCOL *Instance,
1647 IN PCI_TYPE00 *PciHeader
1648 )
1649{
1650 EFI_STATUS Status;
1651 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1652 CHAR16 *DevPathStr;
1653
1654 //
1655 // Recognize PCI Mass Storage, and Xen PCI devices
1656 //
1657 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
1658 (XenDetected () && IS_CLASS2 (PciHeader, 0xFF, 0x80)))
1659 {
1660 DevicePath = NULL;
1661 Status = gBS->HandleProtocol (
1662 Handle,
1663 &gEfiDevicePathProtocolGuid,
1664 (VOID *)&DevicePath
1665 );
1666 if (EFI_ERROR (Status)) {
1667 return Status;
1668 }
1669
1670 //
1671 // Print Device Path
1672 //
1673 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1674 if (DevPathStr != NULL) {
1675 DEBUG ((
1676 DEBUG_INFO,
1677 "Found %s device: %s\n",
1678 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?
1679 L"Mass Storage" :
1680 L"Xen"
1681 ),
1682 DevPathStr
1683 ));
1684 FreePool (DevPathStr);
1685 }
1686
1687 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1688 if (EFI_ERROR (Status)) {
1689 return Status;
1690 }
1691 }
1692
1693 return EFI_SUCCESS;
1694}
1695
1696/**
1697 This notification function is invoked when the
1698 EMU Variable FVB has been changed.
1699
1700 @param Event The event that occurred
1701 @param Context For EFI compatibility. Not used.
1702
1703**/
1704VOID
1705EFIAPI
1706EmuVariablesUpdatedCallback (
1707 IN EFI_EVENT Event,
1708 IN VOID *Context
1709 )
1710{
1711 DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n"));
1712 UpdateNvVarsOnFileSystem ();
1713}
1714
1715EFI_STATUS
1716EFIAPI
1717VisitingFileSystemInstance (
1718 IN EFI_HANDLE Handle,
1719 IN VOID *Instance,
1720 IN VOID *Context
1721 )
1722{
1723 EFI_STATUS Status;
1724 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1725 RETURN_STATUS PcdStatus;
1726
1727 if (ConnectedToFileSystem) {
1728 return EFI_ALREADY_STARTED;
1729 }
1730
1731 Status = ConnectNvVarsToFileSystem (Handle);
1732 if (EFI_ERROR (Status)) {
1733 return Status;
1734 }
1735
1736 ConnectedToFileSystem = TRUE;
1737 mEmuVariableEvent =
1738 EfiCreateProtocolNotifyEvent (
1739 &gEfiDevicePathProtocolGuid,
1740 TPL_CALLBACK,
1741 EmuVariablesUpdatedCallback,
1742 NULL,
1743 &mEmuVariableEventReg
1744 );
1745 PcdStatus = PcdSet64S (
1746 PcdEmuVariableEvent,
1747 (UINT64)(UINTN)mEmuVariableEvent
1748 );
1749 ASSERT_RETURN_ERROR (PcdStatus);
1750
1751 return EFI_SUCCESS;
1752}
1753
1754VOID
1755PlatformBdsRestoreNvVarsFromHardDisk (
1756 )
1757{
1758 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1759 VisitAllInstancesOfProtocol (
1760 &gEfiSimpleFileSystemProtocolGuid,
1761 VisitingFileSystemInstance,
1762 NULL
1763 );
1764}
1765
1766/**
1767 Connect with predefined platform connect sequence.
1768
1769 The OEM/IBV can customize with their own connect sequence.
1770**/
1771VOID
1772PlatformBdsConnectSequence (
1773 VOID
1774 )
1775{
1776 UINTN Index;
1777 RETURN_STATUS Status;
1778
1779 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));
1780
1781 Index = 0;
1782
1783 //
1784 // Here we can get the customized platform connect sequence
1785 // Notes: we can connect with new variable which record the
1786 // last time boots connect device path sequence
1787 //
1788 while (gPlatformConnectSequence[Index] != NULL) {
1789 //
1790 // Build the platform boot option
1791 //
1792 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1793 Index++;
1794 }
1795
1796 Status = ConnectDevicesFromQemu ();
1797 if (RETURN_ERROR (Status)) {
1798 //
1799 // Just use the simple policy to connect all devices
1800 //
1801 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));
1802 EfiBootManagerConnectAll ();
1803 }
1804}
1805
1806/**
1807 Save the S3 boot script.
1808
1809 Note that DxeSmmReadyToLock must be signaled after this function returns;
1810 otherwise the script wouldn't be saved actually.
1811**/
1812STATIC
1813VOID
1814SaveS3BootScript (
1815 VOID
1816 )
1817{
1818 EFI_STATUS Status;
1819 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1820 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1821
1822 Status = gBS->LocateProtocol (
1823 &gEfiS3SaveStateProtocolGuid,
1824 NULL,
1825 (VOID **)&BootScript
1826 );
1827 ASSERT_EFI_ERROR (Status);
1828
1829 //
1830 // Despite the opcode documentation in the PI spec, the protocol
1831 // implementation embeds a deep copy of the info in the boot script, rather
1832 // than storing just a pointer to runtime or NVS storage.
1833 //
1834 Status = BootScript->Write (
1835 BootScript,
1836 EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1837 (UINT32)sizeof Info,
1838 (EFI_PHYSICAL_ADDRESS)(UINTN)&Info
1839 );
1840 ASSERT_EFI_ERROR (Status);
1841}
1842
1843/**
1844 Do the platform specific action after the console is ready
1845
1846 Possible things that can be done in PlatformBootManagerAfterConsole:
1847
1848 > Console post action:
1849 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1850 > Signal console ready platform customized event
1851 > Run diagnostics like memory testing
1852 > Connect certain devices
1853 > Dispatch aditional option roms
1854 > Special boot: e.g.: USB boot, enter UI
1855**/
1856VOID
1857EFIAPI
1858PlatformBootManagerAfterConsole (
1859 VOID
1860 )
1861{
1862 EFI_BOOT_MODE BootMode;
1863
1864 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));
1865
1866 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1867 DEBUG ((
1868 DEBUG_INFO,
1869 "PlatformBdsPolicyBehavior: not restoring NvVars "
1870 "from disk since flash variables appear to be supported.\n"
1871 ));
1872 } else {
1873 //
1874 // Try to restore variables from the hard disk early so
1875 // they can be used for the other BDS connect operations.
1876 //
1877 PlatformBdsRestoreNvVarsFromHardDisk ();
1878 }
1879
1880 //
1881 // Get current Boot Mode
1882 //
1883 BootMode = GetBootModeHob ();
1884 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1885
1886 //
1887 // Go the different platform policy with different boot mode
1888 // Notes: this part code can be change with the table policy
1889 //
1890 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1891
1892#ifndef VBOX /* @todo Our graphics controller is started in PlatformBdsConnectSequence(). */
1893 //
1894 // Logo show
1895 //
1896 BootLogoEnableLogo ();
1897#endif
1898
1899 //
1900 // Set PCI Interrupt Line registers and ACPI SCI_EN
1901 //
1902 PciAcpiInitialization ();
1903
1904 //
1905 // Write qemu bootorder to efi variables
1906 //
1907 StoreQemuBootOrder ();
1908
1909 //
1910 // Process QEMU's -kernel command line option
1911 //
1912 TryRunningQemuKernel ();
1913
1914 //
1915 // Perform some platform specific connect sequence
1916 //
1917 if (FeaturePcdGet (PcdBootRestrictToFirmware)) {
1918 RestrictBootOptionsToFirmware ();
1919 } else {
1920 PlatformBdsConnectSequence ();
1921 EfiBootManagerRefreshAllBootOption ();
1922 }
1923
1924 BOOLEAN ShellEnabled;
1925 RETURN_STATUS RetStatus;
1926
1927 RetStatus = QemuFwCfgParseBool (
1928 "opt/org.tianocore/EFIShellSupport",
1929 &ShellEnabled
1930 );
1931
1932 if (RETURN_ERROR (RetStatus)) {
1933 ShellEnabled = TRUE;
1934 }
1935
1936#ifdef VBOX /* @todo Our graphics controller is started in PlatformBdsConnectSequence(). */
1937 //
1938 // Logo show
1939 //
1940 BootLogoEnableLogo ();
1941#endif
1942
1943 //
1944 // Register UEFI Shell
1945 //
1946#ifndef VBOX
1947 PlatformRegisterFvBootOption (
1948 &gUefiShellFileGuid,
1949 L"EFI Internal Shell",
1950 LOAD_OPTION_ACTIVE,
1951 ShellEnabled
1952 );
1953#else
1954 /*
1955 * Don't start the shell automatically (can still be selected from the boot manager)
1956 * so we get into the error path when none of the boot options worked.
1957 */
1958 PlatformRegisterFvBootOption (
1959 &gUefiShellFileGuid,
1960 L"EFI Internal Shell",
1961 0,
1962 ShellEnabled
1963 );
1964#endif
1965
1966 //
1967 // Register Grub
1968 //
1969 PlatformRegisterFvBootOption (
1970 &gGrubFileGuid,
1971 L"Grub Bootloader",
1972 LOAD_OPTION_ACTIVE,
1973 TRUE
1974 );
1975
1976 RemoveStaleFvFileOptions ();
1977 SetBootOrderFromQemu ();
1978
1979 PlatformBmPrintScRegisterHandler ();
1980}
1981
1982/**
1983 This notification function is invoked when an instance of the
1984 EFI_DEVICE_PATH_PROTOCOL is produced.
1985
1986 @param Event The event that occurred
1987 @param Context For EFI compatibility. Not used.
1988
1989**/
1990VOID
1991EFIAPI
1992NotifyDevPath (
1993 IN EFI_EVENT Event,
1994 IN VOID *Context
1995 )
1996{
1997 EFI_HANDLE Handle;
1998 EFI_STATUS Status;
1999 UINTN BufferSize;
2000 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
2001 ATAPI_DEVICE_PATH *Atapi;
2002
2003 //
2004 // Examine all new handles
2005 //
2006 for ( ; ;) {
2007 //
2008 // Get the next handle
2009 //
2010 BufferSize = sizeof (Handle);
2011 Status = gBS->LocateHandle (
2012 ByRegisterNotify,
2013 NULL,
2014 mEfiDevPathNotifyReg,
2015 &BufferSize,
2016 &Handle
2017 );
2018
2019 //
2020 // If not found, we're done
2021 //
2022 if (EFI_NOT_FOUND == Status) {
2023 break;
2024 }
2025
2026 if (EFI_ERROR (Status)) {
2027 continue;
2028 }
2029
2030 //
2031 // Get the DevicePath protocol on that handle
2032 //
2033 Status = gBS->HandleProtocol (
2034 Handle,
2035 &gEfiDevicePathProtocolGuid,
2036 (VOID **)&DevPathNode
2037 );
2038 ASSERT_EFI_ERROR (Status);
2039
2040 while (!IsDevicePathEnd (DevPathNode)) {
2041 //
2042 // Find the handler to dump this device path node
2043 //
2044 if (
2045 (DevicePathType (DevPathNode) == MESSAGING_DEVICE_PATH) &&
2046 (DevicePathSubType (DevPathNode) == MSG_ATAPI_DP)
2047 )
2048 {
2049 Atapi = (ATAPI_DEVICE_PATH *)DevPathNode;
2050 PciOr16 (
2051 PCI_LIB_ADDRESS (
2052 0,
2053 1,
2054 1,
2055 (Atapi->PrimarySecondary == 1) ? 0x42 : 0x40
2056 ),
2057 BIT15
2058 );
2059 }
2060
2061 //
2062 // Next device path node
2063 //
2064 DevPathNode = NextDevicePathNode (DevPathNode);
2065 }
2066 }
2067
2068 return;
2069}
2070
2071VOID
2072InstallDevicePathCallback (
2073 VOID
2074 )
2075{
2076 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));
2077 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
2078 &gEfiDevicePathProtocolGuid,
2079 TPL_CALLBACK,
2080 NotifyDevPath,
2081 NULL,
2082 &mEfiDevPathNotifyReg
2083 );
2084}
2085
2086/**
2087 This function is called each second during the boot manager waits the
2088 timeout.
2089
2090 @param TimeoutRemain The remaining timeout.
2091**/
2092VOID
2093EFIAPI
2094PlatformBootManagerWaitCallback (
2095 UINT16 TimeoutRemain
2096 )
2097{
2098 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
2099 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
2100 UINT16 TimeoutInitial;
2101
2102 TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
2103
2104 //
2105 // If PcdPlatformBootTimeOut is set to zero, then we consider
2106 // that no progress update should be enacted (since we'd only
2107 // ever display a one-shot progress of either 0% or 100%).
2108 //
2109 if (TimeoutInitial == 0) {
2110 return;
2111 }
2112
2113 Black.Raw = 0x00000000;
2114 White.Raw = 0x00FFFFFF;
2115
2116 BootLogoUpdateProgress (
2117 White.Pixel,
2118 Black.Pixel,
2119 L"Start boot option",
2120 White.Pixel,
2121 (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
2122 0
2123 );
2124}
2125
2126/**
2127 The function is called when no boot option could be launched,
2128 including platform recovery options and options pointing to applications
2129 built into firmware volumes.
2130
2131 If this function returns, BDS attempts to enter an infinite loop.
2132**/
2133VOID
2134EFIAPI
2135PlatformBootManagerUnableToBoot (
2136 VOID
2137 )
2138{
2139 EFI_STATUS Status;
2140 EFI_INPUT_KEY Key;
2141 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
2142 UINTN Index;
2143
2144#ifdef VBOX
2145 IoWrite16(EFI_PORT_EVENT, EFI_EVENT_TYPE_BOOT_FAILED);
2146#endif
2147
2148 if (FeaturePcdGet (PcdBootRestrictToFirmware)) {
2149 AsciiPrint (
2150 "%a: No bootable option was found.\n",
2151 gEfiCallerBaseName
2152 );
2153 CpuDeadLoop ();
2154 }
2155
2156 //
2157 // BootManagerMenu doesn't contain the correct information when return status
2158 // is EFI_NOT_FOUND.
2159 //
2160 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
2161 if (EFI_ERROR (Status)) {
2162 return;
2163 }
2164
2165 //
2166 // Normally BdsDxe does not print anything to the system console, but this is
2167 // a last resort -- the end-user will likely not see any DEBUG messages
2168 // logged in this situation.
2169 //
2170 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
2171 // here to see if it makes sense to request and wait for a keypress.
2172 //
2173 if (gST->ConIn != NULL) {
2174 AsciiPrint (
2175 "%a: No bootable option or device was found.\n"
2176 "%a: Press any key to enter the Boot Manager Menu.\n",
2177 gEfiCallerBaseName,
2178 gEfiCallerBaseName
2179 );
2180 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
2181 ASSERT_EFI_ERROR (Status);
2182 ASSERT (Index == 0);
2183
2184 //
2185 // Drain any queued keys.
2186 //
2187 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
2188 //
2189 // just throw away Key
2190 //
2191 }
2192 }
2193
2194 for ( ; ;) {
2195 EfiBootManagerBoot (&BootManagerMenu);
2196 }
2197}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette