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