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