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