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