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