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