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