summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c
blob: ff45e4f8e996ad2dad434e05d3ee60f914594564 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/** @file
  This module produces Boot Manager Policy protocol.

Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Uefi.h>
#include <Protocol/BootManagerPolicy.h>
#include <Protocol/ManagedNetwork.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/DevicePathLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiBootManagerLib.h>

CHAR16 mNetworkDeviceList[] = L"_NDL";

/**
  Connect all the system drivers to controllers and create the network device list in NV storage.

  @retval EFI_SUCCESS      Network devices are connected.
  @retval EFI_DEVICE_ERROR No network device is connected.

**/
EFI_STATUS
ConnectAllAndCreateNetworkDeviceList (
  VOID
  )
{
  EFI_STATUS                      Status;
  EFI_HANDLE                      *Handles;
  UINTN                           HandleCount;
  EFI_DEVICE_PATH_PROTOCOL        *SingleDevice;
  EFI_DEVICE_PATH_PROTOCOL        *Devices;
  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;

  EfiBootManagerConnectAll ();

  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiManagedNetworkServiceBindingProtocolGuid, NULL, &HandleCount, &Handles);
  if (EFI_ERROR (Status)) {
    Handles = NULL;
    HandleCount = 0;
  }

  Devices = NULL;
  while (HandleCount-- != 0) {
    Status = gBS->HandleProtocol (Handles[HandleCount], &gEfiDevicePathProtocolGuid, (VOID **) &SingleDevice);
    if (EFI_ERROR (Status) || (SingleDevice == NULL)) {
      continue;
    }
    TempDevicePath = Devices;
    Devices = AppendDevicePathInstance (Devices, SingleDevice);
    if (TempDevicePath != NULL) {
      FreePool (TempDevicePath);
    }
  }

  if (Devices != NULL) {
    Status = gRT->SetVariable (
                    mNetworkDeviceList,
                    &gEfiCallerIdGuid,
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
                    GetDevicePathSize (Devices),
                    Devices
                    );
    //
    // Fails to save the network device list to NV storage is not a fatal error.
    // Only impact is performance.
    //
    FreePool (Devices);
  }

  return (Devices == NULL) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
}

/**
  Connect the network devices.

  @retval EFI_SUCCESS      At least one network device was connected.
  @retval EFI_DEVICE_ERROR Network devices were not connected due to an error.
**/
EFI_STATUS
ConnectNetwork (
  VOID
  )
{
  EFI_STATUS                    Status;
  BOOLEAN                       OneConnected;
  EFI_DEVICE_PATH_PROTOCOL      *Devices;
  EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
  EFI_DEVICE_PATH_PROTOCOL      *SingleDevice;
  UINTN                         Size;

  OneConnected = FALSE;
  GetVariable2 (mNetworkDeviceList, &gEfiCallerIdGuid, (VOID **) &Devices, NULL);
  TempDevicePath = Devices;
  while (TempDevicePath != NULL) {
    SingleDevice = GetNextDevicePathInstance (&TempDevicePath, &Size);
    Status = EfiBootManagerConnectDevicePath (SingleDevice, NULL);
    if (!EFI_ERROR (Status)) {
      OneConnected = TRUE;
    }
    FreePool (SingleDevice);
  }
  if (Devices != NULL) {
    FreePool (Devices);
  }

  if (OneConnected) {
    return EFI_SUCCESS;
  } else {
    //
    // Cached network devices list doesn't exist or is NOT valid.
    //
    return ConnectAllAndCreateNetworkDeviceList ();
  }
}

