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