]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 //
422 // We need to connect all trusted consoles for TCG PP. Here we treat all
423 // consoles in OVMF to be trusted consoles.
424 //
425 // Cloud Hypervisor doesn't emulate any LPC bridge, which is why it must
426 // rely on the serial I/O port to be connected as a console. It reuses the
427 // definition from Xen as it is very generic.
428 //
429 PlatformInitializeConsole (
430 (XenDetected () || PcdGet16 (PcdOvmfHostBridgePciDevId) == CLOUDHV_DEVICE_ID) ? gXenPlatformConsole : gPlatformConsole
431 );
432
433 //
434 // Process TPM PPI request; this may require keyboard input
435 //
436 Tcg2PhysicalPresenceLibProcessRequest (NULL);
437
438 //
439 // Prevent further changes to LockBoxes or SMRAM.
440 // Any TPM 2 Physical Presence Interface opcode must be handled before.
441 //
442 Handle = NULL;
443 Status = gBS->InstallProtocolInterface (
444 &Handle,
445 &gEfiDxeSmmReadyToLockProtocolGuid,
446 EFI_NATIVE_INTERFACE,
447 NULL
448 );
449 ASSERT_EFI_ERROR (Status);
450
451 //
452 // Dispatch deferred images after EndOfDxe event and ReadyToLock
453 // installation.
454 //
455 EfiBootManagerDispatchDeferredImages ();
456
457 //
458 // GPU passthrough only allows Console enablement after ROM image load
459 //
460 PlatformInitializeConsole (
461 XenDetected () ? gXenPlatformConsole : gPlatformConsole
462 );
463
464 FrontPageTimeout = GetFrontPageTimeoutFromQemu ();
465 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);
466 ASSERT_RETURN_ERROR (PcdStatus);
467 //
468 // Reflect the PCD in the standard Timeout variable.
469 //
470 Status = gRT->SetVariable (
471 EFI_TIME_OUT_VARIABLE_NAME,
472 &gEfiGlobalVariableGuid,
473 (EFI_VARIABLE_NON_VOLATILE |
474 EFI_VARIABLE_BOOTSERVICE_ACCESS |
475 EFI_VARIABLE_RUNTIME_ACCESS),
476 sizeof FrontPageTimeout,
477 &FrontPageTimeout
478 );
479 DEBUG ((
480 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
481 "%a: SetVariable(%s, %u): %r\n",
482 __FUNCTION__,
483 EFI_TIME_OUT_VARIABLE_NAME,
484 FrontPageTimeout,
485 Status
486 ));
487
488 PlatformRegisterOptionsAndKeys ();
489
490 //
491 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
492 // instances on Virtio PCI RNG devices.
493 //
494 VisitAllInstancesOfProtocol (
495 &gEfiPciIoProtocolGuid,
496 ConnectVirtioPciRng,
497 NULL
498 );
499 }
500
501 EFI_STATUS
502 EFIAPI
503 ConnectRootBridge (
504 IN EFI_HANDLE RootBridgeHandle,
505 IN VOID *Instance,
506 IN VOID *Context
507 )
508 {
509 EFI_STATUS Status;
510
511 //
512 // Make the PCI bus driver connect the root bridge, non-recursively. This
513 // will produce a number of child handles with PciIo on them.
514 //
515 Status = gBS->ConnectController (
516 RootBridgeHandle, // ControllerHandle
517 NULL, // DriverImageHandle
518 NULL, // RemainingDevicePath -- produce all
519 // children
520 FALSE // Recursive
521 );
522 return Status;
523 }
524
525 STATIC
526 EFI_STATUS
527 EFIAPI
528 ConnectVirtioPciRng (
529 IN EFI_HANDLE Handle,
530 IN VOID *Instance,
531 IN VOID *Context
532 )
533 {
534 EFI_PCI_IO_PROTOCOL *PciIo;
535 EFI_STATUS Status;
536 UINT16 VendorId;
537 UINT16 DeviceId;
538 UINT8 RevisionId;
539 BOOLEAN Virtio10;
540 UINT16 SubsystemId;
541
542 PciIo = Instance;
543
544 //
545 // Read and check VendorId.
546 //
547 Status = PciIo->Pci.Read (
548 PciIo,
549 EfiPciIoWidthUint16,
550 PCI_VENDOR_ID_OFFSET,
551 1,
552 &VendorId
553 );
554 if (EFI_ERROR (Status)) {
555 goto Error;
556 }
557
558 if (VendorId != VIRTIO_VENDOR_ID) {
559 return EFI_SUCCESS;
560 }
561
562 //
563 // Read DeviceId and RevisionId.
564 //
565 Status = PciIo->Pci.Read (
566 PciIo,
567 EfiPciIoWidthUint16,
568 PCI_DEVICE_ID_OFFSET,
569 1,
570 &DeviceId
571 );
572 if (EFI_ERROR (Status)) {
573 goto Error;
574 }
575
576 Status = PciIo->Pci.Read (
577 PciIo,
578 EfiPciIoWidthUint8,
579 PCI_REVISION_ID_OFFSET,
580 1,
581 &RevisionId
582 );
583 if (EFI_ERROR (Status)) {
584 goto Error;
585 }
586
587 //
588 // From DeviceId and RevisionId, determine whether the device is a
589 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
590 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
591 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
592 // only be sanity-checked, and SubsystemId will decide.
593 //
594 if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
595 (RevisionId >= 0x01))
596 {
597 Virtio10 = TRUE;
598 } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
599 Virtio10 = FALSE;
600 } else {
601 return EFI_SUCCESS;
602 }
603
604 //
605 // Read and check SubsystemId as dictated by Virtio10.
606 //
607 Status = PciIo->Pci.Read (
608 PciIo,
609 EfiPciIoWidthUint16,
610 PCI_SUBSYSTEM_ID_OFFSET,
611 1,
612 &SubsystemId
613 );
614 if (EFI_ERROR (Status)) {
615 goto Error;
616 }
617
618 if ((Virtio10 && (SubsystemId >= 0x40)) ||
619 (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)))
620 {
621 Status = gBS->ConnectController (
622 Handle, // ControllerHandle
623 NULL, // DriverImageHandle -- connect all drivers
624 NULL, // RemainingDevicePath -- produce all child handles
625 FALSE // Recursive -- don't follow child handles
626 );
627 if (EFI_ERROR (Status)) {
628 goto Error;
629 }
630 }
631
632 return EFI_SUCCESS;
633
634 Error:
635 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
636 return Status;
637 }
638
639 /**
640 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
641
642 @param[in] DeviceHandle Handle of the LPC Bridge device.
643
644 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
645 ConOut, ConIn, and ErrOut.
646
647 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
648 from DeviceHandle.
649 **/
650 EFI_STATUS
651 PrepareLpcBridgeDevicePath (
652 IN EFI_HANDLE DeviceHandle
653 )
654 {
655 EFI_STATUS Status;
656 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
657 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
658 CHAR16 *DevPathStr;
659
660 DevicePath = NULL;
661 Status = gBS->HandleProtocol (
662 DeviceHandle,
663 &gEfiDevicePathProtocolGuid,
664 (VOID *)&DevicePath
665 );
666 if (EFI_ERROR (Status)) {
667 return Status;
668 }
669
670 TempDevicePath = DevicePath;
671
672 //
673 // Register Keyboard
674 //
675 DevicePath = AppendDevicePathNode (
676 DevicePath,
677 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode
678 );
679
680 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
681
682 //
683 // Register COM1
684 //
685 DevicePath = TempDevicePath;
686 gPnp16550ComPortDeviceNode.UID = 0;
687
688 DevicePath = AppendDevicePathNode (
689 DevicePath,
690 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode
691 );
692 DevicePath = AppendDevicePathNode (
693 DevicePath,
694 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
695 );
696 DevicePath = AppendDevicePathNode (
697 DevicePath,
698 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
699 );
700
701 //
702 // Print Device Path
703 //
704 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
705 if (DevPathStr != NULL) {
706 DEBUG ((
707 DEBUG_INFO,
708 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
709 DEBUG_LINE_NUMBER,
710 gPnp16550ComPortDeviceNode.UID + 1,
711 DevPathStr
712 ));
713 FreePool (DevPathStr);
714 }
715
716 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
717 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
718 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
719
720 //
721 // Register COM2
722 //
723 DevicePath = TempDevicePath;
724 gPnp16550ComPortDeviceNode.UID = 1;
725
726 DevicePath = AppendDevicePathNode (
727 DevicePath,
728 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode
729 );
730 DevicePath = AppendDevicePathNode (
731 DevicePath,
732 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
733 );
734 DevicePath = AppendDevicePathNode (
735 DevicePath,
736 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
737 );
738
739 //
740 // Print Device Path
741 //
742 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
743 if (DevPathStr != NULL) {
744 DEBUG ((
745 DEBUG_INFO,
746 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
747 DEBUG_LINE_NUMBER,
748 gPnp16550ComPortDeviceNode.UID + 1,
749 DevPathStr
750 ));
751 FreePool (DevPathStr);
752 }
753
754 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
755 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
756 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
757
758 return EFI_SUCCESS;
759 }
760
761 typedef struct {
762 VENDOR_DEVICE_PATH Guid;
763 EFI_DEVICE_PATH_PROTOCOL End;
764 } SERIAL_DEVICE_PATH;
765
766 SERIAL_DEVICE_PATH serialDevicePath = {
767 {
768 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }
769 },
770 EDKII_SERIAL_PORT_LIB_VENDOR_GUID
771 },
772 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
773 }
774 };
775
776 VOID
777 PrepareMicrovmDevicePath (
778 VOID
779 )
780 {
781 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
782 UINT16 HostBridgeDevId;
783
784 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
785 if (HostBridgeDevId != MICROVM_PSEUDO_DEVICE_ID) {
786 return;
787 }
788
789 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&serialDevicePath;
790 DevicePath = AppendDevicePathNode (
791 DevicePath,
792 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
793 );
794 DevicePath = AppendDevicePathNode (
795 DevicePath,
796 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
797 );
798
799 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
800 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
801 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
802 }
803
804 EFI_STATUS
805 GetGopDevicePath (
806 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
807 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
808 )
809 {
810 UINTN Index;
811 EFI_STATUS Status;
812 EFI_HANDLE PciDeviceHandle;
813 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
814 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
815 UINTN GopHandleCount;
816 EFI_HANDLE *GopHandleBuffer;
817
818 if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) {
819 return EFI_INVALID_PARAMETER;
820 }
821
822 //
823 // Initialize the GopDevicePath to be PciDevicePath
824 //
825 *GopDevicePath = PciDevicePath;
826 TempPciDevicePath = PciDevicePath;
827
828 Status = gBS->LocateDevicePath (
829 &gEfiDevicePathProtocolGuid,
830 &TempPciDevicePath,
831 &PciDeviceHandle
832 );
833 if (EFI_ERROR (Status)) {
834 return Status;
835 }
836
837 //
838 // Try to connect this handle, so that GOP driver could start on this
839 // device and create child handles with GraphicsOutput Protocol installed
840 // on them, then we get device paths of these child handles and select
841 // them as possible console device.
842 //
843 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
844
845 Status = gBS->LocateHandleBuffer (
846 ByProtocol,
847 &gEfiGraphicsOutputProtocolGuid,
848 NULL,
849 &GopHandleCount,
850 &GopHandleBuffer
851 );
852 if (!EFI_ERROR (Status)) {
853 //
854 // Add all the child handles as possible Console Device
855 //
856 for (Index = 0; Index < GopHandleCount; Index++) {
857 Status = gBS->HandleProtocol (
858 GopHandleBuffer[Index],
859 &gEfiDevicePathProtocolGuid,
860 (VOID *)&TempDevicePath
861 );
862 if (EFI_ERROR (Status)) {
863 continue;
864 }
865
866 if (CompareMem (
867 PciDevicePath,
868 TempDevicePath,
869 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
870 ) == 0)
871 {
872 //
873 // In current implementation, we only enable one of the child handles
874 // as console device, i.e. sotre one of the child handle's device
875 // path to variable "ConOut"
876 // In future, we could select all child handles to be console device
877 //
878
879 *GopDevicePath = TempDevicePath;
880
881 //
882 // Delete the PCI device's path that added by
883 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
884 //
885 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
886 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
887 }
888 }
889
890 gBS->FreePool (GopHandleBuffer);
891 }
892
893 return EFI_SUCCESS;
894 }
895
896 /**
897 Add PCI display to ConOut.
898
899 @param[in] DeviceHandle Handle of the PCI display device.
900
901 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
902
903 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
904 from DeviceHandle.
905 **/
906 EFI_STATUS
907 PreparePciDisplayDevicePath (
908 IN EFI_HANDLE DeviceHandle
909 )
910 {
911 EFI_STATUS Status;
912 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
913 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
914
915 DevicePath = NULL;
916 GopDevicePath = NULL;
917 Status = gBS->HandleProtocol (
918 DeviceHandle,
919 &gEfiDevicePathProtocolGuid,
920 (VOID *)&DevicePath
921 );
922 if (EFI_ERROR (Status)) {
923 return Status;
924 }
925
926 GetGopDevicePath (DevicePath, &GopDevicePath);
927 DevicePath = GopDevicePath;
928
929 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
930
931 return EFI_SUCCESS;
932 }
933
934 /**
935 Add PCI Serial to ConOut, ConIn, ErrOut.
936
937 @param[in] DeviceHandle Handle of the PCI serial device.
938
939 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
940 ErrOut.
941
942 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
943 from DeviceHandle.
944 **/
945 EFI_STATUS
946 PreparePciSerialDevicePath (
947 IN EFI_HANDLE DeviceHandle
948 )
949 {
950 EFI_STATUS Status;
951 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
952
953 DevicePath = NULL;
954 Status = gBS->HandleProtocol (
955 DeviceHandle,
956 &gEfiDevicePathProtocolGuid,
957 (VOID *)&DevicePath
958 );
959 if (EFI_ERROR (Status)) {
960 return Status;
961 }
962
963 DevicePath = AppendDevicePathNode (
964 DevicePath,
965 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode
966 );
967 DevicePath = AppendDevicePathNode (
968 DevicePath,
969 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode
970 );
971
972 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
973 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
974 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
975
976 return EFI_SUCCESS;
977 }
978
979 EFI_STATUS
980 VisitAllInstancesOfProtocol (
981 IN EFI_GUID *Id,
982 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
983 IN VOID *Context
984 )
985 {
986 EFI_STATUS Status;
987 UINTN HandleCount;
988 EFI_HANDLE *HandleBuffer;
989 UINTN Index;
990 VOID *Instance;
991
992 //
993 // Start to check all the PciIo to find all possible device
994 //
995 HandleCount = 0;
996 HandleBuffer = NULL;
997 Status = gBS->LocateHandleBuffer (
998 ByProtocol,
999 Id,
1000 NULL,
1001 &HandleCount,
1002 &HandleBuffer
1003 );
1004 if (EFI_ERROR (Status)) {
1005 return Status;
1006 }
1007
1008 for (Index = 0; Index < HandleCount; Index++) {
1009 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
1010 if (EFI_ERROR (Status)) {
1011 continue;
1012 }
1013
1014 Status = (*CallBackFunction)(
1015 HandleBuffer[Index],
1016 Instance,
1017 Context
1018 );
1019 }
1020
1021 gBS->FreePool (HandleBuffer);
1022
1023 return EFI_SUCCESS;
1024 }
1025
1026 EFI_STATUS
1027 EFIAPI
1028 VisitingAPciInstance (
1029 IN EFI_HANDLE Handle,
1030 IN VOID *Instance,
1031 IN VOID *Context
1032 )
1033 {
1034 EFI_STATUS Status;
1035 EFI_PCI_IO_PROTOCOL *PciIo;
1036 PCI_TYPE00 Pci;
1037
1038 PciIo = (EFI_PCI_IO_PROTOCOL *)Instance;
1039
1040 //
1041 // Check for all PCI device
1042 //
1043 Status = PciIo->Pci.Read (
1044 PciIo,
1045 EfiPciIoWidthUint32,
1046 0,
1047 sizeof (Pci) / sizeof (UINT32),
1048 &Pci
1049 );
1050 if (EFI_ERROR (Status)) {
1051 return Status;
1052 }
1053
1054 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN)Context)(
1055 Handle,
1056 PciIo,
1057 &Pci
1058 );
1059 }
1060
1061 EFI_STATUS
1062 VisitAllPciInstances (
1063 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
1064 )
1065 {
1066 return VisitAllInstancesOfProtocol (
1067 &gEfiPciIoProtocolGuid,
1068 VisitingAPciInstance,
1069 (VOID *)(UINTN)CallBackFunction
1070 );
1071 }
1072
1073 /**
1074 Do platform specific PCI Device check and add them to
1075 ConOut, ConIn, ErrOut.
1076
1077 @param[in] Handle - Handle of PCI device instance
1078 @param[in] PciIo - PCI IO protocol instance
1079 @param[in] Pci - PCI Header register block
1080
1081 @retval EFI_SUCCESS - PCI Device check and Console variable update
1082 successfully.
1083 @retval EFI_STATUS - PCI Device check or Console variable update fail.
1084
1085 **/
1086 EFI_STATUS
1087 EFIAPI
1088 DetectAndPreparePlatformPciDevicePath (
1089 IN EFI_HANDLE Handle,
1090 IN EFI_PCI_IO_PROTOCOL *PciIo,
1091 IN PCI_TYPE00 *Pci
1092 )
1093 {
1094 EFI_STATUS Status;
1095
1096 Status = PciIo->Attributes (
1097 PciIo,
1098 EfiPciIoAttributeOperationEnable,
1099 EFI_PCI_DEVICE_ENABLE,
1100 NULL
1101 );
1102 ASSERT_EFI_ERROR (Status);
1103
1104 //
1105 // Here we decide whether it is LPC Bridge
1106 //
1107 if ((IS_PCI_LPC (Pci)) ||
1108 ((IS_PCI_ISA_PDECODE (Pci)) &&
1109 (Pci->Hdr.VendorId == 0x8086) &&
1110 (Pci->Hdr.DeviceId == 0x7000)
1111 )
1112 )
1113 {
1114 //
1115 // Add IsaKeyboard to ConIn,
1116 // add IsaSerial to ConOut, ConIn, ErrOut
1117 //
1118 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));
1119 PrepareLpcBridgeDevicePath (Handle);
1120 return EFI_SUCCESS;
1121 }
1122
1123 //
1124 // Here we decide which Serial device to enable in PCI bus
1125 //
1126 if (IS_PCI_16550SERIAL (Pci)) {
1127 //
1128 // Add them to ConOut, ConIn, ErrOut.
1129 //
1130 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));
1131 PreparePciSerialDevicePath (Handle);
1132 return EFI_SUCCESS;
1133 }
1134
1135 //
1136 // Here we decide which display device to enable in PCI bus
1137 //
1138 if (IS_PCI_DISPLAY (Pci)) {
1139 //
1140 // Add them to ConOut.
1141 //
1142 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));
1143 PreparePciDisplayDevicePath (Handle);
1144 return EFI_SUCCESS;
1145 }
1146
1147 return Status;
1148 }
1149
1150 /**
1151 Connect the predefined platform default console device.
1152
1153 Always try to find and enable PCI display devices.
1154
1155 @param[in] PlatformConsole Predefined platform default console device array.
1156 **/
1157 VOID
1158 PlatformInitializeConsole (
1159 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
1160 )
1161 {
1162 UINTN Index;
1163
1164 //
1165 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1166 // ErrOut
1167 //
1168 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
1169
1170 PrepareMicrovmDevicePath ();
1171
1172 //
1173 // Have chance to connect the platform default console,
1174 // the platform default console is the minimum device group
1175 // the platform should support
1176 //
1177 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
1178 //
1179 // Update the console variable with the connect type
1180 //
1181 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
1182 EfiBootManagerUpdateConsoleVariable (
1183 ConIn,
1184 PlatformConsole[Index].DevicePath,
1185 NULL
1186 );
1187 }
1188
1189 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
1190 EfiBootManagerUpdateConsoleVariable (
1191 ConOut,
1192 PlatformConsole[Index].DevicePath,
1193 NULL
1194 );
1195 }
1196
1197 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
1198 EfiBootManagerUpdateConsoleVariable (
1199 ErrOut,
1200 PlatformConsole[Index].DevicePath,
1201 NULL
1202 );
1203 }
1204 }
1205 }
1206
1207 /**
1208 Configure PCI Interrupt Line register for applicable devices
1209 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1210
1211 @param[in] Handle - Handle of PCI device instance
1212 @param[in] PciIo - PCI IO protocol instance
1213 @param[in] PciHdr - PCI Header register block
1214
1215 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1216
1217 **/
1218 EFI_STATUS
1219 EFIAPI
1220 SetPciIntLine (
1221 IN EFI_HANDLE Handle,
1222 IN EFI_PCI_IO_PROTOCOL *PciIo,
1223 IN PCI_TYPE00 *PciHdr
1224 )
1225 {
1226 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1227 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1228 UINTN RootSlot;
1229 UINTN Idx;
1230 UINT8 IrqLine;
1231 EFI_STATUS Status;
1232 UINT32 RootBusNumber;
1233
1234 Status = EFI_SUCCESS;
1235
1236 if (PciHdr->Device.InterruptPin != 0) {
1237 DevPathNode = DevicePathFromHandle (Handle);
1238 ASSERT (DevPathNode != NULL);
1239 DevPath = DevPathNode;
1240
1241 RootBusNumber = 0;
1242 if ((DevicePathType (DevPathNode) == ACPI_DEVICE_PATH) &&
1243 (DevicePathSubType (DevPathNode) == ACPI_DP) &&
1244 (((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID (0x0A03)))
1245 {
1246 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1247 }
1248
1249 //
1250 // Compute index into PciHostIrqs[] table by walking
1251 // the device path and adding up all device numbers
1252 //
1253 Status = EFI_NOT_FOUND;
1254 RootSlot = 0;
1255 Idx = PciHdr->Device.InterruptPin - 1;
1256 while (!IsDevicePathEnd (DevPathNode)) {
1257 if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&
1258 (DevicePathSubType (DevPathNode) == HW_PCI_DP))
1259 {
1260 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1261
1262 //
1263 // Unlike SeaBIOS, which starts climbing from the leaf device
1264 // up toward the root, we traverse the device path starting at
1265 // the root moving toward the leaf node.
1266 // The slot number of the top-level parent bridge is needed for
1267 // Q35 cases with more than 24 slots on the root bus.
1268 //
1269 if (Status != EFI_SUCCESS) {
1270 Status = EFI_SUCCESS;
1271 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1272 }
1273 }
1274
1275 DevPathNode = NextDevicePathNode (DevPathNode);
1276 }
1277
1278 if (EFI_ERROR (Status)) {
1279 return Status;
1280 }
1281
1282 if ((RootBusNumber == 0) && (RootSlot == 0)) {
1283 DEBUG ((
1284 DEBUG_ERROR,
1285 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1286 __FUNCTION__
1287 ));
1288 ASSERT (FALSE);
1289 }
1290
1291 //
1292 // Final PciHostIrqs[] index calculation depends on the platform
1293 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1294 //
1295 switch (mHostBridgeDevId) {
1296 case INTEL_82441_DEVICE_ID:
1297 Idx -= 1;
1298 break;
1299 case INTEL_Q35_MCH_DEVICE_ID:
1300 //
1301 // SeaBIOS contains the following comment:
1302 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1303 // with a different starting index - see q35-acpi-dsdt.dsl.
1304 //
1305 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1306 //
1307 if (RootSlot > 24) {
1308 //
1309 // in this case, subtract back out RootSlot from Idx
1310 // (SeaBIOS never adds it to begin with, but that would make our
1311 // device path traversal loop above too awkward)
1312 //
1313 Idx -= RootSlot;
1314 }
1315
1316 break;
1317 default:
1318 ASSERT (FALSE); // should never get here
1319 }
1320
1321 Idx %= ARRAY_SIZE (PciHostIrqs);
1322 IrqLine = PciHostIrqs[Idx];
1323
1324 DEBUG_CODE_BEGIN ();
1325 {
1326 CHAR16 *DevPathString;
1327 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1328 UINTN Segment, Bus, Device, Function;
1329
1330 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1331 if (DevPathString == NULL) {
1332 DevPathString = Fallback;
1333 }
1334
1335 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1336 ASSERT_EFI_ERROR (Status);
1337
1338 DEBUG ((
1339 DEBUG_VERBOSE,
1340 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",
1341 __FUNCTION__,
1342 (UINT32)Bus,
1343 (UINT32)Device,
1344 (UINT32)Function,
1345 DevPathString,
1346 IrqLine
1347 ));
1348
1349 if (DevPathString != Fallback) {
1350 FreePool (DevPathString);
1351 }
1352 }
1353 DEBUG_CODE_END ();
1354
1355 //
1356 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1357 //
1358 Status = PciIo->Pci.Write (
1359 PciIo,
1360 EfiPciIoWidthUint8,
1361 PCI_INT_LINE_OFFSET,
1362 1,
1363 &IrqLine
1364 );
1365 }
1366
1367 return Status;
1368 }
1369
1370 VOID
1371 PciAcpiInitialization (
1372 )
1373 {
1374 UINTN Pmba;
1375
1376 //
1377 // Query Host Bridge DID to determine platform type
1378 //
1379 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1380 switch (mHostBridgeDevId) {
1381 case INTEL_82441_DEVICE_ID:
1382 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1383 //
1384 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1385 //
1386 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // A
1387 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // B
1388 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // C
1389 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // D
1390 break;
1391 case INTEL_Q35_MCH_DEVICE_ID:
1392 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1393 //
1394 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1395 //
1396 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // A
1397 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // B
1398 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // C
1399 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // D
1400 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // E
1401 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // F
1402 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // G
1403 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // H
1404 break;
1405 case MICROVM_PSEUDO_DEVICE_ID:
1406 case CLOUDHV_DEVICE_ID:
1407 return;
1408 default:
1409 if (XenDetected ()) {
1410 //
1411 // There is no PCI bus in this case.
1412 //
1413 return;
1414 }
1415
1416 DEBUG ((
1417 DEBUG_ERROR,
1418 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1419 __FUNCTION__,
1420 mHostBridgeDevId
1421 ));
1422 ASSERT (FALSE);
1423 return;
1424 }
1425
1426 //
1427 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1428 //
1429 VisitAllPciInstances (SetPciIntLine);
1430
1431 //
1432 // Set ACPI SCI_EN bit in PMCNTRL
1433 //
1434 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1435 }
1436
1437 EFI_STATUS
1438 EFIAPI
1439 ConnectRecursivelyIfPciMassStorage (
1440 IN EFI_HANDLE Handle,
1441 IN EFI_PCI_IO_PROTOCOL *Instance,
1442 IN PCI_TYPE00 *PciHeader
1443 )
1444 {
1445 EFI_STATUS Status;
1446 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1447 CHAR16 *DevPathStr;
1448
1449 //
1450 // Recognize PCI Mass Storage, and Xen PCI devices
1451 //
1452 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
1453 (XenDetected () && IS_CLASS2 (PciHeader, 0xFF, 0x80)))
1454 {
1455 DevicePath = NULL;
1456 Status = gBS->HandleProtocol (
1457 Handle,
1458 &gEfiDevicePathProtocolGuid,
1459 (VOID *)&DevicePath
1460 );
1461 if (EFI_ERROR (Status)) {
1462 return Status;
1463 }
1464
1465 //
1466 // Print Device Path
1467 //
1468 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1469 if (DevPathStr != NULL) {
1470 DEBUG ((
1471 DEBUG_INFO,
1472 "Found %s device: %s\n",
1473 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?
1474 L"Mass Storage" :
1475 L"Xen"
1476 ),
1477 DevPathStr
1478 ));
1479 FreePool (DevPathStr);
1480 }
1481
1482 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1483 if (EFI_ERROR (Status)) {
1484 return Status;
1485 }
1486 }
1487
1488 return EFI_SUCCESS;
1489 }
1490
1491 /**
1492 This notification function is invoked when the
1493 EMU Variable FVB has been changed.
1494
1495 @param Event The event that occurred
1496 @param Context For EFI compatibility. Not used.
1497
1498 **/
1499 VOID
1500 EFIAPI
1501 EmuVariablesUpdatedCallback (
1502 IN EFI_EVENT Event,
1503 IN VOID *Context
1504 )
1505 {
1506 DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n"));
1507 UpdateNvVarsOnFileSystem ();
1508 }
1509
1510 EFI_STATUS
1511 EFIAPI
1512 VisitingFileSystemInstance (
1513 IN EFI_HANDLE Handle,
1514 IN VOID *Instance,
1515 IN VOID *Context
1516 )
1517 {
1518 EFI_STATUS Status;
1519 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1520 RETURN_STATUS PcdStatus;
1521
1522 if (ConnectedToFileSystem) {
1523 return EFI_ALREADY_STARTED;
1524 }
1525
1526 Status = ConnectNvVarsToFileSystem (Handle);
1527 if (EFI_ERROR (Status)) {
1528 return Status;
1529 }
1530
1531 ConnectedToFileSystem = TRUE;
1532 mEmuVariableEvent =
1533 EfiCreateProtocolNotifyEvent (
1534 &gEfiDevicePathProtocolGuid,
1535 TPL_CALLBACK,
1536 EmuVariablesUpdatedCallback,
1537 NULL,
1538 &mEmuVariableEventReg
1539 );
1540 PcdStatus = PcdSet64S (
1541 PcdEmuVariableEvent,
1542 (UINT64)(UINTN)mEmuVariableEvent
1543 );
1544 ASSERT_RETURN_ERROR (PcdStatus);
1545
1546 return EFI_SUCCESS;
1547 }
1548
1549 VOID
1550 PlatformBdsRestoreNvVarsFromHardDisk (
1551 )
1552 {
1553 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1554 VisitAllInstancesOfProtocol (
1555 &gEfiSimpleFileSystemProtocolGuid,
1556 VisitingFileSystemInstance,
1557 NULL
1558 );
1559 }
1560
1561 /**
1562 Connect with predefined platform connect sequence.
1563
1564 The OEM/IBV can customize with their own connect sequence.
1565 **/
1566 VOID
1567 PlatformBdsConnectSequence (
1568 VOID
1569 )
1570 {
1571 UINTN Index;
1572 RETURN_STATUS Status;
1573
1574 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));
1575
1576 Index = 0;
1577
1578 //
1579 // Here we can get the customized platform connect sequence
1580 // Notes: we can connect with new variable which record the
1581 // last time boots connect device path sequence
1582 //
1583 while (gPlatformConnectSequence[Index] != NULL) {
1584 //
1585 // Build the platform boot option
1586 //
1587 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1588 Index++;
1589 }
1590
1591 Status = ConnectDevicesFromQemu ();
1592 if (RETURN_ERROR (Status)) {
1593 //
1594 // Just use the simple policy to connect all devices
1595 //
1596 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));
1597 EfiBootManagerConnectAll ();
1598 }
1599 }
1600
1601 /**
1602 Save the S3 boot script.
1603
1604 Note that DxeSmmReadyToLock must be signaled after this function returns;
1605 otherwise the script wouldn't be saved actually.
1606 **/
1607 STATIC
1608 VOID
1609 SaveS3BootScript (
1610 VOID
1611 )
1612 {
1613 EFI_STATUS Status;
1614 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1615 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1616
1617 Status = gBS->LocateProtocol (
1618 &gEfiS3SaveStateProtocolGuid,
1619 NULL,
1620 (VOID **)&BootScript
1621 );
1622 ASSERT_EFI_ERROR (Status);
1623
1624 //
1625 // Despite the opcode documentation in the PI spec, the protocol
1626 // implementation embeds a deep copy of the info in the boot script, rather
1627 // than storing just a pointer to runtime or NVS storage.
1628 //
1629 Status = BootScript->Write (
1630 BootScript,
1631 EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1632 (UINT32)sizeof Info,
1633 (EFI_PHYSICAL_ADDRESS)(UINTN)&Info
1634 );
1635 ASSERT_EFI_ERROR (Status);
1636 }
1637
1638 /**
1639 Do the platform specific action after the console is ready
1640
1641 Possible things that can be done in PlatformBootManagerAfterConsole:
1642
1643 > Console post action:
1644 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1645 > Signal console ready platform customized event
1646 > Run diagnostics like memory testing
1647 > Connect certain devices
1648 > Dispatch aditional option roms
1649 > Special boot: e.g.: USB boot, enter UI
1650 **/
1651 VOID
1652 EFIAPI
1653 PlatformBootManagerAfterConsole (
1654 VOID
1655 )
1656 {
1657 EFI_BOOT_MODE BootMode;
1658
1659 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));
1660
1661 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1662 DEBUG ((
1663 DEBUG_INFO,
1664 "PlatformBdsPolicyBehavior: not restoring NvVars "
1665 "from disk since flash variables appear to be supported.\n"
1666 ));
1667 } else {
1668 //
1669 // Try to restore variables from the hard disk early so
1670 // they can be used for the other BDS connect operations.
1671 //
1672 PlatformBdsRestoreNvVarsFromHardDisk ();
1673 }
1674
1675 //
1676 // Get current Boot Mode
1677 //
1678 BootMode = GetBootModeHob ();
1679 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1680
1681 //
1682 // Go the different platform policy with different boot mode
1683 // Notes: this part code can be change with the table policy
1684 //
1685 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1686
1687 //
1688 // Logo show
1689 //
1690 BootLogoEnableLogo ();
1691
1692 //
1693 // Set PCI Interrupt Line registers and ACPI SCI_EN
1694 //
1695 PciAcpiInitialization ();
1696
1697 //
1698 // Write qemu bootorder to efi variables
1699 //
1700 StoreQemuBootOrder ();
1701
1702 //
1703 // Process QEMU's -kernel command line option
1704 //
1705 TryRunningQemuKernel ();
1706
1707 //
1708 // Perform some platform specific connect sequence
1709 //
1710 PlatformBdsConnectSequence ();
1711
1712 EfiBootManagerRefreshAllBootOption ();
1713
1714 //
1715 // Register UEFI Shell
1716 //
1717 PlatformRegisterFvBootOption (
1718 &gUefiShellFileGuid,
1719 L"EFI Internal Shell",
1720 LOAD_OPTION_ACTIVE
1721 );
1722
1723 RemoveStaleFvFileOptions ();
1724 SetBootOrderFromQemu ();
1725
1726 PlatformBmPrintScRegisterHandler ();
1727 }
1728
1729 /**
1730 This notification function is invoked when an instance of the
1731 EFI_DEVICE_PATH_PROTOCOL is produced.
1732
1733 @param Event The event that occurred
1734 @param Context For EFI compatibility. Not used.
1735
1736 **/
1737 VOID
1738 EFIAPI
1739 NotifyDevPath (
1740 IN EFI_EVENT Event,
1741 IN VOID *Context
1742 )
1743 {
1744 EFI_HANDLE Handle;
1745 EFI_STATUS Status;
1746 UINTN BufferSize;
1747 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1748 ATAPI_DEVICE_PATH *Atapi;
1749
1750 //
1751 // Examine all new handles
1752 //
1753 for ( ; ;) {
1754 //
1755 // Get the next handle
1756 //
1757 BufferSize = sizeof (Handle);
1758 Status = gBS->LocateHandle (
1759 ByRegisterNotify,
1760 NULL,
1761 mEfiDevPathNotifyReg,
1762 &BufferSize,
1763 &Handle
1764 );
1765
1766 //
1767 // If not found, we're done
1768 //
1769 if (EFI_NOT_FOUND == Status) {
1770 break;
1771 }
1772
1773 if (EFI_ERROR (Status)) {
1774 continue;
1775 }
1776
1777 //
1778 // Get the DevicePath protocol on that handle
1779 //
1780 Status = gBS->HandleProtocol (
1781 Handle,
1782 &gEfiDevicePathProtocolGuid,
1783 (VOID **)&DevPathNode
1784 );
1785 ASSERT_EFI_ERROR (Status);
1786
1787 while (!IsDevicePathEnd (DevPathNode)) {
1788 //
1789 // Find the handler to dump this device path node
1790 //
1791 if (
1792 (DevicePathType (DevPathNode) == MESSAGING_DEVICE_PATH) &&
1793 (DevicePathSubType (DevPathNode) == MSG_ATAPI_DP)
1794 )
1795 {
1796 Atapi = (ATAPI_DEVICE_PATH *)DevPathNode;
1797 PciOr16 (
1798 PCI_LIB_ADDRESS (
1799 0,
1800 1,
1801 1,
1802 (Atapi->PrimarySecondary == 1) ? 0x42 : 0x40
1803 ),
1804 BIT15
1805 );
1806 }
1807
1808 //
1809 // Next device path node
1810 //
1811 DevPathNode = NextDevicePathNode (DevPathNode);
1812 }
1813 }
1814
1815 return;
1816 }
1817
1818 VOID
1819 InstallDevicePathCallback (
1820 VOID
1821 )
1822 {
1823 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));
1824 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1825 &gEfiDevicePathProtocolGuid,
1826 TPL_CALLBACK,
1827 NotifyDevPath,
1828 NULL,
1829 &mEfiDevPathNotifyReg
1830 );
1831 }
1832
1833 /**
1834 This function is called each second during the boot manager waits the
1835 timeout.
1836
1837 @param TimeoutRemain The remaining timeout.
1838 **/
1839 VOID
1840 EFIAPI
1841 PlatformBootManagerWaitCallback (
1842 UINT16 TimeoutRemain
1843 )
1844 {
1845 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1846 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1847 UINT16 TimeoutInitial;
1848
1849 TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
1850
1851 //
1852 // If PcdPlatformBootTimeOut is set to zero, then we consider
1853 // that no progress update should be enacted (since we'd only
1854 // ever display a one-shot progress of either 0% or 100%).
1855 //
1856 if (TimeoutInitial == 0) {
1857 return;
1858 }
1859
1860 Black.Raw = 0x00000000;
1861 White.Raw = 0x00FFFFFF;
1862
1863 BootLogoUpdateProgress (
1864 White.Pixel,
1865 Black.Pixel,
1866 L"Start boot option",
1867 White.Pixel,
1868 (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
1869 0
1870 );
1871 }
1872
1873 /**
1874 The function is called when no boot option could be launched,
1875 including platform recovery options and options pointing to applications
1876 built into firmware volumes.
1877
1878 If this function returns, BDS attempts to enter an infinite loop.
1879 **/
1880 VOID
1881 EFIAPI
1882 PlatformBootManagerUnableToBoot (
1883 VOID
1884 )
1885 {
1886 EFI_STATUS Status;
1887 EFI_INPUT_KEY Key;
1888 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
1889 UINTN Index;
1890
1891 //
1892 // BootManagerMenu doesn't contain the correct information when return status
1893 // is EFI_NOT_FOUND.
1894 //
1895 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
1896 if (EFI_ERROR (Status)) {
1897 return;
1898 }
1899
1900 //
1901 // Normally BdsDxe does not print anything to the system console, but this is
1902 // a last resort -- the end-user will likely not see any DEBUG messages
1903 // logged in this situation.
1904 //
1905 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1906 // here to see if it makes sense to request and wait for a keypress.
1907 //
1908 if (gST->ConIn != NULL) {
1909 AsciiPrint (
1910 "%a: No bootable option or device was found.\n"
1911 "%a: Press any key to enter the Boot Manager Menu.\n",
1912 gEfiCallerBaseName,
1913 gEfiCallerBaseName
1914 );
1915 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
1916 ASSERT_EFI_ERROR (Status);
1917 ASSERT (Index == 0);
1918
1919 //
1920 // Drain any queued keys.
1921 //
1922 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
1923 //
1924 // just throw away Key
1925 //
1926 }
1927 }
1928
1929 for ( ; ;) {
1930 EfiBootManagerBoot (&BootManagerMenu);
1931 }
1932 }