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