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