]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmVirtPkg/PlatformBootManagerLib: Don't update progress if Pcd is 0
[mirror_edk2.git] / ArmVirtPkg / Library / PlatformBootManagerLib / PlatformBm.c
CommitLineData
8d620322
LE
1/** @file\r
2 Implementation for PlatformBootManagerLib library class interfaces.\r
3\r
4 Copyright (C) 2015-2016, Red Hat, Inc.\r
5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
8d1b281a 6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
8d620322 7\r
9792fb0e 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8d620322
LE
9\r
10**/\r
11\r
12#include <IndustryStandard/Pci22.h>\r
c4add6b6 13#include <IndustryStandard/Virtio095.h>\r
2c8805bc 14#include <Library/BootLogoLib.h>\r
8d620322
LE
15#include <Library/DevicePathLib.h>\r
16#include <Library/PcdLib.h>\r
1797f32e 17#include <Library/PlatformBmPrintScLib.h>\r
8d620322 18#include <Library/QemuBootOrderLib.h>\r
2c5c33cd 19#include <Library/UefiBootManagerLib.h>\r
8d620322 20#include <Protocol/DevicePath.h>\r
0e2c6c55 21#include <Protocol/FirmwareVolume2.h>\r
8d620322 22#include <Protocol/GraphicsOutput.h>\r
793b3b5b 23#include <Protocol/LoadedImage.h>\r
8d620322
LE
24#include <Protocol/PciIo.h>\r
25#include <Protocol/PciRootBridgeIo.h>\r
c4add6b6 26#include <Protocol/VirtioDevice.h>\r
8d620322
LE
27#include <Guid/EventGroup.h>\r
28#include <Guid/RootBridgesConnectedEventGroup.h>\r
4ff31c08 29#include <Guid/SerialPortLibVendor.h>\r
8d620322
LE
30\r
31#include "PlatformBm.h"\r
32\r
33#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
34\r
35\r
36#pragma pack (1)\r
37typedef struct {\r
38 VENDOR_DEVICE_PATH SerialDxe;\r
39 UART_DEVICE_PATH Uart;\r
40 VENDOR_DEFINED_DEVICE_PATH TermType;\r
41 EFI_DEVICE_PATH_PROTOCOL End;\r
42} PLATFORM_SERIAL_CONSOLE;\r
43#pragma pack ()\r
44\r
8d620322
LE
45STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
46 //\r
47 // VENDOR_DEVICE_PATH SerialDxe\r
48 //\r
49 {\r
50 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
4ff31c08 51 EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
8d620322
LE
52 },\r
53\r
54 //\r
55 // UART_DEVICE_PATH Uart\r
56 //\r
57 {\r
58 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
59 0, // Reserved\r
60 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
61 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits\r
62 FixedPcdGet8 (PcdUartDefaultParity), // Parity\r
63 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits\r
64 },\r
65\r
66 //\r
67 // VENDOR_DEFINED_DEVICE_PATH TermType\r
68 //\r
69 {\r
70 {\r
71 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,\r
72 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)\r
73 }\r
74 //\r
75 // Guid to be filled in dynamically\r
76 //\r
77 },\r
78\r
79 //\r
80 // EFI_DEVICE_PATH_PROTOCOL End\r
81 //\r
82 {\r
83 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
84 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
85 }\r
86};\r
87\r
88\r
89#pragma pack (1)\r
90typedef struct {\r
91 USB_CLASS_DEVICE_PATH Keyboard;\r
92 EFI_DEVICE_PATH_PROTOCOL End;\r
93} PLATFORM_USB_KEYBOARD;\r
94#pragma pack ()\r
95\r
96STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
97 //\r
98 // USB_CLASS_DEVICE_PATH Keyboard\r
99 //\r
100 {\r
101 {\r
102 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,\r
103 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)\r
104 },\r
105 0xFFFF, // VendorId: any\r
106 0xFFFF, // ProductId: any\r
107 3, // DeviceClass: HID\r
108 1, // DeviceSubClass: boot\r
109 1 // DeviceProtocol: keyboard\r
110 },\r
111\r
112 //\r
113 // EFI_DEVICE_PATH_PROTOCOL End\r
114 //\r
115 {\r
116 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
117 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
118 }\r
119};\r
120\r
8d620322
LE
121\r
122/**\r
123 Check if the handle satisfies a particular condition.\r
124\r
125 @param[in] Handle The handle to check.\r
126 @param[in] ReportText A caller-allocated string passed in for reporting\r
127 purposes. It must never be NULL.\r
128\r
129 @retval TRUE The condition is satisfied.\r
130 @retval FALSE Otherwise. This includes the case when the condition could not\r
131 be fully evaluated due to an error.\r
132**/\r
133typedef\r
134BOOLEAN\r
135(EFIAPI *FILTER_FUNCTION) (\r
136 IN EFI_HANDLE Handle,\r
137 IN CONST CHAR16 *ReportText\r
138 );\r
139\r
140\r
141/**\r
142 Process a handle.\r
143\r
144 @param[in] Handle The handle to process.\r
145 @param[in] ReportText A caller-allocated string passed in for reporting\r
146 purposes. It must never be NULL.\r
147**/\r
148typedef\r
149VOID\r
150(EFIAPI *CALLBACK_FUNCTION) (\r
151 IN EFI_HANDLE Handle,\r
152 IN CONST CHAR16 *ReportText\r
153 );\r
154\r
155/**\r
156 Locate all handles that carry the specified protocol, filter them with a\r
157 callback function, and pass each handle that passes the filter to another\r
158 callback.\r
159\r
160 @param[in] ProtocolGuid The protocol to look for.\r
161\r
162 @param[in] Filter The filter function to pass each handle to. If this\r
163 parameter is NULL, then all handles are processed.\r
164\r
165 @param[in] Process The callback function to pass each handle to that\r
166 clears the filter.\r
167**/\r
168STATIC\r
169VOID\r
170FilterAndProcess (\r
171 IN EFI_GUID *ProtocolGuid,\r
172 IN FILTER_FUNCTION Filter OPTIONAL,\r
173 IN CALLBACK_FUNCTION Process\r
174 )\r
175{\r
176 EFI_STATUS Status;\r
177 EFI_HANDLE *Handles;\r
178 UINTN NoHandles;\r
179 UINTN Idx;\r
180\r
181 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
182 NULL /* SearchKey */, &NoHandles, &Handles);\r
183 if (EFI_ERROR (Status)) {\r
184 //\r
185 // This is not an error, just an informative condition.\r
186 //\r
187 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
188 Status));\r
189 return;\r
190 }\r
191\r
192 ASSERT (NoHandles > 0);\r
193 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
194 CHAR16 *DevicePathText;\r
195 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
196\r
197 //\r
198 // The ConvertDevicePathToText() function handles NULL input transparently.\r
199 //\r
200 DevicePathText = ConvertDevicePathToText (\r
201 DevicePathFromHandle (Handles[Idx]),\r
202 FALSE, // DisplayOnly\r
203 FALSE // AllowShortcuts\r
204 );\r
205 if (DevicePathText == NULL) {\r
206 DevicePathText = Fallback;\r
207 }\r
208\r
209 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
210 Process (Handles[Idx], DevicePathText);\r
211 }\r
212\r
213 if (DevicePathText != Fallback) {\r
214 FreePool (DevicePathText);\r
215 }\r
216 }\r
217 gBS->FreePool (Handles);\r
218}\r
219\r
220\r
221/**\r
222 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
223**/\r
224STATIC\r
225BOOLEAN\r
226EFIAPI\r
227IsPciDisplay (\r
228 IN EFI_HANDLE Handle,\r
229 IN CONST CHAR16 *ReportText\r
230 )\r
231{\r
232 EFI_STATUS Status;\r
233 EFI_PCI_IO_PROTOCOL *PciIo;\r
234 PCI_TYPE00 Pci;\r
235\r
236 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
237 (VOID**)&PciIo);\r
238 if (EFI_ERROR (Status)) {\r
239 //\r
240 // This is not an error worth reporting.\r
241 //\r
242 return FALSE;\r
243 }\r
244\r
245 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
246 sizeof Pci / sizeof (UINT32), &Pci);\r
247 if (EFI_ERROR (Status)) {\r
248 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
249 return FALSE;\r
250 }\r
251\r
252 return IS_PCI_DISPLAY (&Pci);\r
253}\r
254\r
255\r
c4add6b6
LE
256/**\r
257 This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
258 the VIRTIO_DEVICE_PROTOCOL level.\r
259**/\r
260STATIC\r
261BOOLEAN\r
262EFIAPI\r
263IsVirtioRng (\r
264 IN EFI_HANDLE Handle,\r
265 IN CONST CHAR16 *ReportText\r
266 )\r
267{\r
268 EFI_STATUS Status;\r
269 VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
270\r
271 Status = gBS->HandleProtocol (Handle, &gVirtioDeviceProtocolGuid,\r
272 (VOID**)&VirtIo);\r
273 if (EFI_ERROR (Status)) {\r
274 return FALSE;\r
275 }\r
276 return (BOOLEAN)(VirtIo->SubSystemDeviceId ==\r
277 VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);\r
278}\r
279\r
280\r
281/**\r
282 This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
283 the EFI_PCI_IO_PROTOCOL level.\r
284**/\r
285STATIC\r
286BOOLEAN\r
287EFIAPI\r
288IsVirtioPciRng (\r
289 IN EFI_HANDLE Handle,\r
290 IN CONST CHAR16 *ReportText\r
291 )\r
292{\r
293 EFI_STATUS Status;\r
294 EFI_PCI_IO_PROTOCOL *PciIo;\r
295 UINT16 VendorId;\r
296 UINT16 DeviceId;\r
297 UINT8 RevisionId;\r
298 BOOLEAN Virtio10;\r
299 UINT16 SubsystemId;\r
300\r
301 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
302 (VOID**)&PciIo);\r
303 if (EFI_ERROR (Status)) {\r
304 return FALSE;\r
305 }\r
306\r
307 //\r
308 // Read and check VendorId.\r
309 //\r
310 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,\r
311 1, &VendorId);\r
312 if (EFI_ERROR (Status)) {\r
313 goto PciError;\r
314 }\r
315 if (VendorId != VIRTIO_VENDOR_ID) {\r
316 return FALSE;\r
317 }\r
318\r
319 //\r
320 // Read DeviceId and RevisionId.\r
321 //\r
322 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,\r
323 1, &DeviceId);\r
324 if (EFI_ERROR (Status)) {\r
325 goto PciError;\r
326 }\r
327 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,\r
328 1, &RevisionId);\r
329 if (EFI_ERROR (Status)) {\r
330 goto PciError;\r
331 }\r
332\r
333 //\r
334 // From DeviceId and RevisionId, determine whether the device is a\r
335 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
336 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
337 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
338 // only be sanity-checked, and SubsystemId will decide.\r
339 //\r
340 if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&\r
341 RevisionId >= 0x01) {\r
342 Virtio10 = TRUE;\r
343 } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {\r
344 Virtio10 = FALSE;\r
345 } else {\r
346 return FALSE;\r
347 }\r
348\r
349 //\r
350 // Read and check SubsystemId as dictated by Virtio10.\r
351 //\r
352 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,\r
353 PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);\r
354 if (EFI_ERROR (Status)) {\r
355 goto PciError;\r
356 }\r
357 if (Virtio10 && SubsystemId >= 0x40) {\r
358 return TRUE;\r
359 }\r
360 if (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {\r
361 return TRUE;\r
362 }\r
363 return FALSE;\r
364\r
365PciError:\r
366 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
367 return FALSE;\r
368}\r
369\r
370\r
8d620322
LE
371/**\r
372 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
373 the matching driver to produce all first-level child handles.\r
374**/\r
375STATIC\r
376VOID\r
377EFIAPI\r
378Connect (\r
379 IN EFI_HANDLE Handle,\r
380 IN CONST CHAR16 *ReportText\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384\r
385 Status = gBS->ConnectController (\r
386 Handle, // ControllerHandle\r
387 NULL, // DriverImageHandle\r
388 NULL, // RemainingDevicePath -- produce all children\r
389 FALSE // Recursive\r
390 );\r
391 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
392 __FUNCTION__, ReportText, Status));\r
393}\r
394\r
395\r
396/**\r
397 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
398 handle, and adds it to ConOut and ErrOut.\r
399**/\r
400STATIC\r
401VOID\r
402EFIAPI\r
403AddOutput (\r
404 IN EFI_HANDLE Handle,\r
405 IN CONST CHAR16 *ReportText\r
406 )\r
407{\r
408 EFI_STATUS Status;\r
409 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
410\r
411 DevicePath = DevicePathFromHandle (Handle);\r
412 if (DevicePath == NULL) {\r
413 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
414 __FUNCTION__, ReportText, Handle));\r
415 return;\r
416 }\r
417\r
b7a33aff 418 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
8d620322
LE
419 if (EFI_ERROR (Status)) {\r
420 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
421 ReportText, Status));\r
422 return;\r
423 }\r
424\r
b7a33aff 425 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
8d620322
LE
426 if (EFI_ERROR (Status)) {\r
427 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
428 ReportText, Status));\r
429 return;\r
430 }\r
431\r
432 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
433 ReportText));\r
434}\r
435\r
793b3b5b
LE
436STATIC\r
437VOID\r
438PlatformRegisterFvBootOption (\r
439 EFI_GUID *FileGuid,\r
440 CHAR16 *Description,\r
441 UINT32 Attributes\r
442 )\r
443{\r
444 EFI_STATUS Status;\r
445 INTN OptionIndex;\r
446 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
447 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
448 UINTN BootOptionCount;\r
449 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
450 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
451 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
452\r
453 Status = gBS->HandleProtocol (\r
454 gImageHandle,\r
455 &gEfiLoadedImageProtocolGuid,\r
456 (VOID **) &LoadedImage\r
457 );\r
458 ASSERT_EFI_ERROR (Status);\r
459\r
460 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
461 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
462 ASSERT (DevicePath != NULL);\r
463 DevicePath = AppendDevicePathNode (\r
464 DevicePath,\r
465 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
466 );\r
467 ASSERT (DevicePath != NULL);\r
468\r
469 Status = EfiBootManagerInitializeLoadOption (\r
470 &NewOption,\r
471 LoadOptionNumberUnassigned,\r
472 LoadOptionTypeBoot,\r
473 Attributes,\r
474 Description,\r
475 DevicePath,\r
476 NULL,\r
477 0\r
478 );\r
479 ASSERT_EFI_ERROR (Status);\r
480 FreePool (DevicePath);\r
481\r
482 BootOptions = EfiBootManagerGetLoadOptions (\r
483 &BootOptionCount, LoadOptionTypeBoot\r
484 );\r
485\r
486 OptionIndex = EfiBootManagerFindLoadOption (\r
487 &NewOption, BootOptions, BootOptionCount\r
488 );\r
489\r
490 if (OptionIndex == -1) {\r
491 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
492 ASSERT_EFI_ERROR (Status);\r
493 }\r
494 EfiBootManagerFreeLoadOption (&NewOption);\r
495 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
496}\r
497\r
498\r
0e2c6c55
LE
499/**\r
500 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options\r
501 whose device paths do not resolve exactly to an FvFile in the system.\r
502\r
503 This removes any boot options that point to binaries built into the firmware\r
504 and have become stale due to any of the following:\r
505 - FvMain's base address or size changed (historical),\r
506 - FvMain's FvNameGuid changed,\r
507 - the FILE_GUID of the pointed-to binary changed,\r
508 - the referenced binary is no longer built into the firmware.\r
509\r
510 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only\r
511 avoids exact duplicates.\r
512**/\r
513STATIC\r
514VOID\r
515RemoveStaleFvFileOptions (\r
516 VOID\r
517 )\r
518{\r
519 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
520 UINTN BootOptionCount;\r
521 UINTN Index;\r
522\r
523 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,\r
524 LoadOptionTypeBoot);\r
525\r
526 for (Index = 0; Index < BootOptionCount; ++Index) {\r
527 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;\r
528 EFI_STATUS Status;\r
529 EFI_HANDLE FvHandle;\r
530\r
531 //\r
532 // If the device path starts with neither MemoryMapped(...) nor Fv(...),\r
533 // then keep the boot option.\r
534 //\r
535 Node1 = BootOptions[Index].FilePath;\r
536 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&\r
537 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&\r
538 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&\r
539 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {\r
540 continue;\r
541 }\r
542\r
543 //\r
544 // If the second device path node is not FvFile(...), then keep the boot\r
545 // option.\r
546 //\r
547 Node2 = NextDevicePathNode (Node1);\r
548 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||\r
549 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {\r
550 continue;\r
551 }\r
552\r
553 //\r
554 // Locate the Firmware Volume2 protocol instance that is denoted by the\r
555 // boot option. If this lookup fails (i.e., the boot option references a\r
556 // firmware volume that doesn't exist), then we'll proceed to delete the\r
557 // boot option.\r
558 //\r
559 SearchNode = Node1;\r
560 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,\r
561 &SearchNode, &FvHandle);\r
562\r
563 if (!EFI_ERROR (Status)) {\r
564 //\r
565 // The firmware volume was found; now let's see if it contains the FvFile\r
566 // identified by GUID.\r
567 //\r
568 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;\r
569 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;\r
570 UINTN BufferSize;\r
571 EFI_FV_FILETYPE FoundType;\r
572 EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
573 UINT32 AuthenticationStatus;\r
574\r
575 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,\r
576 (VOID **)&FvProtocol);\r
577 ASSERT_EFI_ERROR (Status);\r
578\r
579 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;\r
580 //\r
581 // Buffer==NULL means we request metadata only: BufferSize, FoundType,\r
582 // FileAttributes.\r
583 //\r
584 Status = FvProtocol->ReadFile (\r
585 FvProtocol,\r
586 &FvFileNode->FvFileName, // NameGuid\r
587 NULL, // Buffer\r
588 &BufferSize,\r
589 &FoundType,\r
590 &FileAttributes,\r
591 &AuthenticationStatus\r
592 );\r
593 if (!EFI_ERROR (Status)) {\r
594 //\r
595 // The FvFile was found. Keep the boot option.\r
596 //\r
597 continue;\r
598 }\r
599 }\r
600\r
601 //\r
602 // Delete the boot option.\r
603 //\r
604 Status = EfiBootManagerDeleteLoadOptionVariable (\r
605 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
606 DEBUG_CODE (\r
607 CHAR16 *DevicePathString;\r
608\r
609 DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,\r
610 FALSE, FALSE);\r
611 DEBUG ((\r
612 EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,\r
613 "%a: removing stale Boot#%04x %s: %r\n",\r
614 __FUNCTION__,\r
615 (UINT32)BootOptions[Index].OptionNumber,\r
616 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,\r
617 Status\r
618 ));\r
619 if (DevicePathString != NULL) {\r
620 FreePool (DevicePathString);\r
621 }\r
622 );\r
623 }\r
624\r
625 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
626}\r
627\r
628\r
793b3b5b
LE
629STATIC\r
630VOID\r
631PlatformRegisterOptionsAndKeys (\r
632 VOID\r
633 )\r
634{\r
635 EFI_STATUS Status;\r
636 EFI_INPUT_KEY Enter;\r
637 EFI_INPUT_KEY F2;\r
638 EFI_INPUT_KEY Esc;\r
639 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
640\r
641 //\r
642 // Register ENTER as CONTINUE key\r
643 //\r
644 Enter.ScanCode = SCAN_NULL;\r
645 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
646 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
647 ASSERT_EFI_ERROR (Status);\r
648\r
649 //\r
650 // Map F2 and ESC to Boot Manager Menu\r
651 //\r
652 F2.ScanCode = SCAN_F2;\r
653 F2.UnicodeChar = CHAR_NULL;\r
654 Esc.ScanCode = SCAN_ESC;\r
655 Esc.UnicodeChar = CHAR_NULL;\r
656 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
657 ASSERT_EFI_ERROR (Status);\r
658 Status = EfiBootManagerAddKeyOptionVariable (\r
659 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
660 );\r
661 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
662 Status = EfiBootManagerAddKeyOptionVariable (\r
663 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
664 );\r
665 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
793b3b5b
LE
666}\r
667\r
8d620322 668\r
e2a193b7
LE
669//\r
670// BDS Platform Functions\r
671//\r
8d620322 672/**\r
e2a193b7
LE
673 Do the platform init, can be customized by OEM/IBV\r
674 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
675 > Update console variable: 1. include hot-plug devices;\r
676 > 2. Clear ConIn and add SOL for AMT\r
677 > Register new Driver#### or Boot####\r
678 > Register new Key####: e.g.: F12\r
679 > Signal ReadyToLock event\r
680 > Authentication action: 1. connect Auth devices;\r
681 > 2. Identify auto logon user.\r
8d620322
LE
682**/\r
683VOID\r
684EFIAPI\r
e2a193b7 685PlatformBootManagerBeforeConsole (\r
e3fe3c0f 686 VOID\r
8d620322
LE
687 )\r
688{\r
2ea0fee9
LE
689 RETURN_STATUS PcdStatus;\r
690\r
e2a193b7
LE
691 //\r
692 // Signal EndOfDxe PI Event\r
693 //\r
694 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
695\r
34cd9402
RN
696 //\r
697 // Dispatch deferred images after EndOfDxe event.\r
698 //\r
699 EfiBootManagerDispatchDeferredImages ();\r
700\r
8d620322
LE
701 //\r
702 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
703 // non-recursively. This will produce a number of child handles with PciIo on\r
704 // them.\r
705 //\r
706 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
707\r
708 //\r
709 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
710 //\r
711 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
712\r
713 //\r
714 // Find all display class PCI devices (using the handles from the previous\r
715 // step), and connect them non-recursively. This should produce a number of\r
716 // child handles with GOPs on them.\r
717 //\r
718 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
719\r
720 //\r
721 // Now add the device path of all handles with GOP on them to ConOut and\r
722 // ErrOut.\r
723 //\r
724 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
725\r
726 //\r
727 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
728 //\r
b7a33aff 729 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322
LE
730 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
731\r
732 //\r
733 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
734 //\r
735 CopyGuid (&mSerialConsole.TermType.Guid,\r
736 PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
b7a33aff 737 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322 738 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 739 EfiBootManagerUpdateConsoleVariable (ConOut,\r
8d620322 740 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 741 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
8d620322 742 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
48799ab2
LE
743\r
744 //\r
745 // Set the front page timeout from the QEMU configuration.\r
746 //\r
2ea0fee9
LE
747 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,\r
748 GetFrontPageTimeoutFromQemu ());\r
749 ASSERT_RETURN_ERROR (PcdStatus);\r
793b3b5b
LE
750\r
751 //\r
752 // Register platform-specific boot options and keyboard shortcuts.\r
753 //\r
754 PlatformRegisterOptionsAndKeys ();\r
c4add6b6
LE
755\r
756 //\r
757 // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO\r
758 // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.\r
759 //\r
760 FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);\r
761\r
762 //\r
763 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
764 // instances on Virtio PCI RNG devices.\r
765 //\r
766 FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);\r
e2a193b7 767}\r
8d620322 768\r
e2a193b7
LE
769/**\r
770 Do the platform specific action after the console is ready\r
771 Possible things that can be done in PlatformBootManagerAfterConsole:\r
772 > Console post action:\r
7a908953 773 > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
e2a193b7
LE
774 > Signal console ready platform customized event\r
775 > Run diagnostics like memory testing\r
776 > Connect certain devices\r
7a908953 777 > Dispatch additional option roms\r
e2a193b7
LE
778 > Special boot: e.g.: USB boot, enter UI\r
779**/\r
780VOID\r
781EFIAPI\r
782PlatformBootManagerAfterConsole (\r
783 VOID\r
784 )\r
785{\r
ff1d0fbf
LE
786 RETURN_STATUS Status;\r
787\r
8d620322
LE
788 //\r
789 // Show the splash screen.\r
790 //\r
738f70ae 791 BootLogoEnableLogo ();\r
8d620322 792\r
34711bf1
LE
793 //\r
794 // Process QEMU's -kernel command line option. The kernel booted this way\r
795 // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we\r
796 // connected any and all PCI root bridges, and then signaled the ACPI\r
797 // platform driver.\r
798 //\r
799 TryRunningQemuKernel ();\r
800\r
8d620322 801 //\r
ff1d0fbf 802 // Connect the purported boot devices.\r
8d620322 803 //\r
ff1d0fbf
LE
804 Status = ConnectDevicesFromQemu ();\r
805 if (RETURN_ERROR (Status)) {\r
806 //\r
807 // Connect the rest of the devices.\r
808 //\r
809 EfiBootManagerConnectAll ();\r
810 }\r
8d620322 811\r
8d620322 812 //\r
afa456de
LE
813 // Enumerate all possible boot options, then filter and reorder them based on\r
814 // the QEMU configuration.\r
8d620322 815 //\r
afa456de 816 EfiBootManagerRefreshAllBootOption ();\r
efadd415
LE
817\r
818 //\r
819 // Register UEFI Shell\r
820 //\r
821 PlatformRegisterFvBootOption (\r
c81c2c0f 822 &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
efadd415
LE
823 );\r
824\r
0e2c6c55 825 RemoveStaleFvFileOptions ();\r
2542feea 826 SetBootOrderFromQemu ();\r
1797f32e
LE
827\r
828 PlatformBmPrintScRegisterHandler ();\r
8d620322
LE
829}\r
830\r
e3fe3c0f
LE
831/**\r
832 This function is called each second during the boot manager waits the\r
833 timeout.\r
834\r
835 @param TimeoutRemain The remaining timeout.\r
836**/\r
837VOID\r
838EFIAPI\r
839PlatformBootManagerWaitCallback (\r
840 UINT16 TimeoutRemain\r
841 )\r
842{\r
be266b10
LE
843 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
844 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
23ab8df0 845 UINT16 TimeoutInitial;\r
be266b10 846\r
23ab8df0
PB
847 TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);\r
848\r
849 //\r
850 // If PcdPlatformBootTimeOut is set to zero, then we consider\r
851 // that no progress update should be enacted.\r
852 //\r
853 if (TimeoutInitial == 0) {\r
854 return;\r
855 }\r
be266b10
LE
856\r
857 Black.Raw = 0x00000000;\r
858 White.Raw = 0x00FFFFFF;\r
859\r
860 BootLogoUpdateProgress (\r
861 White.Pixel,\r
862 Black.Pixel,\r
863 L"Start boot option",\r
864 White.Pixel,\r
23ab8df0 865 (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,\r
be266b10
LE
866 0\r
867 );\r
e3fe3c0f 868}\r
8d1b281a
RN
869\r
870/**\r
871 The function is called when no boot option could be launched,\r
872 including platform recovery options and options pointing to applications\r
873 built into firmware volumes.\r
874\r
875 If this function returns, BDS attempts to enter an infinite loop.\r
876**/\r
877VOID\r
878EFIAPI\r
879PlatformBootManagerUnableToBoot (\r
880 VOID\r
881 )\r
882{\r
883 EFI_STATUS Status;\r
884 EFI_INPUT_KEY Key;\r
885 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
886 UINTN Index;\r
887\r
888 //\r
889 // BootManagerMenu doesn't contain the correct information when return status\r
890 // is EFI_NOT_FOUND.\r
891 //\r
892 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
893 if (EFI_ERROR (Status)) {\r
894 return;\r
895 }\r
896 //\r
897 // Normally BdsDxe does not print anything to the system console, but this is\r
898 // a last resort -- the end-user will likely not see any DEBUG messages\r
899 // logged in this situation.\r
900 //\r
901 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
902 // here to see if it makes sense to request and wait for a keypress.\r
903 //\r
904 if (gST->ConIn != NULL) {\r
905 AsciiPrint (\r
906 "%a: No bootable option or device was found.\n"\r
907 "%a: Press any key to enter the Boot Manager Menu.\n",\r
908 gEfiCallerBaseName,\r
909 gEfiCallerBaseName\r
910 );\r
911 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
912 ASSERT_EFI_ERROR (Status);\r
913 ASSERT (Index == 0);\r
914\r
915 //\r
916 // Drain any queued keys.\r
917 //\r
918 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
919 //\r
920 // just throw away Key\r
921 //\r
922 }\r
923 }\r
924\r
925 for (;;) {\r
926 EfiBootManagerBoot (&BootManagerMenu);\r
927 }\r
928}\r