]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg: Apply uncrustify changes
[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
9b08c655 451 FrontPageTimeout = GetFrontPageTimeoutFromQemu ();\r
ac0a286f 452 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);\r
579afd6b 453 ASSERT_RETURN_ERROR (PcdStatus);\r
9b08c655
LE
454 //\r
455 // Reflect the PCD in the standard Timeout variable.\r
456 //\r
457 Status = gRT->SetVariable (\r
458 EFI_TIME_OUT_VARIABLE_NAME,\r
459 &gEfiGlobalVariableGuid,\r
460 (EFI_VARIABLE_NON_VOLATILE |\r
461 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
462 EFI_VARIABLE_RUNTIME_ACCESS),\r
463 sizeof FrontPageTimeout,\r
464 &FrontPageTimeout\r
465 );\r
466 DEBUG ((\r
467 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
468 "%a: SetVariable(%s, %u): %r\n",\r
469 __FUNCTION__,\r
470 EFI_TIME_OUT_VARIABLE_NAME,\r
471 FrontPageTimeout,\r
472 Status\r
473 ));\r
07dd96e8
RN
474\r
475 PlatformRegisterOptionsAndKeys ();\r
7ebad830
LE
476\r
477 //\r
478 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
479 // instances on Virtio PCI RNG devices.\r
480 //\r
ac0a286f
MK
481 VisitAllInstancesOfProtocol (\r
482 &gEfiPciIoProtocolGuid,\r
483 ConnectVirtioPciRng,\r
484 NULL\r
485 );\r
30541881
RN
486}\r
487\r
30541881
RN
488EFI_STATUS\r
489EFIAPI\r
490ConnectRootBridge (\r
491 IN EFI_HANDLE RootBridgeHandle,\r
492 IN VOID *Instance,\r
493 IN VOID *Context\r
494 )\r
495{\r
ac0a286f 496 EFI_STATUS Status;\r
30541881
RN
497\r
498 //\r
499 // Make the PCI bus driver connect the root bridge, non-recursively. This\r
500 // will produce a number of child handles with PciIo on them.\r
501 //\r
502 Status = gBS->ConnectController (\r
503 RootBridgeHandle, // ControllerHandle\r
504 NULL, // DriverImageHandle\r
505 NULL, // RemainingDevicePath -- produce all\r
506 // children\r
507 FALSE // Recursive\r
508 );\r
509 return Status;\r
510}\r
511\r
7ebad830
LE
512STATIC\r
513EFI_STATUS\r
514EFIAPI\r
515ConnectVirtioPciRng (\r
ac0a286f
MK
516 IN EFI_HANDLE Handle,\r
517 IN VOID *Instance,\r
518 IN VOID *Context\r
7ebad830
LE
519 )\r
520{\r
ac0a286f
MK
521 EFI_PCI_IO_PROTOCOL *PciIo;\r
522 EFI_STATUS Status;\r
523 UINT16 VendorId;\r
524 UINT16 DeviceId;\r
525 UINT8 RevisionId;\r
526 BOOLEAN Virtio10;\r
527 UINT16 SubsystemId;\r
7ebad830
LE
528\r
529 PciIo = Instance;\r
530\r
531 //\r
532 // Read and check VendorId.\r
533 //\r
ac0a286f
MK
534 Status = PciIo->Pci.Read (\r
535 PciIo,\r
536 EfiPciIoWidthUint16,\r
537 PCI_VENDOR_ID_OFFSET,\r
538 1,\r
539 &VendorId\r
540 );\r
7ebad830
LE
541 if (EFI_ERROR (Status)) {\r
542 goto Error;\r
543 }\r
ac0a286f 544\r
7ebad830
LE
545 if (VendorId != VIRTIO_VENDOR_ID) {\r
546 return EFI_SUCCESS;\r
547 }\r
548\r
549 //\r
550 // Read DeviceId and RevisionId.\r
551 //\r
ac0a286f
MK
552 Status = PciIo->Pci.Read (\r
553 PciIo,\r
554 EfiPciIoWidthUint16,\r
555 PCI_DEVICE_ID_OFFSET,\r
556 1,\r
557 &DeviceId\r
558 );\r
7ebad830
LE
559 if (EFI_ERROR (Status)) {\r
560 goto Error;\r
561 }\r
ac0a286f
MK
562\r
563 Status = PciIo->Pci.Read (\r
564 PciIo,\r
565 EfiPciIoWidthUint8,\r
566 PCI_REVISION_ID_OFFSET,\r
567 1,\r
568 &RevisionId\r
569 );\r
7ebad830
LE
570 if (EFI_ERROR (Status)) {\r
571 goto Error;\r
572 }\r
573\r
574 //\r
575 // From DeviceId and RevisionId, determine whether the device is a\r
576 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
577 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
578 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
579 // only be sanity-checked, and SubsystemId will decide.\r
580 //\r
ac0a286f
MK
581 if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&\r
582 (RevisionId >= 0x01))\r
583 {\r
7ebad830 584 Virtio10 = TRUE;\r
ac0a286f 585 } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {\r
7ebad830
LE
586 Virtio10 = FALSE;\r
587 } else {\r
588 return EFI_SUCCESS;\r
589 }\r
590\r
591 //\r
592 // Read and check SubsystemId as dictated by Virtio10.\r
593 //\r
ac0a286f
MK
594 Status = PciIo->Pci.Read (\r
595 PciIo,\r
596 EfiPciIoWidthUint16,\r
597 PCI_SUBSYSTEM_ID_OFFSET,\r
598 1,\r
599 &SubsystemId\r
600 );\r
7ebad830
LE
601 if (EFI_ERROR (Status)) {\r
602 goto Error;\r
603 }\r
ac0a286f
MK
604\r
605 if ((Virtio10 && (SubsystemId >= 0x40)) ||\r
606 (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)))\r
607 {\r
7ebad830
LE
608 Status = gBS->ConnectController (\r
609 Handle, // ControllerHandle\r
610 NULL, // DriverImageHandle -- connect all drivers\r
611 NULL, // RemainingDevicePath -- produce all child handles\r
612 FALSE // Recursive -- don't follow child handles\r
613 );\r
614 if (EFI_ERROR (Status)) {\r
615 goto Error;\r
616 }\r
617 }\r
ac0a286f 618\r
7ebad830
LE
619 return EFI_SUCCESS;\r
620\r
621Error:\r
622 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));\r
623 return Status;\r
624}\r
625\r
fe1b9e8e
LE
626/**\r
627 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.\r
628\r
629 @param[in] DeviceHandle Handle of the LPC Bridge device.\r
630\r
631 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to\r
632 ConOut, ConIn, and ErrOut.\r
633\r
634 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
635 from DeviceHandle.\r
636**/\r
30541881
RN
637EFI_STATUS\r
638PrepareLpcBridgeDevicePath (\r
ac0a286f 639 IN EFI_HANDLE DeviceHandle\r
30541881 640 )\r
30541881
RN
641{\r
642 EFI_STATUS Status;\r
643 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
644 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
645 CHAR16 *DevPathStr;\r
646\r
647 DevicePath = NULL;\r
ac0a286f
MK
648 Status = gBS->HandleProtocol (\r
649 DeviceHandle,\r
650 &gEfiDevicePathProtocolGuid,\r
651 (VOID *)&DevicePath\r
652 );\r
30541881
RN
653 if (EFI_ERROR (Status)) {\r
654 return Status;\r
655 }\r
ac0a286f 656\r
30541881
RN
657 TempDevicePath = DevicePath;\r
658\r
659 //\r
660 // Register Keyboard\r
661 //\r
ac0a286f
MK
662 DevicePath = AppendDevicePathNode (\r
663 DevicePath,\r
664 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode\r
665 );\r
30541881 666\r
9dc08ec6 667 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
30541881
RN
668\r
669 //\r
670 // Register COM1\r
671 //\r
ac0a286f 672 DevicePath = TempDevicePath;\r
30541881
RN
673 gPnp16550ComPortDeviceNode.UID = 0;\r
674\r
ac0a286f
MK
675 DevicePath = AppendDevicePathNode (\r
676 DevicePath,\r
677 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode\r
678 );\r
679 DevicePath = AppendDevicePathNode (\r
680 DevicePath,\r
681 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
682 );\r
683 DevicePath = AppendDevicePathNode (\r
684 DevicePath,\r
685 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
686 );\r
30541881
RN
687\r
688 //\r
689 // Print Device Path\r
690 //\r
77f47588 691 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881 692 if (DevPathStr != NULL) {\r
ac0a286f 693 DEBUG ((\r
70d5086c 694 DEBUG_INFO,\r
30541881 695 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
fd42dcb1 696 DEBUG_LINE_NUMBER,\r
30541881
RN
697 gPnp16550ComPortDeviceNode.UID + 1,\r
698 DevPathStr\r
699 ));\r
ac0a286f 700 FreePool (DevPathStr);\r
30541881
RN
701 }\r
702\r
9dc08ec6
RN
703 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
704 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
705 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
706\r
707 //\r
708 // Register COM2\r
709 //\r
ac0a286f 710 DevicePath = TempDevicePath;\r
30541881
RN
711 gPnp16550ComPortDeviceNode.UID = 1;\r
712\r
ac0a286f
MK
713 DevicePath = AppendDevicePathNode (\r
714 DevicePath,\r
715 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode\r
716 );\r
717 DevicePath = AppendDevicePathNode (\r
718 DevicePath,\r
719 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
720 );\r
721 DevicePath = AppendDevicePathNode (\r
722 DevicePath,\r
723 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
724 );\r
30541881
RN
725\r
726 //\r
727 // Print Device Path\r
728 //\r
77f47588 729 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881 730 if (DevPathStr != NULL) {\r
ac0a286f 731 DEBUG ((\r
70d5086c 732 DEBUG_INFO,\r
30541881 733 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
fd42dcb1 734 DEBUG_LINE_NUMBER,\r
30541881
RN
735 gPnp16550ComPortDeviceNode.UID + 1,\r
736 DevPathStr\r
737 ));\r
ac0a286f 738 FreePool (DevPathStr);\r
30541881
RN
739 }\r
740\r
9dc08ec6
RN
741 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
742 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
743 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
744\r
745 return EFI_SUCCESS;\r
746}\r
747\r
55f47d22 748typedef struct {\r
ac0a286f
MK
749 VENDOR_DEVICE_PATH Guid;\r
750 EFI_DEVICE_PATH_PROTOCOL End;\r
55f47d22
GH
751} SERIAL_DEVICE_PATH;\r
752\r
ac0a286f 753SERIAL_DEVICE_PATH serialDevicePath = {\r
55f47d22 754 {\r
ac0a286f
MK
755 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }\r
756 },\r
55f47d22
GH
757 EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
758 },\r
ac0a286f
MK
759 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
760 }\r
55f47d22
GH
761};\r
762\r
763VOID\r
764PrepareMicrovmDevicePath (\r
765 VOID\r
766 )\r
767{\r
768 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
769 UINT16 HostBridgeDevId;\r
770\r
771 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
772 if (HostBridgeDevId != MICROVM_PSEUDO_DEVICE_ID) {\r
773 return;\r
774 }\r
775\r
ac0a286f
MK
776 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&serialDevicePath;\r
777 DevicePath = AppendDevicePathNode (\r
778 DevicePath,\r
779 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
780 );\r
781 DevicePath = AppendDevicePathNode (\r
782 DevicePath,\r
783 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
784 );\r
55f47d22
GH
785\r
786 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
787 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
788 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
789}\r
790\r
30541881
RN
791EFI_STATUS\r
792GetGopDevicePath (\r
ac0a286f
MK
793 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,\r
794 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath\r
795 )\r
30541881 796{\r
ac0a286f
MK
797 UINTN Index;\r
798 EFI_STATUS Status;\r
799 EFI_HANDLE PciDeviceHandle;\r
800 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
801 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;\r
802 UINTN GopHandleCount;\r
803 EFI_HANDLE *GopHandleBuffer;\r
804\r
805 if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) {\r
30541881
RN
806 return EFI_INVALID_PARAMETER;\r
807 }\r
808\r
809 //\r
810 // Initialize the GopDevicePath to be PciDevicePath\r
811 //\r
812 *GopDevicePath = PciDevicePath;\r
813 TempPciDevicePath = PciDevicePath;\r
814\r
815 Status = gBS->LocateDevicePath (\r
816 &gEfiDevicePathProtocolGuid,\r
817 &TempPciDevicePath,\r
818 &PciDeviceHandle\r
819 );\r
820 if (EFI_ERROR (Status)) {\r
821 return Status;\r
822 }\r
823\r
824 //\r
f17c0ab6 825 // Try to connect this handle, so that GOP driver could start on this\r
30541881
RN
826 // device and create child handles with GraphicsOutput Protocol installed\r
827 // on them, then we get device paths of these child handles and select\r
828 // them as possible console device.\r
829 //\r
830 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
831\r
832 Status = gBS->LocateHandleBuffer (\r
833 ByProtocol,\r
834 &gEfiGraphicsOutputProtocolGuid,\r
835 NULL,\r
836 &GopHandleCount,\r
837 &GopHandleBuffer\r
838 );\r
839 if (!EFI_ERROR (Status)) {\r
840 //\r
841 // Add all the child handles as possible Console Device\r
842 //\r
843 for (Index = 0; Index < GopHandleCount; Index++) {\r
ac0a286f
MK
844 Status = gBS->HandleProtocol (\r
845 GopHandleBuffer[Index],\r
846 &gEfiDevicePathProtocolGuid,\r
847 (VOID *)&TempDevicePath\r
848 );\r
30541881
RN
849 if (EFI_ERROR (Status)) {\r
850 continue;\r
851 }\r
ac0a286f 852\r
30541881
RN
853 if (CompareMem (\r
854 PciDevicePath,\r
855 TempDevicePath,\r
856 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH\r
ac0a286f
MK
857 ) == 0)\r
858 {\r
30541881
RN
859 //\r
860 // In current implementation, we only enable one of the child handles\r
861 // as console device, i.e. sotre one of the child handle's device\r
862 // path to variable "ConOut"\r
f17c0ab6 863 // In future, we could select all child handles to be console device\r
30541881
RN
864 //\r
865\r
866 *GopDevicePath = TempDevicePath;\r
867\r
868 //\r
18064510
LE
869 // Delete the PCI device's path that added by\r
870 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
30541881 871 //\r
9dc08ec6
RN
872 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
873 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
30541881
RN
874 }\r
875 }\r
ac0a286f 876\r
30541881
RN
877 gBS->FreePool (GopHandleBuffer);\r
878 }\r
879\r
880 return EFI_SUCCESS;\r
881}\r
882\r
fe1b9e8e
LE
883/**\r
884 Add PCI display to ConOut.\r
885\r
886 @param[in] DeviceHandle Handle of the PCI display device.\r
887\r
888 @retval EFI_SUCCESS The PCI display device has been added to ConOut.\r
889\r
890 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
891 from DeviceHandle.\r
892**/\r
30541881 893EFI_STATUS\r
4fdb585c 894PreparePciDisplayDevicePath (\r
ac0a286f 895 IN EFI_HANDLE DeviceHandle\r
30541881 896 )\r
30541881
RN
897{\r
898 EFI_STATUS Status;\r
899 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
900 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
901\r
902 DevicePath = NULL;\r
903 GopDevicePath = NULL;\r
ac0a286f
MK
904 Status = gBS->HandleProtocol (\r
905 DeviceHandle,\r
906 &gEfiDevicePathProtocolGuid,\r
907 (VOID *)&DevicePath\r
908 );\r
30541881
RN
909 if (EFI_ERROR (Status)) {\r
910 return Status;\r
911 }\r
912\r
913 GetGopDevicePath (DevicePath, &GopDevicePath);\r
914 DevicePath = GopDevicePath;\r
915\r
9dc08ec6 916 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
30541881
RN
917\r
918 return EFI_SUCCESS;\r
919}\r
920\r
fe1b9e8e 921/**\r
30541881 922 Add PCI Serial to ConOut, ConIn, ErrOut.\r
30541881 923\r
fe1b9e8e 924 @param[in] DeviceHandle Handle of the PCI serial device.\r
30541881 925\r
fe1b9e8e
LE
926 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
927 ErrOut.\r
30541881 928\r
fe1b9e8e
LE
929 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
930 from DeviceHandle.\r
931**/\r
932EFI_STATUS\r
933PreparePciSerialDevicePath (\r
ac0a286f 934 IN EFI_HANDLE DeviceHandle\r
fe1b9e8e 935 )\r
30541881
RN
936{\r
937 EFI_STATUS Status;\r
938 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
939\r
940 DevicePath = NULL;\r
ac0a286f
MK
941 Status = gBS->HandleProtocol (\r
942 DeviceHandle,\r
943 &gEfiDevicePathProtocolGuid,\r
944 (VOID *)&DevicePath\r
945 );\r
30541881
RN
946 if (EFI_ERROR (Status)) {\r
947 return Status;\r
948 }\r
949\r
ac0a286f
MK
950 DevicePath = AppendDevicePathNode (\r
951 DevicePath,\r
952 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
953 );\r
954 DevicePath = AppendDevicePathNode (\r
955 DevicePath,\r
956 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
957 );\r
30541881 958\r
9dc08ec6
RN
959 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
960 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
961 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
962\r
963 return EFI_SUCCESS;\r
964}\r
965\r
966EFI_STATUS\r
967VisitAllInstancesOfProtocol (\r
968 IN EFI_GUID *Id,\r
969 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
970 IN VOID *Context\r
971 )\r
972{\r
ac0a286f
MK
973 EFI_STATUS Status;\r
974 UINTN HandleCount;\r
975 EFI_HANDLE *HandleBuffer;\r
976 UINTN Index;\r
977 VOID *Instance;\r
30541881
RN
978\r
979 //\r
980 // Start to check all the PciIo to find all possible device\r
981 //\r
ac0a286f 982 HandleCount = 0;\r
30541881 983 HandleBuffer = NULL;\r
ac0a286f
MK
984 Status = gBS->LocateHandleBuffer (\r
985 ByProtocol,\r
986 Id,\r
987 NULL,\r
988 &HandleCount,\r
989 &HandleBuffer\r
990 );\r
30541881
RN
991 if (EFI_ERROR (Status)) {\r
992 return Status;\r
993 }\r
994\r
995 for (Index = 0; Index < HandleCount; Index++) {\r
996 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
997 if (EFI_ERROR (Status)) {\r
998 continue;\r
999 }\r
1000\r
ac0a286f
MK
1001 Status = (*CallBackFunction)(\r
1002 HandleBuffer[Index],\r
1003 Instance,\r
1004 Context\r
1005 );\r
30541881
RN
1006 }\r
1007\r
1008 gBS->FreePool (HandleBuffer);\r
1009\r
1010 return EFI_SUCCESS;\r
1011}\r
1012\r
30541881
RN
1013EFI_STATUS\r
1014EFIAPI\r
1015VisitingAPciInstance (\r
1016 IN EFI_HANDLE Handle,\r
1017 IN VOID *Instance,\r
1018 IN VOID *Context\r
1019 )\r
1020{\r
ac0a286f
MK
1021 EFI_STATUS Status;\r
1022 EFI_PCI_IO_PROTOCOL *PciIo;\r
1023 PCI_TYPE00 Pci;\r
30541881 1024\r
ac0a286f 1025 PciIo = (EFI_PCI_IO_PROTOCOL *)Instance;\r
30541881
RN
1026\r
1027 //\r
1028 // Check for all PCI device\r
1029 //\r
1030 Status = PciIo->Pci.Read (\r
ac0a286f
MK
1031 PciIo,\r
1032 EfiPciIoWidthUint32,\r
1033 0,\r
1034 sizeof (Pci) / sizeof (UINT32),\r
1035 &Pci\r
1036 );\r
30541881
RN
1037 if (EFI_ERROR (Status)) {\r
1038 return Status;\r
1039 }\r
1040\r
ac0a286f
MK
1041 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN)Context)(\r
1042 Handle,\r
1043 PciIo,\r
1044 &Pci\r
1045 );\r
30541881
RN
1046}\r
1047\r
30541881
RN
1048EFI_STATUS\r
1049VisitAllPciInstances (\r
ac0a286f 1050 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
30541881
RN
1051 )\r
1052{\r
1053 return VisitAllInstancesOfProtocol (\r
1054 &gEfiPciIoProtocolGuid,\r
1055 VisitingAPciInstance,\r
ac0a286f 1056 (VOID *)(UINTN)CallBackFunction\r
30541881
RN
1057 );\r
1058}\r
1059\r
30541881
RN
1060/**\r
1061 Do platform specific PCI Device check and add them to\r
1062 ConOut, ConIn, ErrOut.\r
1063\r
1064 @param[in] Handle - Handle of PCI device instance\r
1065 @param[in] PciIo - PCI IO protocol instance\r
1066 @param[in] Pci - PCI Header register block\r
1067\r
18064510
LE
1068 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
1069 successfully.\r
30541881
RN
1070 @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
1071\r
1072**/\r
1073EFI_STATUS\r
1074EFIAPI\r
1075DetectAndPreparePlatformPciDevicePath (\r
1076 IN EFI_HANDLE Handle,\r
1077 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1078 IN PCI_TYPE00 *Pci\r
1079 )\r
1080{\r
ac0a286f 1081 EFI_STATUS Status;\r
30541881
RN
1082\r
1083 Status = PciIo->Attributes (\r
ac0a286f
MK
1084 PciIo,\r
1085 EfiPciIoAttributeOperationEnable,\r
1086 EFI_PCI_DEVICE_ENABLE,\r
1087 NULL\r
1088 );\r
30541881
RN
1089 ASSERT_EFI_ERROR (Status);\r
1090\r
f803c03c
LE
1091 //\r
1092 // Here we decide whether it is LPC Bridge\r
1093 //\r
1094 if ((IS_PCI_LPC (Pci)) ||\r
1095 ((IS_PCI_ISA_PDECODE (Pci)) &&\r
1096 (Pci->Hdr.VendorId == 0x8086) &&\r
1097 (Pci->Hdr.DeviceId == 0x7000)\r
1098 )\r
ac0a286f
MK
1099 )\r
1100 {\r
30541881 1101 //\r
f803c03c
LE
1102 // Add IsaKeyboard to ConIn,\r
1103 // add IsaSerial to ConOut, ConIn, ErrOut\r
30541881 1104 //\r
70d5086c 1105 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));\r
f803c03c
LE
1106 PrepareLpcBridgeDevicePath (Handle);\r
1107 return EFI_SUCCESS;\r
1108 }\r
ac0a286f 1109\r
f803c03c
LE
1110 //\r
1111 // Here we decide which Serial device to enable in PCI bus\r
1112 //\r
1113 if (IS_PCI_16550SERIAL (Pci)) {\r
30541881 1114 //\r
f803c03c 1115 // Add them to ConOut, ConIn, ErrOut.\r
30541881 1116 //\r
70d5086c 1117 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));\r
f803c03c
LE
1118 PreparePciSerialDevicePath (Handle);\r
1119 return EFI_SUCCESS;\r
30541881
RN
1120 }\r
1121\r
1122 //\r
4fdb585c 1123 // Here we decide which display device to enable in PCI bus\r
30541881 1124 //\r
4fdb585c 1125 if (IS_PCI_DISPLAY (Pci)) {\r
30541881
RN
1126 //\r
1127 // Add them to ConOut.\r
1128 //\r
70d5086c 1129 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));\r
4fdb585c 1130 PreparePciDisplayDevicePath (Handle);\r
30541881
RN
1131 return EFI_SUCCESS;\r
1132 }\r
1133\r
1134 return Status;\r
1135}\r
1136\r
fe1b9e8e
LE
1137/**\r
1138 Connect the predefined platform default console device.\r
1139\r
1140 Always try to find and enable PCI display devices.\r
1141\r
1142 @param[in] PlatformConsole Predefined platform default console device array.\r
1143**/\r
e9e9ad64
RN
1144VOID\r
1145PlatformInitializeConsole (\r
ac0a286f 1146 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
30541881 1147 )\r
30541881 1148{\r
ac0a286f 1149 UINTN Index;\r
30541881
RN
1150\r
1151 //\r
f803c03c
LE
1152 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
1153 // ErrOut\r
30541881 1154 //\r
f803c03c 1155 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
30541881 1156\r
55f47d22
GH
1157 PrepareMicrovmDevicePath ();\r
1158\r
f803c03c
LE
1159 //\r
1160 // Have chance to connect the platform default console,\r
1161 // the platform default console is the minimum device group\r
1162 // the platform should support\r
1163 //\r
1164 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {\r
30541881 1165 //\r
f803c03c 1166 // Update the console variable with the connect type\r
30541881 1167 //\r
f803c03c 1168 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {\r
ac0a286f
MK
1169 EfiBootManagerUpdateConsoleVariable (\r
1170 ConIn,\r
1171 PlatformConsole[Index].DevicePath,\r
1172 NULL\r
1173 );\r
f803c03c 1174 }\r
ac0a286f 1175\r
f803c03c 1176 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
ac0a286f
MK
1177 EfiBootManagerUpdateConsoleVariable (\r
1178 ConOut,\r
1179 PlatformConsole[Index].DevicePath,\r
1180 NULL\r
1181 );\r
f803c03c 1182 }\r
ac0a286f 1183\r
f803c03c 1184 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
ac0a286f
MK
1185 EfiBootManagerUpdateConsoleVariable (\r
1186 ErrOut,\r
1187 PlatformConsole[Index].DevicePath,\r
1188 NULL\r
1189 );\r
30541881 1190 }\r
30541881 1191 }\r
30541881
RN
1192}\r
1193\r
30541881
RN
1194/**\r
1195 Configure PCI Interrupt Line register for applicable devices\r
1196 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
1197\r
1198 @param[in] Handle - Handle of PCI device instance\r
1199 @param[in] PciIo - PCI IO protocol instance\r
1200 @param[in] PciHdr - PCI Header register block\r
1201\r
1202 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
1203\r
1204**/\r
1205EFI_STATUS\r
1206EFIAPI\r
1207SetPciIntLine (\r
1208 IN EFI_HANDLE Handle,\r
1209 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1210 IN PCI_TYPE00 *PciHdr\r
1211 )\r
1212{\r
1213 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1214 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1215 UINTN RootSlot;\r
1216 UINTN Idx;\r
1217 UINT8 IrqLine;\r
1218 EFI_STATUS Status;\r
1219 UINT32 RootBusNumber;\r
1220\r
1221 Status = EFI_SUCCESS;\r
1222\r
1223 if (PciHdr->Device.InterruptPin != 0) {\r
30541881
RN
1224 DevPathNode = DevicePathFromHandle (Handle);\r
1225 ASSERT (DevPathNode != NULL);\r
1226 DevPath = DevPathNode;\r
1227\r
1228 RootBusNumber = 0;\r
ac0a286f
MK
1229 if ((DevicePathType (DevPathNode) == ACPI_DEVICE_PATH) &&\r
1230 (DevicePathSubType (DevPathNode) == ACPI_DP) &&\r
1231 (((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID (0x0A03)))\r
1232 {\r
30541881
RN
1233 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;\r
1234 }\r
1235\r
1236 //\r
1237 // Compute index into PciHostIrqs[] table by walking\r
1238 // the device path and adding up all device numbers\r
1239 //\r
ac0a286f 1240 Status = EFI_NOT_FOUND;\r
30541881 1241 RootSlot = 0;\r
ac0a286f 1242 Idx = PciHdr->Device.InterruptPin - 1;\r
30541881 1243 while (!IsDevicePathEnd (DevPathNode)) {\r
ac0a286f
MK
1244 if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&\r
1245 (DevicePathSubType (DevPathNode) == HW_PCI_DP))\r
1246 {\r
30541881
RN
1247 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1248\r
1249 //\r
1250 // Unlike SeaBIOS, which starts climbing from the leaf device\r
1251 // up toward the root, we traverse the device path starting at\r
1252 // the root moving toward the leaf node.\r
1253 // The slot number of the top-level parent bridge is needed for\r
1254 // Q35 cases with more than 24 slots on the root bus.\r
1255 //\r
1256 if (Status != EFI_SUCCESS) {\r
ac0a286f 1257 Status = EFI_SUCCESS;\r
30541881
RN
1258 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1259 }\r
1260 }\r
1261\r
1262 DevPathNode = NextDevicePathNode (DevPathNode);\r
1263 }\r
ac0a286f 1264\r
30541881
RN
1265 if (EFI_ERROR (Status)) {\r
1266 return Status;\r
1267 }\r
ac0a286f
MK
1268\r
1269 if ((RootBusNumber == 0) && (RootSlot == 0)) {\r
1270 DEBUG ((\r
70d5086c 1271 DEBUG_ERROR,\r
30541881
RN
1272 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
1273 __FUNCTION__\r
1274 ));\r
1275 ASSERT (FALSE);\r
1276 }\r
1277\r
1278 //\r
1279 // Final PciHostIrqs[] index calculation depends on the platform\r
1280 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
1281 //\r
1282 switch (mHostBridgeDevId) {\r
1283 case INTEL_82441_DEVICE_ID:\r
1284 Idx -= 1;\r
1285 break;\r
1286 case INTEL_Q35_MCH_DEVICE_ID:\r
1287 //\r
1288 // SeaBIOS contains the following comment:\r
1289 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
1290 // with a different starting index - see q35-acpi-dsdt.dsl.\r
1291 //\r
1292 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
1293 //\r
1294 if (RootSlot > 24) {\r
1295 //\r
1296 // in this case, subtract back out RootSlot from Idx\r
1297 // (SeaBIOS never adds it to begin with, but that would make our\r
1298 // device path traversal loop above too awkward)\r
1299 //\r
1300 Idx -= RootSlot;\r
1301 }\r
ac0a286f 1302\r
30541881
RN
1303 break;\r
1304 default:\r
1305 ASSERT (FALSE); // should never get here\r
1306 }\r
ac0a286f
MK
1307\r
1308 Idx %= ARRAY_SIZE (PciHostIrqs);\r
30541881
RN
1309 IrqLine = PciHostIrqs[Idx];\r
1310\r
1311 DEBUG_CODE_BEGIN ();\r
1312 {\r
ac0a286f
MK
1313 CHAR16 *DevPathString;\r
1314 STATIC CHAR16 Fallback[] = L"<failed to convert>";\r
1315 UINTN Segment, Bus, Device, Function;\r
30541881
RN
1316\r
1317 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);\r
1318 if (DevPathString == NULL) {\r
1319 DevPathString = Fallback;\r
1320 }\r
ac0a286f 1321\r
30541881
RN
1322 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
1323 ASSERT_EFI_ERROR (Status);\r
1324\r
ac0a286f
MK
1325 DEBUG ((\r
1326 DEBUG_VERBOSE,\r
1327 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",\r
1328 __FUNCTION__,\r
1329 (UINT32)Bus,\r
1330 (UINT32)Device,\r
1331 (UINT32)Function,\r
1332 DevPathString,\r
1333 IrqLine\r
1334 ));\r
30541881
RN
1335\r
1336 if (DevPathString != Fallback) {\r
1337 FreePool (DevPathString);\r
1338 }\r
1339 }\r
1340 DEBUG_CODE_END ();\r
1341\r
1342 //\r
1343 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
1344 //\r
1345 Status = PciIo->Pci.Write (\r
ac0a286f
MK
1346 PciIo,\r
1347 EfiPciIoWidthUint8,\r
1348 PCI_INT_LINE_OFFSET,\r
1349 1,\r
1350 &IrqLine\r
1351 );\r
30541881
RN
1352 }\r
1353\r
1354 return Status;\r
1355}\r
1356\r
30541881
RN
1357VOID\r
1358PciAcpiInitialization (\r
1359 )\r
1360{\r
1361 UINTN Pmba;\r
1362\r
1363 //\r
1364 // Query Host Bridge DID to determine platform type\r
1365 //\r
1366 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
1367 switch (mHostBridgeDevId) {\r
1368 case INTEL_82441_DEVICE_ID:\r
1369 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
1370 //\r
1371 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
1372 //\r
6573ae8c
BH
1373 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // A\r
1374 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // B\r
1375 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // C\r
1376 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // D\r
30541881
RN
1377 break;\r
1378 case INTEL_Q35_MCH_DEVICE_ID:\r
1379 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
1380 //\r
1381 // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
1382 //\r
6573ae8c
BH
1383 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // A\r
1384 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // B\r
1385 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // C\r
1386 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // D\r
1387 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // E\r
1388 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // F\r
1389 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // G\r
1390 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // H\r
30541881 1391 break;\r
2c467c9b
GH
1392 case MICROVM_PSEUDO_DEVICE_ID:\r
1393 return;\r
30541881 1394 default:\r
ad256f95
AP
1395 if (XenDetected ()) {\r
1396 //\r
1397 // There is no PCI bus in this case.\r
1398 //\r
1399 return;\r
1400 }\r
ac0a286f
MK
1401\r
1402 DEBUG ((\r
1403 DEBUG_ERROR,\r
1404 "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
1405 __FUNCTION__,\r
1406 mHostBridgeDevId\r
1407 ));\r
30541881
RN
1408 ASSERT (FALSE);\r
1409 return;\r
1410 }\r
1411\r
1412 //\r
1413 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
1414 //\r
1415 VisitAllPciInstances (SetPciIntLine);\r
1416\r
1417 //\r
1418 // Set ACPI SCI_EN bit in PMCNTRL\r
1419 //\r
1420 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
1421}\r
1422\r
30541881
RN
1423EFI_STATUS\r
1424EFIAPI\r
1425ConnectRecursivelyIfPciMassStorage (\r
1426 IN EFI_HANDLE Handle,\r
1427 IN EFI_PCI_IO_PROTOCOL *Instance,\r
1428 IN PCI_TYPE00 *PciHeader\r
1429 )\r
1430{\r
1431 EFI_STATUS Status;\r
1432 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1433 CHAR16 *DevPathStr;\r
1434\r
da2369d2
GL
1435 //\r
1436 // Recognize PCI Mass Storage, and Xen PCI devices\r
1437 //\r
1438 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||\r
ac0a286f
MK
1439 (XenDetected () && IS_CLASS2 (PciHeader, 0xFF, 0x80)))\r
1440 {\r
30541881 1441 DevicePath = NULL;\r
ac0a286f
MK
1442 Status = gBS->HandleProtocol (\r
1443 Handle,\r
1444 &gEfiDevicePathProtocolGuid,\r
1445 (VOID *)&DevicePath\r
1446 );\r
30541881
RN
1447 if (EFI_ERROR (Status)) {\r
1448 return Status;\r
1449 }\r
1450\r
1451 //\r
1452 // Print Device Path\r
1453 //\r
77f47588 1454 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881 1455 if (DevPathStr != NULL) {\r
ac0a286f 1456 DEBUG ((\r
70d5086c 1457 DEBUG_INFO,\r
da2369d2 1458 "Found %s device: %s\n",\r
18064510
LE
1459 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1460 L"Mass Storage" :\r
1461 L"Xen"\r
ac0a286f 1462 ),\r
30541881
RN
1463 DevPathStr\r
1464 ));\r
ac0a286f 1465 FreePool (DevPathStr);\r
30541881
RN
1466 }\r
1467\r
1468 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1469 if (EFI_ERROR (Status)) {\r
1470 return Status;\r
1471 }\r
30541881
RN
1472 }\r
1473\r
1474 return EFI_SUCCESS;\r
1475}\r
1476\r
30541881
RN
1477/**\r
1478 This notification function is invoked when the\r
1479 EMU Variable FVB has been changed.\r
1480\r
8c0b0b34
TH
1481 @param Event The event that occurred\r
1482 @param Context For EFI compatibility. Not used.\r
30541881
RN
1483\r
1484**/\r
1485VOID\r
1486EFIAPI\r
1487EmuVariablesUpdatedCallback (\r
ac0a286f
MK
1488 IN EFI_EVENT Event,\r
1489 IN VOID *Context\r
30541881
RN
1490 )\r
1491{\r
70d5086c 1492 DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n"));\r
30541881
RN
1493 UpdateNvVarsOnFileSystem ();\r
1494}\r
1495\r
30541881
RN
1496EFI_STATUS\r
1497EFIAPI\r
1498VisitingFileSystemInstance (\r
1499 IN EFI_HANDLE Handle,\r
1500 IN VOID *Instance,\r
1501 IN VOID *Context\r
1502 )\r
1503{\r
1504 EFI_STATUS Status;\r
1505 STATIC BOOLEAN ConnectedToFileSystem = FALSE;\r
579afd6b 1506 RETURN_STATUS PcdStatus;\r
30541881
RN
1507\r
1508 if (ConnectedToFileSystem) {\r
1509 return EFI_ALREADY_STARTED;\r
1510 }\r
1511\r
1512 Status = ConnectNvVarsToFileSystem (Handle);\r
1513 if (EFI_ERROR (Status)) {\r
1514 return Status;\r
1515 }\r
1516\r
1517 ConnectedToFileSystem = TRUE;\r
ac0a286f 1518 mEmuVariableEvent =\r
30541881
RN
1519 EfiCreateProtocolNotifyEvent (\r
1520 &gEfiDevicePathProtocolGuid,\r
1521 TPL_CALLBACK,\r
1522 EmuVariablesUpdatedCallback,\r
1523 NULL,\r
1524 &mEmuVariableEventReg\r
1525 );\r
ac0a286f
MK
1526 PcdStatus = PcdSet64S (\r
1527 PcdEmuVariableEvent,\r
1528 (UINT64)(UINTN)mEmuVariableEvent\r
1529 );\r
579afd6b 1530 ASSERT_RETURN_ERROR (PcdStatus);\r
30541881
RN
1531\r
1532 return EFI_SUCCESS;\r
1533}\r
1534\r
30541881
RN
1535VOID\r
1536PlatformBdsRestoreNvVarsFromHardDisk (\r
1537 )\r
1538{\r
1539 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);\r
1540 VisitAllInstancesOfProtocol (\r
1541 &gEfiSimpleFileSystemProtocolGuid,\r
1542 VisitingFileSystemInstance,\r
1543 NULL\r
1544 );\r
30541881
RN
1545}\r
1546\r
fe1b9e8e
LE
1547/**\r
1548 Connect with predefined platform connect sequence.\r
1549\r
1550 The OEM/IBV can customize with their own connect sequence.\r
1551**/\r
30541881
RN
1552VOID\r
1553PlatformBdsConnectSequence (\r
1554 VOID\r
1555 )\r
30541881 1556{\r
ac0a286f
MK
1557 UINTN Index;\r
1558 RETURN_STATUS Status;\r
30541881 1559\r
70d5086c 1560 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));\r
30541881
RN
1561\r
1562 Index = 0;\r
1563\r
1564 //\r
1565 // Here we can get the customized platform connect sequence\r
1566 // Notes: we can connect with new variable which record the\r
1567 // last time boots connect device path sequence\r
1568 //\r
1569 while (gPlatformConnectSequence[Index] != NULL) {\r
1570 //\r
1571 // Build the platform boot option\r
1572 //\r
fed691a6 1573 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
30541881
RN
1574 Index++;\r
1575 }\r
1576\r
245c643c
LE
1577 Status = ConnectDevicesFromQemu ();\r
1578 if (RETURN_ERROR (Status)) {\r
1579 //\r
1580 // Just use the simple policy to connect all devices\r
1581 //\r
1582 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));\r
1583 EfiBootManagerConnectAll ();\r
1584 }\r
30541881
RN
1585}\r
1586\r
30541881
RN
1587/**\r
1588 Save the S3 boot script.\r
1589\r
1590 Note that DxeSmmReadyToLock must be signaled after this function returns;\r
1591 otherwise the script wouldn't be saved actually.\r
1592**/\r
1593STATIC\r
1594VOID\r
1595SaveS3BootScript (\r
1596 VOID\r
1597 )\r
1598{\r
ac0a286f
MK
1599 EFI_STATUS Status;\r
1600 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;\r
1601 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };\r
30541881 1602\r
ac0a286f
MK
1603 Status = gBS->LocateProtocol (\r
1604 &gEfiS3SaveStateProtocolGuid,\r
1605 NULL,\r
1606 (VOID **)&BootScript\r
1607 );\r
30541881
RN
1608 ASSERT_EFI_ERROR (Status);\r
1609\r
1610 //\r
1611 // Despite the opcode documentation in the PI spec, the protocol\r
1612 // implementation embeds a deep copy of the info in the boot script, rather\r
1613 // than storing just a pointer to runtime or NVS storage.\r
1614 //\r
ac0a286f
MK
1615 Status = BootScript->Write (\r
1616 BootScript,\r
1617 EFI_BOOT_SCRIPT_INFORMATION_OPCODE,\r
1618 (UINT32)sizeof Info,\r
1619 (EFI_PHYSICAL_ADDRESS)(UINTN)&Info\r
1620 );\r
30541881
RN
1621 ASSERT_EFI_ERROR (Status);\r
1622}\r
1623\r
fe1b9e8e
LE
1624/**\r
1625 Do the platform specific action after the console is ready\r
1626\r
1627 Possible things that can be done in PlatformBootManagerAfterConsole:\r
1628\r
1629 > Console post action:\r
1630 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1631 > Signal console ready platform customized event\r
1632 > Run diagnostics like memory testing\r
1633 > Connect certain devices\r
1634 > Dispatch aditional option roms\r
1635 > Special boot: e.g.: USB boot, enter UI\r
1636**/\r
30541881
RN
1637VOID\r
1638EFIAPI\r
a7566234
RN
1639PlatformBootManagerAfterConsole (\r
1640 VOID\r
30541881 1641 )\r
30541881 1642{\r
ac0a286f 1643 EFI_BOOT_MODE BootMode;\r
30541881 1644\r
70d5086c 1645 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));\r
30541881
RN
1646\r
1647 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
ac0a286f
MK
1648 DEBUG ((\r
1649 DEBUG_INFO,\r
1650 "PlatformBdsPolicyBehavior: not restoring NvVars "\r
1651 "from disk since flash variables appear to be supported.\n"\r
1652 ));\r
30541881
RN
1653 } else {\r
1654 //\r
1655 // Try to restore variables from the hard disk early so\r
1656 // they can be used for the other BDS connect operations.\r
1657 //\r
1658 PlatformBdsRestoreNvVarsFromHardDisk ();\r
1659 }\r
1660\r
30541881
RN
1661 //\r
1662 // Get current Boot Mode\r
1663 //\r
30edcbf5 1664 BootMode = GetBootModeHob ();\r
837d9eea 1665 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
30541881
RN
1666\r
1667 //\r
1668 // Go the different platform policy with different boot mode\r
1669 // Notes: this part code can be change with the table policy\r
1670 //\r
1671 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
30541881
RN
1672\r
1673 //\r
e64a2ebe 1674 // Logo show\r
30541881 1675 //\r
ab970515 1676 BootLogoEnableLogo ();\r
30541881 1677\r
5942ea61
LE
1678 //\r
1679 // Set PCI Interrupt Line registers and ACPI SCI_EN\r
1680 //\r
1681 PciAcpiInitialization ();\r
1682\r
30541881 1683 //\r
a34a8869 1684 // Process QEMU's -kernel command line option\r
30541881 1685 //\r
a34a8869 1686 TryRunningQemuKernel ();\r
30541881
RN
1687\r
1688 //\r
a34a8869 1689 // Perform some platform specific connect sequence\r
30541881 1690 //\r
a34a8869 1691 PlatformBdsConnectSequence ();\r
30541881 1692\r
04fe914b
RN
1693 EfiBootManagerRefreshAllBootOption ();\r
1694\r
14b2ebc3
GL
1695 //\r
1696 // Register UEFI Shell\r
1697 //\r
1698 PlatformRegisterFvBootOption (\r
ac0a286f
MK
1699 &gUefiShellFileGuid,\r
1700 L"EFI Internal Shell",\r
1701 LOAD_OPTION_ACTIVE\r
14b2ebc3
GL
1702 );\r
1703\r
2eb35898 1704 RemoveStaleFvFileOptions ();\r
2542feea 1705 SetBootOrderFromQemu ();\r
a7488174
LE
1706\r
1707 PlatformBmPrintScRegisterHandler ();\r
30541881
RN
1708}\r
1709\r
30541881
RN
1710/**\r
1711 This notification function is invoked when an instance of the\r
1712 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1713\r
8c0b0b34
TH
1714 @param Event The event that occurred\r
1715 @param Context For EFI compatibility. Not used.\r
30541881
RN
1716\r
1717**/\r
1718VOID\r
1719EFIAPI\r
1720NotifyDevPath (\r
ac0a286f
MK
1721 IN EFI_EVENT Event,\r
1722 IN VOID *Context\r
30541881
RN
1723 )\r
1724{\r
ac0a286f
MK
1725 EFI_HANDLE Handle;\r
1726 EFI_STATUS Status;\r
1727 UINTN BufferSize;\r
1728 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1729 ATAPI_DEVICE_PATH *Atapi;\r
30541881
RN
1730\r
1731 //\r
1732 // Examine all new handles\r
1733 //\r
ac0a286f 1734 for ( ; ;) {\r
30541881
RN
1735 //\r
1736 // Get the next handle\r
1737 //\r
1738 BufferSize = sizeof (Handle);\r
ac0a286f
MK
1739 Status = gBS->LocateHandle (\r
1740 ByRegisterNotify,\r
1741 NULL,\r
1742 mEfiDevPathNotifyReg,\r
1743 &BufferSize,\r
1744 &Handle\r
1745 );\r
30541881
RN
1746\r
1747 //\r
1748 // If not found, we're done\r
1749 //\r
1750 if (EFI_NOT_FOUND == Status) {\r
1751 break;\r
1752 }\r
1753\r
1754 if (EFI_ERROR (Status)) {\r
1755 continue;\r
1756 }\r
1757\r
1758 //\r
1759 // Get the DevicePath protocol on that handle\r
1760 //\r
ac0a286f
MK
1761 Status = gBS->HandleProtocol (\r
1762 Handle,\r
1763 &gEfiDevicePathProtocolGuid,\r
1764 (VOID **)&DevPathNode\r
1765 );\r
30541881
RN
1766 ASSERT_EFI_ERROR (Status);\r
1767\r
1768 while (!IsDevicePathEnd (DevPathNode)) {\r
1769 //\r
1770 // Find the handler to dump this device path node\r
1771 //\r
1772 if (\r
ac0a286f
MK
1773 (DevicePathType (DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1774 (DevicePathSubType (DevPathNode) == MSG_ATAPI_DP)\r
1775 )\r
1776 {\r
1777 Atapi = (ATAPI_DEVICE_PATH *)DevPathNode;\r
30541881
RN
1778 PciOr16 (\r
1779 PCI_LIB_ADDRESS (\r
1780 0,\r
1781 1,\r
1782 1,\r
ac0a286f 1783 (Atapi->PrimarySecondary == 1) ? 0x42 : 0x40\r
30541881
RN
1784 ),\r
1785 BIT15\r
1786 );\r
1787 }\r
1788\r
1789 //\r
1790 // Next device path node\r
1791 //\r
1792 DevPathNode = NextDevicePathNode (DevPathNode);\r
1793 }\r
1794 }\r
1795\r
1796 return;\r
1797}\r
1798\r
30541881
RN
1799VOID\r
1800InstallDevicePathCallback (\r
1801 VOID\r
1802 )\r
1803{\r
70d5086c 1804 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));\r
30541881 1805 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
ac0a286f
MK
1806 &gEfiDevicePathProtocolGuid,\r
1807 TPL_CALLBACK,\r
1808 NotifyDevPath,\r
1809 NULL,\r
1810 &mEfiDevPathNotifyReg\r
1811 );\r
30541881
RN
1812}\r
1813\r
a7566234 1814/**\r
18064510
LE
1815 This function is called each second during the boot manager waits the\r
1816 timeout.\r
a7566234
RN
1817\r
1818 @param TimeoutRemain The remaining timeout.\r
1819**/\r
1820VOID\r
1821EFIAPI\r
1822PlatformBootManagerWaitCallback (\r
ac0a286f 1823 UINT16 TimeoutRemain\r
a7566234
RN
1824 )\r
1825{\r
ac0a286f
MK
1826 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1827 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1828 UINT16 TimeoutInitial;\r
fd096a99 1829\r
c3c90d8a
PB
1830 TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);\r
1831\r
1832 //\r
1833 // If PcdPlatformBootTimeOut is set to zero, then we consider\r
1834 // that no progress update should be enacted (since we'd only\r
1835 // ever display a one-shot progress of either 0% or 100%).\r
1836 //\r
1837 if (TimeoutInitial == 0) {\r
1838 return;\r
1839 }\r
fd096a99
LE
1840\r
1841 Black.Raw = 0x00000000;\r
1842 White.Raw = 0x00FFFFFF;\r
1843\r
1844 BootLogoUpdateProgress (\r
1845 White.Pixel,\r
1846 Black.Pixel,\r
1847 L"Start boot option",\r
1848 White.Pixel,\r
c3c90d8a 1849 (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,\r
fd096a99
LE
1850 0\r
1851 );\r
a7566234
RN
1852}\r
1853\r
5f66615b
RN
1854/**\r
1855 The function is called when no boot option could be launched,\r
1856 including platform recovery options and options pointing to applications\r
1857 built into firmware volumes.\r
1858\r
1859 If this function returns, BDS attempts to enter an infinite loop.\r
1860**/\r
1861VOID\r
1862EFIAPI\r
1863PlatformBootManagerUnableToBoot (\r
1864 VOID\r
1865 )\r
1866{\r
ac0a286f
MK
1867 EFI_STATUS Status;\r
1868 EFI_INPUT_KEY Key;\r
1869 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
1870 UINTN Index;\r
5f66615b
RN
1871\r
1872 //\r
1873 // BootManagerMenu doesn't contain the correct information when return status\r
1874 // is EFI_NOT_FOUND.\r
1875 //\r
1876 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1877 if (EFI_ERROR (Status)) {\r
1878 return;\r
1879 }\r
ac0a286f 1880\r
5f66615b
RN
1881 //\r
1882 // Normally BdsDxe does not print anything to the system console, but this is\r
1883 // a last resort -- the end-user will likely not see any DEBUG messages\r
1884 // logged in this situation.\r
1885 //\r
1886 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
1887 // here to see if it makes sense to request and wait for a keypress.\r
1888 //\r
1889 if (gST->ConIn != NULL) {\r
1890 AsciiPrint (\r
1891 "%a: No bootable option or device was found.\n"\r
1892 "%a: Press any key to enter the Boot Manager Menu.\n",\r
1893 gEfiCallerBaseName,\r
1894 gEfiCallerBaseName\r
1895 );\r
1896 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
1897 ASSERT_EFI_ERROR (Status);\r
1898 ASSERT (Index == 0);\r
1899\r
1900 //\r
1901 // Drain any queued keys.\r
1902 //\r
1903 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
1904 //\r
1905 // just throw away Key\r
1906 //\r
1907 }\r
1908 }\r
1909\r
ac0a286f 1910 for ( ; ;) {\r
5f66615b
RN
1911 EfiBootManagerBoot (&BootManagerMenu);\r
1912 }\r
1913}\r