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