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