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