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