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