VirtualBox

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