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