/**
  Connect a device path following the platforms EFI Boot Manager policy.

  The ConnectDevicePath() function allows the caller to connect a DevicePath using the
  same policy as the EFI Boot Manger.

  @param[in] This       A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
  @param[in] DevicePath Points to the start of the EFI device path to connect.
                        If DevicePath is NULL then all the controllers in the
                        system will be connected using the platforms EFI Boot
                        Manager policy.
  @param[in] Recursive  If TRUE, then ConnectController() is called recursively
                        until the entire tree of controllers below the
                        controller specified by DevicePath have been created.
                        If FALSE, then the tree of controllers is only expanded
                        one level. If DevicePath is NULL then Recursive is ignored.

  @retval EFI_SUCCESS            The DevicePath was connected.
  @retval EFI_NOT_FOUND          The DevicePath was not found.
  @retval EFI_NOT_FOUND          No driver was connected to DevicePath.
  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
                                 drivers on the DevicePath.
  @retval EFI_UNSUPPORTED        The current TPL is not TPL_APPLICATION.
**/
EFI_STATUS
EFIAPI
BootManagerPolicyConnectDevicePath (
  IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
  IN EFI_DEVICE_PATH                  *DevicePath,
  IN BOOLEAN                          Recursive
  )
{
  EFI_STATUS                          Status;
  EFI_HANDLE                          Controller;

  if (EfiGetCurrentTpl () != TPL_APPLICATION) {
    return EFI_UNSUPPORTED;
  }

  if (DevicePath == NULL) {
    EfiBootManagerConnectAll ();
    return EFI_SUCCESS;
  }

  if (Recursive) {
    Status = EfiBootManagerConnectDevicePath (DevicePath, NULL);
  } else {
    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Controller);
    if (!EFI_ERROR (Status)) {
      Status = gBS->ConnectController (Controller, NULL, DevicePath, FALSE);
    }
  }
  return Status;
}
/**
  Connect a class of devices using the platform Boot Manager policy.

  The ConnectDeviceClass() function allows the caller to request that the Boot
  Manager connect a class of devices.

  If Class is EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID then the Boot Manager will
  use platform policy to connect consoles. Some platforms may restrict the
  number of consoles connected as they attempt to fast boot, and calling
  ConnectDeviceClass() with a Class value of EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID
  must connect the set of consoles that follow the Boot Manager platform policy,
  and the EFI_SIMPLE_TEXT_INPUT_PROTOCOL, EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL, and
  the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL are produced on the connected handles.
  The Boot Manager may restrict which consoles get connect due to platform policy,
  for example a security policy may require that a given console is not connected.

  If Class is EFI_BOOT_MANAGER_POLICY_NETWORK_GUID then the Boot Manager will
  connect the protocols the platforms supports for UEFI general purpose network
  applications on one or more handles. If more than one network controller is
  available a platform will connect, one, many, or all of the networks based
  on platform policy. Connecting UEFI networking protocols, like EFI_DHCP4_PROTOCOL,
  does not establish connections on the network. The UEFI general purpose network
  application that called ConnectDeviceClass() may need to use the published
  protocols to establish the network connection. The Boot Manager can optionally
  have a policy to establish a network connection.

  If Class is EFI_BOOT_MANAGER_POLICY_CONNECT_ALL_GUID then the Boot Manager
  will connect all UEFI drivers using the UEFI Boot Service
  EFI_BOOT_SERVICES.ConnectController(). If the Boot Manager has policy
  associated with connect all UEFI drivers this policy will be used.

  A platform can also define platform specific Class values as a properly generated
  EFI_GUID would never conflict with this specification.

  @param[in] This  A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
  @param[in] Class A pointer to an EFI_GUID that represents a class of devices
                   that will be connected using the Boot Mangers platform policy.

  @retval EFI_SUCCESS      At least one devices of the Class was connected.
  @retval EFI_DEVICE_ERROR Devices were not connected due to an error.
  @retval EFI_NOT_FOUND    The Class is not supported by the platform.
  @retval EFI_UNSUPPORTED  The current TPL is not TPL_APPLICATION.
**/
EFI_STATUS
EFIAPI
BootManagerPolicyConnectDeviceClass (
  IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
  IN EFI_GUID                         *Class
  )
{
  if (EfiGetCurrentTpl () != TPL_APPLICATION) {
    return EFI_UNSUPPORTED;
  }

  if (CompareGuid (Class, &gEfiBootManagerPolicyConnectAllGuid)) {
    ConnectAllAndCreateNetworkDeviceList ();
    return EFI_SUCCESS;
  }

  if (CompareGuid (Class, &gEfiBootManagerPolicyConsoleGuid)) {
    return EfiBootManagerConnectAllDefaultConsoles ();
  }

  if (CompareGuid (Class, &gEfiBootManagerPolicyNetworkGuid)) {
    return ConnectNetwork ();
  }

  return EFI_NOT_FOUND;
}

EFI_BOOT_MANAGER_POLICY_PROTOCOL  mBootManagerPolicy = {
  EFI_BOOT_MANAGER_POLICY_PROTOCOL_REVISION,
  BootManagerPolicyConnectDevicePath,
  BootManagerPolicyConnectDeviceClass
};

/**
  Install Boot Manager Policy Protocol.

  @param ImageHandle    The image handle.
  @param SystemTable    The system table.

  @retval  EFI_SUCEESS  The Boot Manager Policy protocol is successfully installed.
  @retval  Other        Return status from gBS->InstallMultipleProtocolInterfaces().

**/
EFI_STATUS
EFIAPI
BootManagerPolicyInitialize (
  IN EFI_HANDLE                            ImageHandle,
  IN EFI_SYSTEM_TABLE                      *SystemTable
  )
{
  EFI_HANDLE                               Handle;

  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiBootManagerPolicyProtocolGuid);

  Handle = NULL;
  return gBS->InstallMultipleProtocolInterfaces (
                &Handle,
                &gEfiBootManagerPolicyProtocolGuid, &mBootManagerPolicy,
                NULL
                );
}