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