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