Home | History | Annotate | Download | only in PlatformBootManagerLib
      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   Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
      8 
      9   This program and the accompanying materials are licensed and made available
     10   under the terms and conditions of the BSD License which accompanies this
     11   distribution. The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     15   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #include <IndustryStandard/Pci22.h>
     20 #include <Library/DevicePathLib.h>
     21 #include <Library/PcdLib.h>
     22 #include <Library/UefiBootManagerLib.h>
     23 #include <Library/UefiLib.h>
     24 #include <Protocol/DevicePath.h>
     25 #include <Protocol/GraphicsOutput.h>
     26 #include <Protocol/LoadedImage.h>
     27 #include <Protocol/PciIo.h>
     28 #include <Protocol/PciRootBridgeIo.h>
     29 #include <Guid/EventGroup.h>
     30 #include <Guid/TtyTerm.h>
     31 
     32 #include "PlatformBm.h"
     33 
     34 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
     35 
     36 
     37 #pragma pack (1)
     38 typedef struct {
     39   VENDOR_DEVICE_PATH         SerialDxe;
     40   UART_DEVICE_PATH           Uart;
     41   VENDOR_DEFINED_DEVICE_PATH TermType;
     42   EFI_DEVICE_PATH_PROTOCOL   End;
     43 } PLATFORM_SERIAL_CONSOLE;
     44 #pragma pack ()
     45 
     46 #define SERIAL_DXE_FILE_GUID { \
     47           0xD3987D4B, 0x971A, 0x435F, \
     48           { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
     49           }
     50 
     51 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
     52   //
     53   // VENDOR_DEVICE_PATH SerialDxe
     54   //
     55   {
     56     { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
     57     SERIAL_DXE_FILE_GUID
     58   },
     59 
     60   //
     61   // UART_DEVICE_PATH Uart
     62   //
     63   {
     64     { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
     65     0,                                      // Reserved
     66     FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
     67     FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits
     68     FixedPcdGet8 (PcdUartDefaultParity),    // Parity
     69     FixedPcdGet8 (PcdUartDefaultStopBits)   // StopBits
     70   },
     71 
     72   //
     73   // VENDOR_DEFINED_DEVICE_PATH TermType
     74   //
     75   {
     76     {
     77       MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
     78       DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
     79     }
     80     //
     81     // Guid to be filled in dynamically
     82     //
     83   },
     84 
     85   //
     86   // EFI_DEVICE_PATH_PROTOCOL End
     87   //
     88   {
     89     END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
     90     DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
     91   }
     92 };
     93 
     94 
     95 #pragma pack (1)
     96 typedef struct {
     97   USB_CLASS_DEVICE_PATH    Keyboard;
     98   EFI_DEVICE_PATH_PROTOCOL End;
     99 } PLATFORM_USB_KEYBOARD;
    100 #pragma pack ()
    101 
    102 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
    103   //
    104   // USB_CLASS_DEVICE_PATH Keyboard
    105   //
    106   {
    107     {
    108       MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
    109       DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
    110     },
    111     0xFFFF, // VendorId: any
    112     0xFFFF, // ProductId: any
    113     3,      // DeviceClass: HID
    114     1,      // DeviceSubClass: boot
    115     1       // DeviceProtocol: keyboard
    116   },
    117 
    118   //
    119   // EFI_DEVICE_PATH_PROTOCOL End
    120   //
    121   {
    122     END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
    123     DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
    124   }
    125 };
    126 
    127 
    128 /**
    129   Check if the handle satisfies a particular condition.
    130 
    131   @param[in] Handle      The handle to check.
    132   @param[in] ReportText  A caller-allocated string passed in for reporting
    133                          purposes. It must never be NULL.
    134 
    135   @retval TRUE   The condition is satisfied.
    136   @retval FALSE  Otherwise. This includes the case when the condition could not
    137                  be fully evaluated due to an error.
    138 **/
    139 typedef
    140 BOOLEAN
    141 (EFIAPI *FILTER_FUNCTION) (
    142   IN EFI_HANDLE   Handle,
    143   IN CONST CHAR16 *ReportText
    144   );
    145 
    146 
    147 /**
    148   Process a handle.
    149 
    150   @param[in] Handle      The handle to process.
    151   @param[in] ReportText  A caller-allocated string passed in for reporting
    152                          purposes. It must never be NULL.
    153 **/
    154 typedef
    155 VOID
    156 (EFIAPI *CALLBACK_FUNCTION)  (
    157   IN EFI_HANDLE   Handle,
    158   IN CONST CHAR16 *ReportText
    159   );
    160 
    161 /**
    162   Locate all handles that carry the specified protocol, filter them with a
    163   callback function, and pass each handle that passes the filter to another
    164   callback.
    165 
    166   @param[in] ProtocolGuid  The protocol to look for.
    167 
    168   @param[in] Filter        The filter function to pass each handle to. If this
    169                            parameter is NULL, then all handles are processed.
    170 
    171   @param[in] Process       The callback function to pass each handle to that
    172                            clears the filter.
    173 **/
    174 STATIC
    175 VOID
    176 FilterAndProcess (
    177   IN EFI_GUID          *ProtocolGuid,
    178   IN FILTER_FUNCTION   Filter         OPTIONAL,
    179   IN CALLBACK_FUNCTION Process
    180   )
    181 {
    182   EFI_STATUS Status;
    183   EFI_HANDLE *Handles;
    184   UINTN      NoHandles;
    185   UINTN      Idx;
    186 
    187   Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
    188                   NULL /* SearchKey */, &NoHandles, &Handles);
    189   if (EFI_ERROR (Status)) {
    190     //
    191     // This is not an error, just an informative condition.
    192     //
    193     DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
    194       Status));
    195     return;
    196   }
    197 
    198   ASSERT (NoHandles > 0);
    199   for (Idx = 0; Idx < NoHandles; ++Idx) {
    200     CHAR16        *DevicePathText;
    201     STATIC CHAR16 Fallback[] = L"<device path unavailable>";
    202 
    203     //
    204     // The ConvertDevicePathToText() function handles NULL input transparently.
    205     //
    206     DevicePathText = ConvertDevicePathToText (
    207                        DevicePathFromHandle (Handles[Idx]),
    208                        FALSE, // DisplayOnly
    209                        FALSE  // AllowShortcuts
    210                        );
    211     if (DevicePathText == NULL) {
    212       DevicePathText = Fallback;
    213     }
    214 
    215     if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
    216       Process (Handles[Idx], DevicePathText);
    217     }
    218 
    219     if (DevicePathText != Fallback) {
    220       FreePool (DevicePathText);
    221     }
    222   }
    223   gBS->FreePool (Handles);
    224 }
    225 
    226 
    227 /**
    228   This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
    229 **/
    230 STATIC
    231 BOOLEAN
    232 EFIAPI
    233 IsPciDisplay (
    234   IN EFI_HANDLE   Handle,
    235   IN CONST CHAR16 *ReportText
    236   )
    237 {
    238   EFI_STATUS          Status;
    239   EFI_PCI_IO_PROTOCOL *PciIo;
    240   PCI_TYPE00          Pci;
    241 
    242   Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
    243                   (VOID**)&PciIo);
    244   if (EFI_ERROR (Status)) {
    245     //
    246     // This is not an error worth reporting.
    247     //
    248     return FALSE;
    249   }
    250 
    251   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
    252                         sizeof Pci / sizeof (UINT32), &Pci);
    253   if (EFI_ERROR (Status)) {
    254     DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
    255     return FALSE;
    256   }
    257 
    258   return IS_PCI_DISPLAY (&Pci);
    259 }
    260 
    261 
    262 /**
    263   This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
    264   the matching driver to produce all first-level child handles.
    265 **/
    266 STATIC
    267 VOID
    268 EFIAPI
    269 Connect (
    270   IN EFI_HANDLE   Handle,
    271   IN CONST CHAR16 *ReportText
    272   )
    273 {
    274   EFI_STATUS Status;
    275 
    276   Status = gBS->ConnectController (
    277                   Handle, // ControllerHandle
    278                   NULL,   // DriverImageHandle
    279                   NULL,   // RemainingDevicePath -- produce all children
    280                   FALSE   // Recursive
    281                   );
    282   DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
    283     __FUNCTION__, ReportText, Status));
    284 }
    285 
    286 
    287 /**
    288   This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
    289   handle, and adds it to ConOut and ErrOut.
    290 **/
    291 STATIC
    292 VOID
    293 EFIAPI
    294 AddOutput (
    295   IN EFI_HANDLE   Handle,
    296   IN CONST CHAR16 *ReportText
    297   )
    298 {
    299   EFI_STATUS               Status;
    300   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
    301 
    302   DevicePath = DevicePathFromHandle (Handle);
    303   if (DevicePath == NULL) {
    304     DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
    305       __FUNCTION__, ReportText, Handle));
    306     return;
    307   }
    308 
    309   Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
    310   if (EFI_ERROR (Status)) {
    311     DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
    312       ReportText, Status));
    313     return;
    314   }
    315 
    316   Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
    317   if (EFI_ERROR (Status)) {
    318     DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
    319       ReportText, Status));
    320     return;
    321   }
    322 
    323   DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
    324     ReportText));
    325 }
    326 
    327 STATIC
    328 VOID
    329 PlatformRegisterFvBootOption (
    330   EFI_GUID                         *FileGuid,
    331   CHAR16                           *Description,
    332   UINT32                           Attributes
    333   )
    334 {
    335   EFI_STATUS                        Status;
    336   INTN                              OptionIndex;
    337   EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
    338   EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
    339   UINTN                             BootOptionCount;
    340   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
    341   EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
    342   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
    343 
    344   Status = gBS->HandleProtocol (
    345                   gImageHandle,
    346                   &gEfiLoadedImageProtocolGuid,
    347                   (VOID **) &LoadedImage
    348                   );
    349   ASSERT_EFI_ERROR (Status);
    350 
    351   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
    352   DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
    353   ASSERT (DevicePath != NULL);
    354   DevicePath = AppendDevicePathNode (
    355                  DevicePath,
    356                  (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
    357                  );
    358   ASSERT (DevicePath != NULL);
    359 
    360   Status = EfiBootManagerInitializeLoadOption (
    361              &NewOption,
    362              LoadOptionNumberUnassigned,
    363              LoadOptionTypeBoot,
    364              Attributes,
    365              Description,
    366              DevicePath,
    367              NULL,
    368              0
    369              );
    370   ASSERT_EFI_ERROR (Status);
    371   FreePool (DevicePath);
    372 
    373   BootOptions = EfiBootManagerGetLoadOptions (
    374                   &BootOptionCount, LoadOptionTypeBoot
    375                   );
    376 
    377   OptionIndex = EfiBootManagerFindLoadOption (
    378                   &NewOption, BootOptions, BootOptionCount
    379                   );
    380 
    381   if (OptionIndex == -1) {
    382     Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
    383     ASSERT_EFI_ERROR (Status);
    384   }
    385   EfiBootManagerFreeLoadOption (&NewOption);
    386   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    387 }
    388 
    389 
    390 STATIC
    391 VOID
    392 PlatformRegisterOptionsAndKeys (
    393   VOID
    394   )
    395 {
    396   EFI_STATUS                   Status;
    397   EFI_INPUT_KEY                Enter;
    398   EFI_INPUT_KEY                F2;
    399   EFI_INPUT_KEY                Esc;
    400   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
    401 
    402   //
    403   // Register ENTER as CONTINUE key
    404   //
    405   Enter.ScanCode    = SCAN_NULL;
    406   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
    407   Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
    408   ASSERT_EFI_ERROR (Status);
    409 
    410   //
    411   // Map F2 and ESC to Boot Manager Menu
    412   //
    413   F2.ScanCode     = SCAN_F2;
    414   F2.UnicodeChar  = CHAR_NULL;
    415   Esc.ScanCode    = SCAN_ESC;
    416   Esc.UnicodeChar = CHAR_NULL;
    417   Status = EfiBootManagerGetBootManagerMenu (&BootOption);
    418   ASSERT_EFI_ERROR (Status);
    419   Status = EfiBootManagerAddKeyOptionVariable (
    420              NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
    421              );
    422   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
    423   Status = EfiBootManagerAddKeyOptionVariable (
    424              NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
    425              );
    426   ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
    427 }
    428 
    429 
    430 //
    431 // BDS Platform Functions
    432 //
    433 /**
    434   Do the platform init, can be customized by OEM/IBV
    435   Possible things that can be done in PlatformBootManagerBeforeConsole:
    436   > Update console variable: 1. include hot-plug devices;
    437   >                          2. Clear ConIn and add SOL for AMT
    438   > Register new Driver#### or Boot####
    439   > Register new Key####: e.g.: F12
    440   > Signal ReadyToLock event
    441   > Authentication action: 1. connect Auth devices;
    442   >                        2. Identify auto logon user.
    443 **/
    444 VOID
    445 EFIAPI
    446 PlatformBootManagerBeforeConsole (
    447   VOID
    448   )
    449 {
    450   //
    451   // Signal EndOfDxe PI Event
    452   //
    453   EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
    454 
    455   //
    456   // Locate the PCI root bridges and make the PCI bus driver connect each,
    457   // non-recursively. This will produce a number of child handles with PciIo on
    458   // them.
    459   //
    460   FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
    461 
    462   //
    463   // Find all display class PCI devices (using the handles from the previous
    464   // step), and connect them non-recursively. This should produce a number of
    465   // child handles with GOPs on them.
    466   //
    467   FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
    468 
    469   //
    470   // Now add the device path of all handles with GOP on them to ConOut and
    471   // ErrOut.
    472   //
    473   FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
    474 
    475   //
    476   // Add the hardcoded short-form USB keyboard device path to ConIn.
    477   //
    478   EfiBootManagerUpdateConsoleVariable (ConIn,
    479     (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
    480 
    481   //
    482   // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
    483   //
    484   ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);
    485   CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
    486 
    487   EfiBootManagerUpdateConsoleVariable (ConIn,
    488     (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
    489   EfiBootManagerUpdateConsoleVariable (ConOut,
    490     (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
    491   EfiBootManagerUpdateConsoleVariable (ErrOut,
    492     (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
    493 
    494   //
    495   // Register platform-specific boot options and keyboard shortcuts.
    496   //
    497   PlatformRegisterOptionsAndKeys ();
    498 }
    499 
    500 /**
    501   Do the platform specific action after the console is ready
    502   Possible things that can be done in PlatformBootManagerAfterConsole:
    503   > Console post action:
    504     > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
    505     > Signal console ready platform customized event
    506   > Run diagnostics like memory testing
    507   > Connect certain devices
    508   > Dispatch aditional option roms
    509   > Special boot: e.g.: USB boot, enter UI
    510 **/
    511 VOID
    512 EFIAPI
    513 PlatformBootManagerAfterConsole (
    514   VOID
    515   )
    516 {
    517   Print (L"Press ESCAPE for boot options ");
    518 
    519   //
    520   // Show the splash screen.
    521   //
    522   EnableQuietBoot (PcdGetPtr (PcdLogoFile));
    523 
    524   //
    525   // Connect the rest of the devices.
    526   //
    527   EfiBootManagerConnectAll ();
    528 
    529   //
    530   // Enumerate all possible boot options.
    531   //
    532   EfiBootManagerRefreshAllBootOption ();
    533 
    534   //
    535   // Register UEFI Shell
    536   //
    537   PlatformRegisterFvBootOption (
    538     PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE
    539     );
    540 }
    541 
    542 /**
    543   This function is called each second during the boot manager waits the
    544   timeout.
    545 
    546   @param TimeoutRemain  The remaining timeout.
    547 **/
    548 VOID
    549 EFIAPI
    550 PlatformBootManagerWaitCallback (
    551   UINT16          TimeoutRemain
    552   )
    553 {
    554   Print (L".");
    555 }
    556