efi_loader: add firmware management protocol for raw image

In this commit, a very simple firmware management protocol driver
is implemented. It will take a binary image in a capsule file and
apply the data using dfu backend storage drivers via dfu_write_by_alt()
interface.

So "dfu_alt_info" variable should be properly set to specify a device
and location to be updated. Please read README.dfu.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
This commit is contained in:
AKASHI Takahiro 2020-11-17 09:28:00 +09:00 committed by Heinrich Schuchardt
parent f27c201485
commit bb7e71d33c
6 changed files with 213 additions and 72 deletions

View file

@ -1857,6 +1857,10 @@ struct efi_signature_list {
EFI_GUID(0xae13ff2d, 0x9ad4, 0x4e25, 0x9a, 0xc8, \ EFI_GUID(0xae13ff2d, 0x9ad4, 0x4e25, 0x9a, 0xc8, \
0x6d, 0x80, 0xb3, 0xb2, 0x21, 0x47) 0x6d, 0x80, 0xb3, 0xb2, 0x21, 0x47)
#define EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID \
EFI_GUID(0xe2bb9c06, 0x70e9, 0x4b14, 0x97, 0xa3, \
0x5a, 0x79, 0x13, 0x17, 0x6e, 0x3f)
#define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x0000000000000001 #define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x0000000000000001
#define IMAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002 #define IMAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
#define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004 #define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004

View file

@ -817,6 +817,7 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
u16 *efi_create_indexed_name(u16 *buffer, const char *name, unsigned int index); u16 *efi_create_indexed_name(u16 *buffer, const char *name, unsigned int index);
extern const struct efi_firmware_management_protocol efi_fmp_fit; extern const struct efi_firmware_management_protocol efi_fmp_fit;
extern const struct efi_firmware_management_protocol efi_fmp_raw;
/* Capsule update */ /* Capsule update */
efi_status_t EFIAPI efi_update_capsule( efi_status_t EFIAPI efi_update_capsule(

View file

@ -127,6 +127,10 @@ config EFI_CAPSULE_ON_DISK_EARLY
executed as part of U-Boot initialisation so that they will executed as part of U-Boot initialisation so that they will
surely take place whatever is set to distro_bootcmd. surely take place whatever is set to distro_bootcmd.
config EFI_CAPSULE_FIRMWARE
bool
default n
config EFI_CAPSULE_FIRMWARE_MANAGEMENT config EFI_CAPSULE_FIRMWARE_MANAGEMENT
bool "Capsule: Firmware Management Protocol" bool "Capsule: Firmware Management Protocol"
depends on EFI_HAVE_CAPSULE_SUPPORT depends on EFI_HAVE_CAPSULE_SUPPORT
@ -141,11 +145,23 @@ config EFI_CAPSULE_FIRMWARE_FIT
depends on FIT depends on FIT
select UPDATE_FIT select UPDATE_FIT
select DFU select DFU
select EFI_CAPSULE_FIRMWARE
default n default n
help help
Select this option if you want to enable firmware management protocol Select this option if you want to enable firmware management protocol
driver for FIT image driver for FIT image
config EFI_CAPSULE_FIRMWARE_RAW
bool "FMP driver for raw image"
depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
select DFU
select DFU_WRITE_ALT
select EFI_CAPSULE_FIRMWARE
default n
help
Select this option if you want to enable firmware management protocol
driver for raw image
config EFI_DEVICE_PATH_TO_TEXT config EFI_DEVICE_PATH_TO_TEXT
bool "Device path to text protocol" bool "Device path to text protocol"
default y default y

View file

@ -24,7 +24,7 @@ obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-y += efi_bootmgr.o obj-y += efi_bootmgr.o
obj-y += efi_boottime.o obj-y += efi_boottime.o
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE_FIT) += efi_firmware.o obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
obj-y += efi_console.o obj-y += efi_console.o
obj-y += efi_device_path.o obj-y += efi_device_path.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o

View file

@ -807,6 +807,14 @@ efi_status_t __weak arch_efi_load_capsule_drivers(void)
&efi_fmp_fit, NULL)); &efi_fmp_fit, NULL));
} }
if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_RAW)) {
handle = NULL;
ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
&efi_root,
&efi_guid_firmware_management_protocol,
&efi_fmp_raw, NULL));
}
return ret; return ret;
} }

View file

