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