audk/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c

288 lines
10 KiB
C

/** @file
This module produces Boot Manager Policy protocol.
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#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
);
}