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