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