]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: connect Virtio RNG devices again
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLib / BdsPlatform.c
CommitLineData
30541881
RN
1/** @file\r
2 Platform BDS customizations.\r
3\r
a7566234 4 Copyright (c) 2004 - 2016, 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
30541881
RN
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
30541881
RN
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
30541881
RN
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
07dd96e8
RN
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
2eb35898
LE
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
07dd96e8
RN
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
07dd96e8
RN
311}\r
312\r
30541881
RN
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
7ebad830
LE
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
30541881
RN
330STATIC\r
331VOID\r
332SaveS3BootScript (\r
333 VOID\r
334 );\r
335\r
336//\r
337// BDS Platform Functions\r
338//\r
fe1b9e8e
LE
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
30541881
RN
352VOID\r
353EFIAPI\r
a7566234 354PlatformBootManagerBeforeConsole (\r
30541881
RN
355 VOID\r
356 )\r
30541881 357{\r
579afd6b
LE
358 EFI_HANDLE Handle;\r
359 EFI_STATUS Status;\r
360 RETURN_STATUS PcdStatus;\r
30541881 361\r
a7566234 362 DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));\r
30541881
RN
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
e9e9ad64 398\r
9789894e 399 //\r
18064510
LE
400 // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
401 // installation.\r
9789894e
RN
402 //\r
403 EfiBootManagerDispatchDeferredImages ();\r
404\r
e9e9ad64 405 PlatformInitializeConsole (gPlatformConsole);\r
579afd6b
LE
406 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,\r
407 GetFrontPageTimeoutFromQemu ());\r
408 ASSERT_RETURN_ERROR (PcdStatus);\r
07dd96e8
RN
409\r
410 PlatformRegisterOptionsAndKeys ();\r
7ebad830
LE
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
30541881
RN
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
7ebad830
LE
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
fe1b9e8e
LE
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
30541881
RN
546EFI_STATUS\r
547PrepareLpcBridgeDevicePath (\r
548 IN EFI_HANDLE DeviceHandle\r
549 )\r
30541881
RN
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
18064510
LE
570 DevicePath = AppendDevicePathNode (DevicePath,\r
571 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
30541881 572\r
9dc08ec6 573 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
30541881
RN
574\r
575 //\r
576 // Register COM1\r
577 //\r
578 DevicePath = TempDevicePath;\r
579 gPnp16550ComPortDeviceNode.UID = 0;\r
580\r
18064510
LE
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
30541881
RN
587\r
588 //\r
589 // Print Device Path\r
590 //\r
77f47588 591 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
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
9dc08ec6
RN
603 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
604 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
605 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
606\r
607 //\r
608 // Register COM2\r
609 //\r
610 DevicePath = TempDevicePath;\r
611 gPnp16550ComPortDeviceNode.UID = 1;\r
612\r
18064510
LE
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
30541881
RN
619\r
620 //\r
621 // Print Device Path\r
622 //\r
77f47588 623 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
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
9dc08ec6
RN
635 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
636 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
637 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
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
f17c0ab6 676 // Try to connect this handle, so that GOP driver could start on this\r
30541881
RN
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
18064510
LE
695 Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
696 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
30541881
RN
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
f17c0ab6 709 // In future, we could select all child handles to be console device\r
30541881
RN
710 //\r
711\r
712 *GopDevicePath = TempDevicePath;\r
713\r
714 //\r
18064510
LE
715 // Delete the PCI device's path that added by\r
716 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
30541881 717 //\r
9dc08ec6
RN
718 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
719 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
30541881
RN
720 }\r
721 }\r
722 gBS->FreePool (GopHandleBuffer);\r
723 }\r
724\r
725 return EFI_SUCCESS;\r
726}\r
727\r
fe1b9e8e
LE
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
30541881 738EFI_STATUS\r
4fdb585c 739PreparePciDisplayDevicePath (\r
30541881
RN
740 IN EFI_HANDLE DeviceHandle\r
741 )\r
30541881
RN
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
9dc08ec6 761 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
30541881
RN
762\r
763 return EFI_SUCCESS;\r
764}\r
765\r
fe1b9e8e 766/**\r
30541881 767 Add PCI Serial to ConOut, ConIn, ErrOut.\r
30541881 768\r
fe1b9e8e 769 @param[in] DeviceHandle Handle of the PCI serial device.\r
30541881 770\r
fe1b9e8e
LE
771 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
772 ErrOut.\r
30541881 773\r
fe1b9e8e
LE
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
30541881
RN
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
18064510
LE
795 DevicePath = AppendDevicePathNode (DevicePath,\r
796 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
797 DevicePath = AppendDevicePathNode (DevicePath,\r
798 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
30541881 799\r
9dc08ec6
RN
800 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
801 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
802 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
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
18064510
LE
914 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
915 successfully.\r
30541881
RN
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
f803c03c
LE
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
30541881 946 //\r
f803c03c
LE
947 // Add IsaKeyboard to ConIn,\r
948 // add IsaSerial to ConOut, ConIn, ErrOut\r
30541881 949 //\r
f803c03c
LE
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
30541881 958 //\r
f803c03c 959 // Add them to ConOut, ConIn, ErrOut.\r
30541881 960 //\r
f803c03c
LE
961 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));\r
962 PreparePciSerialDevicePath (Handle);\r
963 return EFI_SUCCESS;\r
30541881
RN
964 }\r
965\r
966 //\r
4fdb585c 967 // Here we decide which display device to enable in PCI bus\r
30541881 968 //\r
4fdb585c 969 if (IS_PCI_DISPLAY (Pci)) {\r
30541881
RN
970 //\r
971 // Add them to ConOut.\r
972 //\r
4fdb585c
LE
973 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));\r
974 PreparePciDisplayDevicePath (Handle);\r
30541881
RN
975 return EFI_SUCCESS;\r
976 }\r
977\r
978 return Status;\r
979}\r
980\r
981\r
fe1b9e8e
LE
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
e9e9ad64
RN
989VOID\r
990PlatformInitializeConsole (\r
991 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
30541881 992 )\r
30541881 993{\r
30541881 994 UINTN Index;\r
30541881
RN
995\r
996 //\r
f803c03c
LE
997 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
998 // ErrOut\r
30541881 999 //\r
f803c03c 1000 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
30541881 1001\r
f803c03c
LE
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
30541881 1008 //\r
f803c03c 1009 // Update the console variable with the connect type\r
30541881 1010 //\r
f803c03c
LE
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
30541881 1022 }\r
30541881 1023 }\r
30541881
RN
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
da2369d2
GL
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
30541881
RN
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
da2369d2
GL
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
30541881
RN
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
77f47588 1294 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
1295 if (DevPathStr != NULL) {\r
1296 DEBUG((\r
1297 EFI_D_INFO,\r
da2369d2 1298 "Found %s device: %s\n",\r
18064510
LE
1299 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1300 L"Mass Storage" :\r
1301 L"Xen"\r
1302 ),\r
30541881
RN
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
8c0b0b34
TH
1323 @param Event The event that occurred\r
1324 @param Context For EFI compatibility. Not used.\r
30541881
RN
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
579afd6b 1349 RETURN_STATUS PcdStatus;\r
30541881
RN
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
579afd6b
LE
1369 PcdStatus = PcdSet64S (PcdEmuVariableEvent,\r
1370 (UINT64)(UINTN) mEmuVariableEvent);\r
1371 ASSERT_RETURN_ERROR (PcdStatus);\r
30541881
RN
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
fe1b9e8e
LE
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
30541881
RN
1395VOID\r
1396PlatformBdsConnectSequence (\r
1397 VOID\r
1398 )\r
30541881 1399{\r
245c643c
LE
1400 UINTN Index;\r
1401 RETURN_STATUS Status;\r
30541881
RN
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
fed691a6 1416 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
30541881
RN
1417 Index++;\r
1418 }\r
1419\r
245c643c
LE
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
30541881
RN
1428}\r
1429\r
30541881
RN
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
fe1b9e8e
LE
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
30541881
RN
1475VOID\r
1476EFIAPI\r
a7566234
RN
1477PlatformBootManagerAfterConsole (\r
1478 VOID\r
30541881 1479 )\r
30541881 1480{\r
30541881
RN
1481 EFI_BOOT_MODE BootMode;\r
1482\r
a7566234 1483 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));\r
30541881
RN
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
30541881
RN
1496 //\r
1497 // Get current Boot Mode\r
1498 //\r
30edcbf5 1499 BootMode = GetBootModeHob ();\r
837d9eea 1500 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
30541881
RN
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
30541881
RN
1507\r
1508 //\r
e64a2ebe 1509 // Logo show\r
30541881 1510 //\r
ab970515 1511 BootLogoEnableLogo ();\r
30541881 1512\r
5942ea61
LE
1513 //\r
1514 // Set PCI Interrupt Line registers and ACPI SCI_EN\r
1515 //\r
1516 PciAcpiInitialization ();\r
1517\r
30541881 1518 //\r
a34a8869 1519 // Process QEMU's -kernel command line option\r
30541881 1520 //\r
a34a8869 1521 TryRunningQemuKernel ();\r
30541881
RN
1522\r
1523 //\r
a34a8869 1524 // Perform some platform specific connect sequence\r
30541881 1525 //\r
a34a8869 1526 PlatformBdsConnectSequence ();\r
30541881 1527\r
04fe914b
RN
1528 EfiBootManagerRefreshAllBootOption ();\r
1529\r
14b2ebc3
GL
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
2eb35898 1537 RemoveStaleFvFileOptions ();\r
2542feea 1538 SetBootOrderFromQemu ();\r
30541881
RN
1539}\r
1540\r
30541881
RN
1541/**\r
1542 This notification function is invoked when an instance of the\r
1543 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1544\r
8c0b0b34
TH
1545 @param Event The event that occurred\r
1546 @param Context For EFI compatibility. Not used.\r
30541881
RN
1547\r
1548**/\r
1549VOID\r
1550EFIAPI\r
1551NotifyDevPath (\r
1552 IN EFI_EVENT Event,\r
1553 IN VOID *Context\r
1554 )\r
1555{\r
1556 EFI_HANDLE Handle;\r
1557 EFI_STATUS Status;\r
1558 UINTN BufferSize;\r
1559 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1560 ATAPI_DEVICE_PATH *Atapi;\r
1561\r
1562 //\r
1563 // Examine all new handles\r
1564 //\r
1565 for (;;) {\r
1566 //\r
1567 // Get the next handle\r
1568 //\r
1569 BufferSize = sizeof (Handle);\r
1570 Status = gBS->LocateHandle (\r
1571 ByRegisterNotify,\r
1572 NULL,\r
1573 mEfiDevPathNotifyReg,\r
1574 &BufferSize,\r
1575 &Handle\r
1576 );\r
1577\r
1578 //\r
1579 // If not found, we're done\r
1580 //\r
1581 if (EFI_NOT_FOUND == Status) {\r
1582 break;\r
1583 }\r
1584\r
1585 if (EFI_ERROR (Status)) {\r
1586 continue;\r
1587 }\r
1588\r
1589 //\r
1590 // Get the DevicePath protocol on that handle\r
1591 //\r
18064510
LE
1592 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1593 (VOID **)&DevPathNode);\r
30541881
RN
1594 ASSERT_EFI_ERROR (Status);\r
1595\r
1596 while (!IsDevicePathEnd (DevPathNode)) {\r
1597 //\r
1598 // Find the handler to dump this device path node\r
1599 //\r
1600 if (\r
1601 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1602 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
1603 ) {\r
1604 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
1605 PciOr16 (\r
1606 PCI_LIB_ADDRESS (\r
1607 0,\r
1608 1,\r
1609 1,\r
1610 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
1611 ),\r
1612 BIT15\r
1613 );\r
1614 }\r
1615\r
1616 //\r
1617 // Next device path node\r
1618 //\r
1619 DevPathNode = NextDevicePathNode (DevPathNode);\r
1620 }\r
1621 }\r
1622\r
1623 return;\r
1624}\r
1625\r
1626\r
1627VOID\r
1628InstallDevicePathCallback (\r
1629 VOID\r
1630 )\r
1631{\r
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
a7566234 1642/**\r
18064510
LE
1643 This function is called each second during the boot manager waits the\r
1644 timeout.\r
a7566234
RN
1645\r
1646 @param TimeoutRemain The remaining timeout.\r
1647**/\r
1648VOID\r
1649EFIAPI\r
1650PlatformBootManagerWaitCallback (\r
1651 UINT16 TimeoutRemain\r
1652 )\r
1653{\r
fd096a99
LE
1654 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1655 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
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
a7566234
RN
1671}\r
1672\r