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