Home | History | Annotate | Download | only in BootManagerPolicyDxe
      1 /** @file
      2   This module produces Boot Manager Policy protocol.
      3 
      4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Uefi.h>
     16 #include <Protocol/BootManagerPolicy.h>
     17 #include <Protocol/ManagedNetwork.h>
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 #include <Library/UefiLib.h>
     21 #include <Library/DevicePathLib.h>
     22 #include <Library/DebugLib.h>
     23 #include <Library/UefiBootServicesTableLib.h>
     24 #include <Library/UefiRuntimeServicesTableLib.h>
     25 #include <Library/UefiBootManagerLib.h>
     26 
     27 CHAR16 mNetworkDeviceList[] = L"_NDL";
     28 
     29 /**
     30   Connect all the system drivers to controllers and create the network device list in NV storage.
     31 
     32   @retval EFI_SUCCESS      Network devices are connected.
     33   @retval EFI_DEVICE_ERROR No network device is connected.
     34 
     35 **/
     36 EFI_STATUS
     37 ConnectAllAndCreateNetworkDeviceList (
     38   VOID
     39   )
     40 {
     41   EFI_STATUS                      Status;
     42   EFI_HANDLE                      *Handles;
     43   UINTN                           HandleCount;
     44   EFI_DEVICE_PATH_PROTOCOL        *SingleDevice;
     45   EFI_DEVICE_PATH_PROTOCOL        *Devices;
     46   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
     47 
     48   EfiBootManagerConnectAll ();
     49 
     50   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiManagedNetworkServiceBindingProtocolGuid, NULL, &HandleCount, &Handles);
     51   if (EFI_ERROR (Status)) {
     52     Handles = NULL;
     53     HandleCount = 0;
     54   }
     55 
     56   Devices = NULL;
     57   while (HandleCount-- != 0) {
     58     Status = gBS->HandleProtocol (Handles[HandleCount], &gEfiDevicePathProtocolGuid, (VOID **) &SingleDevice);
     59     if (EFI_ERROR (Status) || (SingleDevice == NULL)) {
     60       continue;
     61     }
     62     TempDevicePath = Devices;
     63     Devices = AppendDevicePathInstance (Devices, SingleDevice);
     64     if (TempDevicePath != NULL) {
     65       FreePool (TempDevicePath);
     66     }
     67   }
     68 
     69   if (Devices != NULL) {
     70     Status = gRT->SetVariable (
     71                     mNetworkDeviceList,
     72                     &gEfiCallerIdGuid,
     73                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
     74                     GetDevicePathSize (Devices),
     75                     Devices
     76                     );
     77     //
     78     // Fails to save the network device list to NV storage is not a fatal error.
     79     // Only impact is performance.
     80     //
     81     FreePool (Devices);
     82   }
     83 
     84   return (Devices == NULL) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
     85 }
     86 
     87 /**
     88   Connect the network devices.
     89 
     90   @retval EFI_SUCCESS      At least one network device was connected.
     91   @retval EFI_DEVICE_ERROR Network devices were not connected due to an error.
     92 **/
     93 EFI_STATUS
     94 ConnectNetwork (
     95   VOID
     96   )
     97 {
     98   EFI_STATUS                    Status;
     99   BOOLEAN                       OneConnected;
    100   EFI_DEVICE_PATH_PROTOCOL      *Devices;
    101   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
    102   EFI_DEVICE_PATH_PROTOCOL      *SingleDevice;
    103   UINTN                         Size;
    104 
    105   OneConnected = FALSE;
    106   GetVariable2 (mNetworkDeviceList, &gEfiCallerIdGuid, (VOID **) &Devices, NULL);
    107   TempDevicePath = Devices;
    108   while (TempDevicePath != NULL) {
    109     SingleDevice = GetNextDevicePathInstance (&TempDevicePath, &Size);
    110     Status = EfiBootManagerConnectDevicePath (SingleDevice, NULL);
    111     if (!EFI_ERROR (Status)) {
    112       OneConnected = TRUE;
    113     }
    114     FreePool (SingleDevice);
    115   }
    116   if (Devices != NULL) {
    117     FreePool (Devices);
    118   }
    119 
    120   if (OneConnected) {
    121     return EFI_SUCCESS;
    122   } else {
    123     //
    124     // Cached network devices list doesn't exist or is NOT valid.
    125     //
    126     return ConnectAllAndCreateNetworkDeviceList ();
    127   }
    128 }
    129 
    130 /**
    131   Connect a device path following the platforms EFI Boot Manager policy.
    132 
    133   The ConnectDevicePath() function allows the caller to connect a DevicePath using the
    134   same policy as the EFI Boot Manger.
    135 
    136   @param[in] This       A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
    137   @param[in] DevicePath Points to the start of the EFI device path to connect.
    138                         If DevicePath is NULL then all the controllers in the
    139                         system will be connected using the platforms EFI Boot
    140                         Manager policy.
    141   @param[in] Recursive  If TRUE, then ConnectController() is called recursively
    142                         until the entire tree of controllers below the
    143                         controller specified by DevicePath have been created.
    144                         If FALSE, then the tree of controllers is only expanded
    145                         one level. If DevicePath is NULL then Recursive is ignored.
    146 
    147   @retval EFI_SUCCESS            The DevicePath was connected.
    148   @retval EFI_NOT_FOUND          The DevicePath was not found.
    149   @retval EFI_NOT_FOUND          No driver was connected to DevicePath.
    150   @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
    151                                  drivers on the DevicePath.
    152   @retval EFI_UNSUPPORTED        The current TPL is not TPL_APPLICATION.
    153 **/
    154 EFI_STATUS
    155 EFIAPI
    156 BootManagerPolicyConnectDevicePath (
    157   IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
    158   IN EFI_DEVICE_PATH                  *DevicePath,
    159   IN BOOLEAN                          Recursive
    160   )
    161 {
    162   EFI_STATUS                          Status;
    163   EFI_HANDLE                          Controller;
    164 
    165   if (EfiGetCurrentTpl () != TPL_APPLICATION) {
    166     return EFI_UNSUPPORTED;
    167   }
    168 
    169   if (DevicePath == NULL) {
    170     EfiBootManagerConnectAll ();
    171     return EFI_SUCCESS;
    172   }
    173 
    174   if (Recursive) {
    175     Status = EfiBootManagerConnectDevicePath (DevicePath, NULL);
    176   } else {
    177     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Controller);
    178     if (!EFI_ERROR (Status)) {
    179       Status = gBS->ConnectController (Controller, NULL, DevicePath, FALSE);
    180     }
    181   }
    182   return Status;
    183 }
    184 /**
    185   Connect a class of devices using the platform Boot Manager policy.
    186 
    187   The ConnectDeviceClass() function allows the caller to request that the Boot
    188   Manager connect a class of devices.
    189 
    190   If Class is EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID then the Boot Manager will
    191   use platform policy to connect consoles. Some platforms may restrict the
    192   number of consoles connected as they attempt to fast boot, and calling
    193   ConnectDeviceClass() with a Class value of EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID
    194   must connect the set of consoles that follow the Boot Manager platform policy,
    195   and the EFI_SIMPLE_TEXT_INPUT_PROTOCOL, EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL, and
    196   the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL are produced on the connected handles.
    197   The Boot Manager may restrict which consoles get connect due to platform policy,
    198   for example a security policy may require that a given console is not connected.
    199 
    200   If Class is EFI_BOOT_MANAGER_POLICY_NETWORK_GUID then the Boot Manager will
    201   connect the protocols the platforms supports for UEFI general purpose network
    202   applications on one or more handles. If more than one network controller is
    203   available a platform will connect, one, many, or all of the networks based
    204   on platform policy. Connecting UEFI networking protocols, like EFI_DHCP4_PROTOCOL,
    205   does not establish connections on the network. The UEFI general purpose network
    206   application that called ConnectDeviceClass() may need to use the published
    207   protocols to establish the network connection. The Boot Manager can optionally
    208   have a policy to establish a network connection.
    209 
    210   If Class is EFI_BOOT_MANAGER_POLICY_CONNECT_ALL_GUID then the Boot Manager
    211   will connect all UEFI drivers using the UEFI Boot Service
    212   EFI_BOOT_SERVICES.ConnectController(). If the Boot Manager has policy
    213   associated with connect all UEFI drivers this policy will be used.
    214 
    215   A platform can also define platform specific Class values as a properly generated
    216   EFI_GUID would never conflict with this specification.
    217 
    218   @param[in] This  A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
    219   @param[in] Class A pointer to an EFI_GUID that represents a class of devices
    220                    that will be connected using the Boot Mangers platform policy.
    221 
    222   @retval EFI_SUCCESS      At least one devices of the Class was connected.
    223   @retval EFI_DEVICE_ERROR Devices were not connected due to an error.
    224   @retval EFI_NOT_FOUND    The Class is not supported by the platform.
    225   @retval EFI_UNSUPPORTED  The current TPL is not TPL_APPLICATION.
    226 **/
    227 EFI_STATUS
    228 EFIAPI
    229 BootManagerPolicyConnectDeviceClass (
    230   IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
    231   IN EFI_GUID                         *Class
    232   )
    233 {
    234   if (EfiGetCurrentTpl () != TPL_APPLICATION) {
    235     return EFI_UNSUPPORTED;
    236   }
    237 
    238   if (CompareGuid (Class, &gEfiBootManagerPolicyConnectAllGuid)) {
    239     ConnectAllAndCreateNetworkDeviceList ();
    240     return EFI_SUCCESS;
    241   }
    242 
    243   if (CompareGuid (Class, &gEfiBootManagerPolicyConsoleGuid)) {
    244     return EfiBootManagerConnectAllDefaultConsoles ();
    245   }
    246 
    247   if (CompareGuid (Class, &gEfiBootManagerPolicyNetworkGuid)) {
    248     return ConnectNetwork ();
    249   }
    250 
    251   return EFI_NOT_FOUND;
    252 }
    253 
    254 EFI_BOOT_MANAGER_POLICY_PROTOCOL  mBootManagerPolicy = {
    255   EFI_BOOT_MANAGER_POLICY_PROTOCOL_REVISION,
    256   BootManagerPolicyConnectDevicePath,
    257   BootManagerPolicyConnectDeviceClass
    258 };
    259 
    260 /**
    261   Install Boot Manager Policy Protocol.
    262 
    263   @param ImageHandle    The image handle.
    264   @param SystemTable    The system table.
    265 
    266   @retval  EFI_SUCEESS  The Boot Manager Policy protocol is successfully installed.
    267   @retval  Other        Return status from gBS->InstallMultipleProtocolInterfaces().
    268 
    269 **/
    270 EFI_STATUS
    271 EFIAPI
    272 BootManagerPolicyInitialize (
    273   IN EFI_HANDLE                            ImageHandle,
    274   IN EFI_SYSTEM_TABLE                      *SystemTable
    275   )
    276 {
    277   EFI_HANDLE                               Handle;
    278 
    279   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiBootManagerPolicyProtocolGuid);
    280 
    281   Handle = NULL;
    282   return gBS->InstallMultipleProtocolInterfaces (
    283                 &Handle,
    284                 &gEfiBootManagerPolicyProtocolGuid, &mBootManagerPolicy,
    285                 NULL
    286                 );
    287 }
    288