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