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