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