]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: Use XenDetected from XenPlatformLib
[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
1211 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
1212 __FUNCTION__, mHostBridgeDevId));\r
1213 ASSERT (FALSE);\r
1214 return;\r
1215 }\r
1216\r
1217 //\r
1218 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
1219 //\r
1220 VisitAllPciInstances (SetPciIntLine);\r
1221\r
1222 //\r
1223 // Set ACPI SCI_EN bit in PMCNTRL\r
1224 //\r
1225 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
1226}\r
1227\r
30541881
RN
1228EFI_STATUS\r
1229EFIAPI\r
1230ConnectRecursivelyIfPciMassStorage (\r
1231 IN EFI_HANDLE Handle,\r
1232 IN EFI_PCI_IO_PROTOCOL *Instance,\r
1233 IN PCI_TYPE00 *PciHeader\r
1234 )\r
1235{\r
1236 EFI_STATUS Status;\r
1237 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1238 CHAR16 *DevPathStr;\r
1239\r
da2369d2
GL
1240 //\r
1241 // Recognize PCI Mass Storage, and Xen PCI devices\r
1242 //\r
1243 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||\r
1244 (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {\r
30541881
RN
1245 DevicePath = NULL;\r
1246 Status = gBS->HandleProtocol (\r
1247 Handle,\r
1248 &gEfiDevicePathProtocolGuid,\r
1249 (VOID*)&DevicePath\r
1250 );\r
1251 if (EFI_ERROR (Status)) {\r
1252 return Status;\r
1253 }\r
1254\r
1255 //\r
1256 // Print Device Path\r
1257 //\r
77f47588 1258 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
1259 if (DevPathStr != NULL) {\r
1260 DEBUG((\r
1261 EFI_D_INFO,\r
da2369d2 1262 "Found %s device: %s\n",\r
18064510
LE
1263 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1264 L"Mass Storage" :\r
1265 L"Xen"\r
1266 ),\r
30541881
RN
1267 DevPathStr\r
1268 ));\r
1269 FreePool(DevPathStr);\r
1270 }\r
1271\r
1272 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1273 if (EFI_ERROR (Status)) {\r
1274 return Status;\r
1275 }\r
1276\r
1277 }\r
1278\r
1279 return EFI_SUCCESS;\r
1280}\r
1281\r
1282\r
1283/**\r
1284 This notification function is invoked when the\r
1285 EMU Variable FVB has been changed.\r
1286\r
8c0b0b34
TH
1287 @param Event The event that occurred\r
1288 @param Context For EFI compatibility. Not used.\r
30541881
RN
1289\r
1290**/\r
1291VOID\r
1292EFIAPI\r
1293EmuVariablesUpdatedCallback (\r
1294 IN EFI_EVENT Event,\r
1295 IN VOID *Context\r
1296 )\r
1297{\r
1298 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));\r
1299 UpdateNvVarsOnFileSystem ();\r
1300}\r
1301\r
1302\r
1303EFI_STATUS\r
1304EFIAPI\r
1305VisitingFileSystemInstance (\r
1306 IN EFI_HANDLE Handle,\r
1307 IN VOID *Instance,\r
1308 IN VOID *Context\r
1309 )\r
1310{\r
1311 EFI_STATUS Status;\r
1312 STATIC BOOLEAN ConnectedToFileSystem = FALSE;\r
579afd6b 1313 RETURN_STATUS PcdStatus;\r
30541881
RN
1314\r
1315 if (ConnectedToFileSystem) {\r
1316 return EFI_ALREADY_STARTED;\r
1317 }\r
1318\r
1319 Status = ConnectNvVarsToFileSystem (Handle);\r
1320 if (EFI_ERROR (Status)) {\r
1321 return Status;\r
1322 }\r
1323\r
1324 ConnectedToFileSystem = TRUE;\r
1325 mEmuVariableEvent =\r
1326 EfiCreateProtocolNotifyEvent (\r
1327 &gEfiDevicePathProtocolGuid,\r
1328 TPL_CALLBACK,\r
1329 EmuVariablesUpdatedCallback,\r
1330 NULL,\r
1331 &mEmuVariableEventReg\r
1332 );\r
579afd6b
LE
1333 PcdStatus = PcdSet64S (PcdEmuVariableEvent,\r
1334 (UINT64)(UINTN) mEmuVariableEvent);\r
1335 ASSERT_RETURN_ERROR (PcdStatus);\r
30541881
RN
1336\r
1337 return EFI_SUCCESS;\r
1338}\r
1339\r
1340\r
1341VOID\r
1342PlatformBdsRestoreNvVarsFromHardDisk (\r
1343 )\r
1344{\r
1345 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);\r
1346 VisitAllInstancesOfProtocol (\r
1347 &gEfiSimpleFileSystemProtocolGuid,\r
1348 VisitingFileSystemInstance,\r
1349 NULL\r
1350 );\r
1351\r
1352}\r
1353\r
fe1b9e8e
LE
1354/**\r
1355 Connect with predefined platform connect sequence.\r
1356\r
1357 The OEM/IBV can customize with their own connect sequence.\r
1358**/\r
30541881
RN
1359VOID\r
1360PlatformBdsConnectSequence (\r
1361 VOID\r
1362 )\r
30541881 1363{\r
245c643c
LE
1364 UINTN Index;\r
1365 RETURN_STATUS Status;\r
30541881
RN
1366\r
1367 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));\r
1368\r
1369 Index = 0;\r
1370\r
1371 //\r
1372 // Here we can get the customized platform connect sequence\r
1373 // Notes: we can connect with new variable which record the\r
1374 // last time boots connect device path sequence\r
1375 //\r
1376 while (gPlatformConnectSequence[Index] != NULL) {\r
1377 //\r
1378 // Build the platform boot option\r
1379 //\r
fed691a6 1380 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
30541881
RN
1381 Index++;\r
1382 }\r
1383\r
245c643c
LE
1384 Status = ConnectDevicesFromQemu ();\r
1385 if (RETURN_ERROR (Status)) {\r
1386 //\r
1387 // Just use the simple policy to connect all devices\r
1388 //\r
1389 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));\r
1390 EfiBootManagerConnectAll ();\r
1391 }\r
30541881
RN
1392}\r
1393\r
30541881
RN
1394/**\r
1395 Save the S3 boot script.\r
1396\r
1397 Note that DxeSmmReadyToLock must be signaled after this function returns;\r
1398 otherwise the script wouldn't be saved actually.\r
1399**/\r
1400STATIC\r
1401VOID\r
1402SaveS3BootScript (\r
1403 VOID\r
1404 )\r
1405{\r
1406 EFI_STATUS Status;\r
1407 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;\r
1408 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };\r
1409\r
1410 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,\r
1411 (VOID **) &BootScript);\r
1412 ASSERT_EFI_ERROR (Status);\r
1413\r
1414 //\r
1415 // Despite the opcode documentation in the PI spec, the protocol\r
1416 // implementation embeds a deep copy of the info in the boot script, rather\r
1417 // than storing just a pointer to runtime or NVS storage.\r
1418 //\r
1419 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,\r
1420 (UINT32) sizeof Info,\r
1421 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);\r
1422 ASSERT_EFI_ERROR (Status);\r
1423}\r
1424\r
1425\r
fe1b9e8e
LE
1426/**\r
1427 Do the platform specific action after the console is ready\r
1428\r
1429 Possible things that can be done in PlatformBootManagerAfterConsole:\r
1430\r
1431 > Console post action:\r
1432 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1433 > Signal console ready platform customized event\r
1434 > Run diagnostics like memory testing\r
1435 > Connect certain devices\r
1436 > Dispatch aditional option roms\r
1437 > Special boot: e.g.: USB boot, enter UI\r
1438**/\r
30541881
RN
1439VOID\r
1440EFIAPI\r
a7566234
RN
1441PlatformBootManagerAfterConsole (\r
1442 VOID\r
30541881 1443 )\r
30541881 1444{\r
30541881
RN
1445 EFI_BOOT_MODE BootMode;\r
1446\r
a7566234 1447 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));\r
30541881
RN
1448\r
1449 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
1450 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "\r
1451 "from disk since flash variables appear to be supported.\n"));\r
1452 } else {\r
1453 //\r
1454 // Try to restore variables from the hard disk early so\r
1455 // they can be used for the other BDS connect operations.\r
1456 //\r
1457 PlatformBdsRestoreNvVarsFromHardDisk ();\r
1458 }\r
1459\r
30541881
RN
1460 //\r
1461 // Get current Boot Mode\r
1462 //\r
30edcbf5 1463 BootMode = GetBootModeHob ();\r
837d9eea 1464 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
30541881
RN
1465\r
1466 //\r
1467 // Go the different platform policy with different boot mode\r
1468 // Notes: this part code can be change with the table policy\r
1469 //\r
1470 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
30541881
RN
1471\r
1472 //\r
e64a2ebe 1473 // Logo show\r
30541881 1474 //\r
ab970515 1475 BootLogoEnableLogo ();\r
30541881 1476\r
5942ea61
LE
1477 //\r
1478 // Set PCI Interrupt Line registers and ACPI SCI_EN\r
1479 //\r
1480 PciAcpiInitialization ();\r
1481\r
8d65d3b2
MAL
1482 //\r
1483 // Process TPM PPI request\r
1484 //\r
1485 Tcg2PhysicalPresenceLibProcessRequest (NULL);\r
1486\r
30541881 1487 //\r
a34a8869 1488 // Process QEMU's -kernel command line option\r
30541881 1489 //\r
a34a8869 1490 TryRunningQemuKernel ();\r
30541881
RN
1491\r
1492 //\r
a34a8869 1493 // Perform some platform specific connect sequence\r
30541881 1494 //\r
a34a8869 1495 PlatformBdsConnectSequence ();\r
30541881 1496\r
04fe914b
RN
1497 EfiBootManagerRefreshAllBootOption ();\r
1498\r
14b2ebc3
GL
1499 //\r
1500 // Register UEFI Shell\r
1501 //\r
1502 PlatformRegisterFvBootOption (\r
84f736a7 1503 &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
14b2ebc3
GL
1504 );\r
1505\r
2eb35898 1506 RemoveStaleFvFileOptions ();\r
2542feea 1507 SetBootOrderFromQemu ();\r
a7488174
LE
1508\r
1509 PlatformBmPrintScRegisterHandler ();\r
30541881
RN
1510}\r
1511\r
30541881
RN
1512/**\r
1513 This notification function is invoked when an instance of the\r
1514 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1515\r
8c0b0b34
TH
1516 @param Event The event that occurred\r
1517 @param Context For EFI compatibility. Not used.\r
30541881
RN
1518\r
1519**/\r
1520VOID\r
1521EFIAPI\r
1522NotifyDevPath (\r
1523 IN EFI_EVENT Event,\r
1524 IN VOID *Context\r
1525 )\r
1526{\r
1527 EFI_HANDLE Handle;\r
1528 EFI_STATUS Status;\r
1529 UINTN BufferSize;\r
1530 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1531 ATAPI_DEVICE_PATH *Atapi;\r
1532\r
1533 //\r
1534 // Examine all new handles\r
1535 //\r
1536 for (;;) {\r
1537 //\r
1538 // Get the next handle\r
1539 //\r
1540 BufferSize = sizeof (Handle);\r
1541 Status = gBS->LocateHandle (\r
1542 ByRegisterNotify,\r
1543 NULL,\r
1544 mEfiDevPathNotifyReg,\r
1545 &BufferSize,\r
1546 &Handle\r
1547 );\r
1548\r
1549 //\r
1550 // If not found, we're done\r
1551 //\r
1552 if (EFI_NOT_FOUND == Status) {\r
1553 break;\r
1554 }\r
1555\r
1556 if (EFI_ERROR (Status)) {\r
1557 continue;\r
1558 }\r
1559\r
1560 //\r
1561 // Get the DevicePath protocol on that handle\r
1562 //\r
18064510
LE
1563 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1564 (VOID **)&DevPathNode);\r
30541881
RN
1565 ASSERT_EFI_ERROR (Status);\r
1566\r
1567 while (!IsDevicePathEnd (DevPathNode)) {\r
1568 //\r
1569 // Find the handler to dump this device path node\r
1570 //\r
1571 if (\r
1572 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1573 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
1574 ) {\r
1575 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
1576 PciOr16 (\r
1577 PCI_LIB_ADDRESS (\r
1578 0,\r
1579 1,\r
1580 1,\r
1581 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
1582 ),\r
1583 BIT15\r
1584 );\r
1585 }\r
1586\r
1587 //\r
1588 // Next device path node\r
1589 //\r
1590 DevPathNode = NextDevicePathNode (DevPathNode);\r
1591 }\r
1592 }\r
1593\r
1594 return;\r
1595}\r
1596\r
1597\r
1598VOID\r
1599InstallDevicePathCallback (\r
1600 VOID\r
1601 )\r
1602{\r
1603 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));\r
1604 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
1605 &gEfiDevicePathProtocolGuid,\r
1606 TPL_CALLBACK,\r
1607 NotifyDevPath,\r
1608 NULL,\r
1609 &mEfiDevPathNotifyReg\r
1610 );\r
1611}\r
1612\r
a7566234 1613/**\r
18064510
LE
1614 This function is called each second during the boot manager waits the\r
1615 timeout.\r
a7566234
RN
1616\r
1617 @param TimeoutRemain The remaining timeout.\r
1618**/\r
1619VOID\r
1620EFIAPI\r
1621PlatformBootManagerWaitCallback (\r
1622 UINT16 TimeoutRemain\r
1623 )\r
1624{\r
fd096a99
LE
1625 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1626 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1627 UINT16 Timeout;\r
1628\r
1629 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
1630\r
1631 Black.Raw = 0x00000000;\r
1632 White.Raw = 0x00FFFFFF;\r
1633\r
1634 BootLogoUpdateProgress (\r
1635 White.Pixel,\r
1636 Black.Pixel,\r
1637 L"Start boot option",\r
1638 White.Pixel,\r
1639 (Timeout - TimeoutRemain) * 100 / Timeout,\r
1640 0\r
1641 );\r
a7566234
RN
1642}\r
1643\r
5f66615b
RN
1644/**\r
1645 The function is called when no boot option could be launched,\r
1646 including platform recovery options and options pointing to applications\r
1647 built into firmware volumes.\r
1648\r
1649 If this function returns, BDS attempts to enter an infinite loop.\r
1650**/\r
1651VOID\r
1652EFIAPI\r
1653PlatformBootManagerUnableToBoot (\r
1654 VOID\r
1655 )\r
1656{\r
1657 EFI_STATUS Status;\r
1658 EFI_INPUT_KEY Key;\r
1659 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
1660 UINTN Index;\r
1661\r
1662 //\r
1663 // BootManagerMenu doesn't contain the correct information when return status\r
1664 // is EFI_NOT_FOUND.\r
1665 //\r
1666 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1667 if (EFI_ERROR (Status)) {\r
1668 return;\r
1669 }\r
1670 //\r
1671 // Normally BdsDxe does not print anything to the system console, but this is\r
1672 // a last resort -- the end-user will likely not see any DEBUG messages\r
1673 // logged in this situation.\r
1674 //\r
1675 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
1676 // here to see if it makes sense to request and wait for a keypress.\r
1677 //\r
1678 if (gST->ConIn != NULL) {\r
1679 AsciiPrint (\r
1680 "%a: No bootable option or device was found.\n"\r
1681 "%a: Press any key to enter the Boot Manager Menu.\n",\r
1682 gEfiCallerBaseName,\r
1683 gEfiCallerBaseName\r
1684 );\r
1685 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
1686 ASSERT_EFI_ERROR (Status);\r
1687 ASSERT (Index == 0);\r
1688\r
1689 //\r
1690 // Drain any queued keys.\r
1691 //\r
1692 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
1693 //\r
1694 // just throw away Key\r
1695 //\r
1696 }\r
1697 }\r
1698\r
1699 for (;;) {\r
1700 EfiBootManagerBoot (&BootManagerMenu);\r
1701 }\r
1702}\r