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