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