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