@ -13,16 +13,66 @@
#include <image.h> #include <image.h>
#include <linux/list.h> #include <linux/list.h>
/* /* Place holder; not supported */
* This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update static
* method with existing FIT image format, and handles efi_status_t EFIAPI efi_firmware_get_image_unsupported(
* - multiple regions of firmware via DFU struct efi_firmware_management_protocol *this,
* but doesn't support u8 image_index,
* - versioning of firmware image void *image,
* - package information efi_uintn_t *image_size)
*/ {
const efi_guid_t efi_firmware_image_type_uboot_fit = EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
return EFI_EXIT(EFI_UNSUPPORTED);
}
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_check_image_unsupported(
struct efi_firmware_management_protocol *this,
u8 image_index,
const void *image,
efi_uintn_t *image_size,
u32 *image_updatable)
{
EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
image_updatable);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
struct efi_firmware_management_protocol *this,
u32 *package_version,
u16 **package_version_name,
u32 *package_version_name_maxlen,
u64 *attributes_supported,
u64 *attributes_setting)
{
EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
package_version_name, package_version_name_maxlen,
attributes_supported, attributes_setting);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
struct efi_firmware_management_protocol *this,
const void *image,
efi_uintn_t *image_size,
const void *vendor_code,
u32 package_version,
const u16 *package_version_name)
{
EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
package_version, package_version_name);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/** /**
* efi_get_dfu_info - return information about the current firmware image * efi_get_dfu_info - return information about the current firmware image
@ -129,6 +179,18 @@ static efi_status_t efi_get_dfu_info(
return EFI_SUCCESS; return EFI_SUCCESS;
} }
#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
/*
* This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
* method with existing FIT image format, and handles
* - multiple regions of firmware via DFU
* but doesn't support
* - versioning of firmware image
* - package information
*/
const efi_guid_t efi_firmware_image_type_uboot_fit =
EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
/** /**
* efi_firmware_fit_get_image_info - return information about the current * efi_firmware_fit_get_image_info - return information about the current
* firmware image * firmware image
@ -182,19 +244,6 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info(
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_get_image_unsupported(
struct efi_firmware_management_protocol *this,
u8 image_index,
void *image,
efi_uintn_t *image_size)
{
EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/** /**
* efi_firmware_fit_set_image - update the firmware image * efi_firmware_fit_set_image - update the firmware image
* @this: Protocol instance * @this: Protocol instance
@ -233,54 +282,6 @@ efi_status_t EFIAPI efi_firmware_fit_set_image(
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
} }
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_check_image_unsupported(
struct efi_firmware_management_protocol *this,
u8 image_index,
const void *image,
efi_uintn_t *image_size,
u32 *image_updatable)
{
EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
image_updatable);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
struct efi_firmware_management_protocol *this,
u32 *package_version,
u16 **package_version_name,
u32 *package_version_name_maxlen,
u64 *attributes_supported,
u64 *attributes_setting)
{
EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
package_version_name, package_version_name_maxlen,
attributes_supported, attributes_setting);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
struct efi_firmware_management_protocol *this,
const void *image,
efi_uintn_t *image_size,
const void *vendor_code,
u32 package_version,
const u16 *package_version_name)
{
EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
package_version, package_version_name);
return EFI_EXIT(EFI_UNSUPPORTED);
}
const struct efi_firmware_management_protocol efi_fmp_fit = { const struct efi_firmware_management_protocol efi_fmp_fit = {
.get_image_info = efi_firmware_fit_get_image_info, .get_image_info = efi_firmware_fit_get_image_info,
.get_image = efi_firmware_get_image_unsupported, .get_image = efi_firmware_get_image_unsupported,
@ -289,3 +290,114 @@ const struct efi_firmware_management_protocol efi_fmp_fit = {
.get_package_info = efi_firmware_get_package_info_unsupported, .get_package_info = efi_firmware_get_package_info_unsupported,
.set_package_info = efi_firmware_set_package_info_unsupported, .set_package_info = efi_firmware_set_package_info_unsupported,
}; };
#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
/*
* This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
* method with raw data.
*/
const efi_guid_t efi_firmware_image_type_uboot_raw =
EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
/**
* efi_firmware_raw_get_image_info - return information about the current
firmware image
* @this: Protocol instance
* @image_info_size: Size of @image_info
* @image_info: Image information
* @descriptor_version: Pointer to version number
* @descriptor_count: Pointer to number of descriptors
* @descriptor_size: Pointer to descriptor size
* package_version: Package version
* package_version_name: Package version's name
*
* Return information bout the current firmware image in @image_info.
* @image_info will consist of a number of descriptors.
* Each descriptor will be created based on "dfu_alt_info" variable.
*
* Return status code
*/
static
efi_status_t EFIAPI efi_firmware_raw_get_image_info(
struct efi_firmware_management_protocol *this,
efi_uintn_t *image_info_size,
struct efi_firmware_image_descriptor *image_info,
u32 *descriptor_version,
u8 *descriptor_count,
efi_uintn_t *descriptor_size,
u32 *package_version,
u16 **package_version_name)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
image_info_size, image_info,
descriptor_version, descriptor_count, descriptor_size,
package_version, package_version_name);
if (!image_info_size)
return EFI_EXIT(EFI_INVALID_PARAMETER);
if (*image_info_size &&
(!image_info || !descriptor_version || !descriptor_count ||
!descriptor_size || !package_version || !package_version_name))
return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = efi_get_dfu_info(image_info_size, image_info,
descriptor_version, descriptor_count,
descriptor_size,
package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
return EFI_EXIT(ret);
}
/**
* efi_firmware_raw_set_image - update the firmware image
* @this: Protocol instance
* @image_index: Image index number
* @image: New image
* @image_size: Size of new image
* @vendor_code: Vendor-specific update policy
* @progress: Function to report the progress of update
* @abort_reason: Pointer to string of abort reason
*
* Update the firmware to new image, using dfu. The new image should
* be a single raw image.
* @vendor_code, @progress and @abort_reason are not supported.
*
* Return: status code
*/
static
efi_status_t EFIAPI efi_firmware_raw_set_image(
struct efi_firmware_management_protocol *this,
u8 image_index,
const void *image,
efi_uintn_t image_size,
const void *vendor_code,
efi_status_t (*progress)(efi_uintn_t completion),
u16 **abort_reason)
{
EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
image_size, vendor_code, progress, abort_reason);
if (!image)
return EFI_EXIT(EFI_INVALID_PARAMETER);
if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
NULL, NULL))
return EFI_EXIT(EFI_DEVICE_ERROR);
return EFI_EXIT(EFI_SUCCESS);
}
const struct efi_firmware_management_protocol efi_fmp_raw = {
.get_image_info = efi_firmware_raw_get_image_info,
.get_image = efi_firmware_get_image_unsupported,
.set_image = efi_firmware_raw_set_image,
.check_image = efi_firmware_check_image_unsupported,
.get_package_info = efi_firmware_get_package_info_unsupported,
.set_package_info = efi_firmware_set_package_info_unsupported,
};
#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */