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