mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-27 23:20:26 +09:00
efi_loader: capsule: support firmware update
A capsule tagged with the guid, EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID, is handled as a firmware update object. What efi_update_capsule() basically does is to load any firmware management protocol (or fmp) drivers contained in a capsule, find out an appropriate fmp driver and then invoke its set_image() interface against each binary in a capsule. In this commit, however, loading drivers is not supported. The result of applying a capsule is set to be stored in "CapsuleXXXX" variable, but its implementation is deferred to a fmp driver. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
This commit is contained in:
parent
ed9349c697
commit
8d99026f06
@ -217,6 +217,9 @@ enum efi_reset_type {
|
|||||||
#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
|
#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
|
||||||
#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000
|
#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000
|
||||||
|
|
||||||
|
#define CAPSULE_SUPPORT_AUTHENTICATION 0x0000000000000001
|
||||||
|
#define CAPSULE_SUPPORT_DEPENDENCY 0x0000000000000002
|
||||||
|
|
||||||
#define EFI_CAPSULE_REPORT_GUID \
|
#define EFI_CAPSULE_REPORT_GUID \
|
||||||
EFI_GUID(0x39b68c46, 0xf7fb, 0x441b, 0xb6, 0xec, \
|
EFI_GUID(0x39b68c46, 0xf7fb, 0x441b, 0xb6, 0xec, \
|
||||||
0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3)
|
0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3)
|
||||||
@ -225,6 +228,10 @@ enum efi_reset_type {
|
|||||||
EFI_GUID(0xde9f0ec, 0x88b6, 0x428f, 0x97, 0x7a, \
|
EFI_GUID(0xde9f0ec, 0x88b6, 0x428f, 0x97, 0x7a, \
|
||||||
0x25, 0x8f, 0x1d, 0xe, 0x5e, 0x72)
|
0x25, 0x8f, 0x1d, 0xe, 0x5e, 0x72)
|
||||||
|
|
||||||
|
#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID \
|
||||||
|
EFI_GUID(0x6dcbd5ed, 0xe82d, 0x4c44, 0xbd, 0xa1, \
|
||||||
|
0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a)
|
||||||
|
|
||||||
struct efi_capsule_header {
|
struct efi_capsule_header {
|
||||||
efi_guid_t capsule_guid;
|
efi_guid_t capsule_guid;
|
||||||
u32 header_size;
|
u32 header_size;
|
||||||
@ -253,6 +260,33 @@ struct efi_memory_range_capsule {
|
|||||||
struct efi_memory_range memory_ranges[];
|
struct efi_memory_range memory_ranges[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct efi_firmware_management_capsule_header {
|
||||||
|
u32 version;
|
||||||
|
u16 embedded_driver_count;
|
||||||
|
u16 payload_item_count;
|
||||||
|
u64 item_offset_list[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct efi_firmware_management_capsule_image_header {
|
||||||
|
u32 version;
|
||||||
|
efi_guid_t update_image_type_id;
|
||||||
|
u8 update_image_index;
|
||||||
|
u8 reserved[3];
|
||||||
|
u32 update_image_size;
|
||||||
|
u32 update_vendor_code_size;
|
||||||
|
u64 update_hardware_instance;
|
||||||
|
u64 image_capsule_support;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct efi_capsule_result_variable_fmp {
|
||||||
|
u16 version;
|
||||||
|
u8 payload_index;
|
||||||
|
u8 update_image_index;
|
||||||
|
efi_guid_t update_image_type_id;
|
||||||
|
// u16 capsule_file_name[];
|
||||||
|
// u16 capsule_target[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define EFI_RT_SUPPORTED_GET_TIME 0x0001
|
#define EFI_RT_SUPPORTED_GET_TIME 0x0001
|
||||||
#define EFI_RT_SUPPORTED_SET_TIME 0x0002
|
#define EFI_RT_SUPPORTED_SET_TIME 0x0002
|
||||||
#define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004
|
#define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004
|
||||||
@ -1812,4 +1846,99 @@ struct efi_signature_list {
|
|||||||
/* struct efi_signature_data signatures[...][signature_size]; */
|
/* struct efi_signature_data signatures[...][signature_size]; */
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Firmware management protocol
|
||||||
|
*/
|
||||||
|
#define EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID \
|
||||||
|
EFI_GUID(0x86c77a67, 0x0b97, 0x4633, 0xa1, 0x87, \
|
||||||
|
0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7)
|
||||||
|
|
||||||
|
#define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x0000000000000001
|
||||||
|
#define IMAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
|
||||||
|
#define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
|
||||||
|
#define IMAGE_ATTRIBUTE_IN_USE 0x0000000000000008
|
||||||
|
#define IMAGE_ATTRIBUTE_UEFI_IMAGE 0x0000000000000010
|
||||||
|
#define IMAGE_ATTRIBUTE_DEPENDENCY 0x0000000000000020
|
||||||
|
|
||||||
|
#define IMAGE_COMPATIBILITY_CHECK_SUPPORTED 0x0000000000000001
|
||||||
|
|
||||||
|
#define IMAGE_UPDATABLE_VALID 0x0000000000000001
|
||||||
|
#define IMAGE_UPDATABLE_INVALID 0x0000000000000002
|
||||||
|
#define IMAGE_UPDATABLE_INVALID_TYPE 0x0000000000000004
|
||||||
|
#define IMAGE_UPDATABLE_INVALID_OLLD 0x0000000000000008
|
||||||
|
#define IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE 0x0000000000000010
|
||||||
|
|
||||||
|
#define PACKAGE_ATTRIBUTE_VERSION_UPDATABLE 0x0000000000000001
|
||||||
|
#define PACKAGE_ATTRIBUTE_RESET_REQUIRED 0x0000000000000002
|
||||||
|
#define PACKAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x0000000000000004
|
||||||
|
|
||||||
|
#define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION 4
|
||||||
|
|
||||||
|
typedef struct efi_firmware_image_dependencies {
|
||||||
|
u8 dependencies[0];
|
||||||
|
} efi_firmware_image_dep_t;
|
||||||
|
|
||||||
|
struct efi_firmware_image_descriptor {
|
||||||
|
u8 image_index;
|
||||||
|
efi_guid_t image_type_id;
|
||||||
|
u64 image_id;
|
||||||
|
u16 *image_id_name;
|
||||||
|
u32 version;
|
||||||
|
u16 *version_name;
|
||||||
|
efi_uintn_t size;
|
||||||
|
u64 attributes_supported;
|
||||||
|
u64 attributes_setting;
|
||||||
|
u64 compatibilities;
|
||||||
|
u32 lowest_supported_image_version;
|
||||||
|
u32 last_attempt_version;
|
||||||
|
u32 last_attempt_status;
|
||||||
|
u64 hardware_instance;
|
||||||
|
efi_firmware_image_dep_t *dependencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct efi_firmware_management_protocol {
|
||||||
|
efi_status_t (EFIAPI *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 (EFIAPI *get_image)(
|
||||||
|
struct efi_firmware_management_protocol *this,
|
||||||
|
u8 image_index,
|
||||||
|
void *image,
|
||||||
|
efi_uintn_t *image_size);
|
||||||
|
efi_status_t (EFIAPI *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_status_t (EFIAPI *check_image)(
|
||||||
|
struct efi_firmware_management_protocol *this,
|
||||||
|
u8 image_index,
|
||||||
|
const void *image,
|
||||||
|
efi_uintn_t *image_size,
|
||||||
|
u32 *image_updatable);
|
||||||
|
efi_status_t (EFIAPI *get_package_info)(
|
||||||
|
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_status_t (EFIAPI *set_package_info)(
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,6 +212,8 @@ extern const efi_guid_t efi_guid_cert_type_pkcs7;
|
|||||||
extern const efi_guid_t efi_guid_rng_protocol;
|
extern const efi_guid_t efi_guid_rng_protocol;
|
||||||
/* GUID of capsule update result */
|
/* GUID of capsule update result */
|
||||||
extern const efi_guid_t efi_guid_capsule_report;
|
extern const efi_guid_t efi_guid_capsule_report;
|
||||||
|
/* GUID of firmware management protocol */
|
||||||
|
extern const efi_guid_t efi_guid_firmware_management_protocol;
|
||||||
|
|
||||||
extern unsigned int __efi_runtime_start, __efi_runtime_stop;
|
extern unsigned int __efi_runtime_start, __efi_runtime_stop;
|
||||||
extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
|
extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
|
||||||
|
@ -127,6 +127,14 @@ 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_MANAGEMENT
|
||||||
|
bool "Capsule: Firmware Management Protocol"
|
||||||
|
depends on EFI_HAVE_CAPSULE_SUPPORT
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Select this option if you want to enable capsule-based
|
||||||
|
firmware update using Firmware Management Protocol.
|
||||||
|
|
||||||
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
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
#include <sort.h>
|
#include <sort.h>
|
||||||
|
|
||||||
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
|
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
|
||||||
|
static const efi_guid_t efi_guid_firmware_management_capsule_id =
|
||||||
|
EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
|
||||||
|
const efi_guid_t efi_guid_firmware_management_protocol =
|
||||||
|
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
|
||||||
|
|
||||||
#ifdef CONFIG_EFI_CAPSULE_ON_DISK
|
#ifdef CONFIG_EFI_CAPSULE_ON_DISK
|
||||||
/* for file system access */
|
/* for file system access */
|
||||||
@ -85,9 +89,214 @@ void set_capsule_result(int index, struct efi_capsule_header *capsule,
|
|||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
sizeof(result), &result);
|
sizeof(result), &result);
|
||||||
if (ret)
|
if (ret)
|
||||||
printf("EFI: creating %ls failed\n", variable_name16);
|
log_err("EFI: creating %ls failed\n", variable_name16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT
|
||||||
|
/**
|
||||||
|
* efi_fmp_find - search for Firmware Management Protocol drivers
|
||||||
|
* @image_type: Image type guid
|
||||||
|
* @instance: Instance number
|
||||||
|
* @handles: Handles of FMP drivers
|
||||||
|
* @no_handles: Number of handles
|
||||||
|
*
|
||||||
|
* Search for Firmware Management Protocol drivers, matching the image
|
||||||
|
* type, @image_type and the machine instance, @instance, from the list,
|
||||||
|
* @handles.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* * Protocol instance - on success
|
||||||
|
* * NULL - on failure
|
||||||
|
*/
|
||||||
|
static struct efi_firmware_management_protocol *
|
||||||
|
efi_fmp_find(efi_guid_t *image_type, u64 instance, efi_handle_t *handles,
|
||||||
|
efi_uintn_t no_handles)
|
||||||
|
{
|
||||||
|
efi_handle_t *handle;
|
||||||
|
struct efi_firmware_management_protocol *fmp;
|
||||||
|
struct efi_firmware_image_descriptor *image_info, *desc;
|
||||||
|
efi_uintn_t info_size, descriptor_size;
|
||||||
|
u32 descriptor_version;
|
||||||
|
u8 descriptor_count;
|
||||||
|
u32 package_version;
|
||||||
|
u16 *package_version_name;
|
||||||
|
bool found = false;
|
||||||
|
int i, j;
|
||||||
|
efi_status_t ret;
|
||||||
|
|
||||||
|
for (i = 0, handle = handles; i < no_handles; i++, handle++) {
|
||||||
|
ret = EFI_CALL(efi_handle_protocol(
|
||||||
|
*handle,
|
||||||
|
&efi_guid_firmware_management_protocol,
|
||||||
|
(void **)&fmp));
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* get device's image info */
|
||||||
|
info_size = 0;
|
||||||
|
image_info = NULL;
|
||||||
|
descriptor_version = 0;
|
||||||
|
descriptor_count = 0;
|
||||||
|
descriptor_size = 0;
|
||||||
|
package_version = 0;
|
||||||
|
package_version_name = NULL;
|
||||||
|
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size,
|
||||||
|
image_info,
|
||||||
|
&descriptor_version,
|
||||||
|
&descriptor_count,
|
||||||
|
&descriptor_size,
|
||||||
|
&package_version,
|
||||||
|
&package_version_name));
|
||||||
|
if (ret != EFI_BUFFER_TOO_SMALL)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
image_info = malloc(info_size);
|
||||||
|
if (!image_info)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
ret = EFI_CALL(fmp->get_image_info(fmp, &info_size,
|
||||||
|
image_info,
|
||||||
|
&descriptor_version,
|
||||||
|
&descriptor_count,
|
||||||
|
&descriptor_size,
|
||||||
|
&package_version,
|
||||||
|
&package_version_name));
|
||||||
|
if (ret != EFI_SUCCESS ||
|
||||||
|
descriptor_version != EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
/* matching */
|
||||||
|
for (j = 0, desc = image_info; j < descriptor_count;
|
||||||
|
j++, desc = (void *)desc + descriptor_size) {
|
||||||
|
log_debug("+++ desc[%d] index: %d, name: %ls\n",
|
||||||
|
j, desc->image_index, desc->image_id_name);
|
||||||
|
if (!guidcmp(&desc->image_type_id, image_type) &&
|
||||||
|
(!instance ||
|
||||||
|
!desc->hardware_instance ||
|
||||||
|
desc->hardware_instance == instance))
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip:
|
||||||
|
efi_free_pool(package_version_name);
|
||||||
|
free(image_info);
|
||||||
|
EFI_CALL(efi_close_protocol(
|
||||||
|
(efi_handle_t)fmp,
|
||||||
|
&efi_guid_firmware_management_protocol,
|
||||||
|
NULL, NULL));
|
||||||
|
if (found)
|
||||||
|
return fmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* efi_capsule_update_firmware - update firmware from capsule
|
||||||
|
* @capsule_data: Capsule
|
||||||
|
*
|
||||||
|
* Update firmware, using a capsule, @capsule_data. Loading any FMP
|
||||||
|
* drivers embedded in a capsule is not supported.
|
||||||
|
*
|
||||||
|
* Return: status code
|
||||||
|
*/
|
||||||
|
static efi_status_t efi_capsule_update_firmware(
|
||||||
|
struct efi_capsule_header *capsule_data)
|
||||||
|
{
|
||||||
|
struct efi_firmware_management_capsule_header *capsule;
|
||||||
|
struct efi_firmware_management_capsule_image_header *image;
|
||||||
|
size_t capsule_size;
|
||||||
|
void *image_binary, *vendor_code;
|
||||||
|
efi_handle_t *handles;
|
||||||
|
efi_uintn_t no_handles;
|
||||||
|
int item;
|
||||||
|
struct efi_firmware_management_protocol *fmp;
|
||||||
|
u16 *abort_reason;
|
||||||
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (capsule_data->header_size < sizeof(*capsule) ||
|
||||||
|
capsule_data->header_size >= capsule_data->capsule_image_size)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
capsule = (void *)capsule_data + capsule_data->header_size;
|
||||||
|
capsule_size = capsule_data->capsule_image_size
|
||||||
|
- capsule_data->header_size;
|
||||||
|
|
||||||
|
if (capsule->version != 0x00000001)
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
handles = NULL;
|
||||||
|
ret = EFI_CALL(efi_locate_handle_buffer(
|
||||||
|
BY_PROTOCOL,
|
||||||
|
&efi_guid_firmware_management_protocol,
|
||||||
|
NULL, &no_handles, (efi_handle_t **)&handles));
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
/* Payload */
|
||||||
|
for (item = capsule->embedded_driver_count;
|
||||||
|
item < capsule->embedded_driver_count
|
||||||
|
+ capsule->payload_item_count; item++) {
|
||||||
|
/* sanity check */
|
||||||
|
if ((capsule->item_offset_list[item] + sizeof(*image)
|
||||||
|
>= capsule_size)) {
|
||||||
|
log_err("EFI: A capsule has not enough data\n");
|
||||||
|
ret = EFI_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = (void *)capsule + capsule->item_offset_list[item];
|
||||||
|
|
||||||
|
if (image->version != 0x00000003) {
|
||||||
|
ret = EFI_UNSUPPORTED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find a device for update firmware */
|
||||||
|
/* TODO: should we pass index as well, or nothing but type? */
|
||||||
|
fmp = efi_fmp_find(&image->update_image_type_id,
|
||||||
|
image->update_hardware_instance,
|
||||||
|
handles, no_handles);
|
||||||
|
if (!fmp) {
|
||||||
|
log_err("EFI Capsule: driver not found for firmware type: %pUl, hardware instance: %lld\n",
|
||||||
|
&image->update_image_type_id,
|
||||||
|
image->update_hardware_instance);
|
||||||
|
ret = EFI_UNSUPPORTED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do update */
|
||||||
|
image_binary = (void *)image + sizeof(*image);
|
||||||
|
vendor_code = image_binary + image->update_image_size;
|
||||||
|
|
||||||
|
abort_reason = NULL;
|
||||||
|
ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index,
|
||||||
|
image_binary,
|
||||||
|
image->update_image_size,
|
||||||
|
vendor_code, NULL,
|
||||||
|
&abort_reason));
|
||||||
|
if (ret != EFI_SUCCESS) {
|
||||||
|
log_err("EFI Capsule: firmware update failed: %ls\n",
|
||||||
|
abort_reason);
|
||||||
|
efi_free_pool(abort_reason);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
efi_free_pool(handles);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static efi_status_t efi_capsule_update_firmware(
|
||||||
|
struct efi_capsule_header *capsule_data)
|
||||||
|
{
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* efi_update_capsule() - process information from operating system
|
* efi_update_capsule() - process information from operating system
|
||||||
* @capsule_header_array: Array of virtual address pointers
|
* @capsule_header_array: Array of virtual address pointers
|
||||||
@ -118,9 +327,29 @@ efi_status_t EFIAPI efi_update_capsule(
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = EFI_UNSUPPORTED;
|
ret = EFI_SUCCESS;
|
||||||
for (i = 0, capsule = *capsule_header_array; i < capsule_count;
|
for (i = 0, capsule = *capsule_header_array; i < capsule_count;
|
||||||
i++, capsule = *(++capsule_header_array)) {
|
i++, capsule = *(++capsule_header_array)) {
|
||||||
|
/* sanity check */
|
||||||
|
if (capsule->header_size < sizeof(*capsule) ||
|
||||||
|
capsule->capsule_image_size < sizeof(*capsule)) {
|
||||||
|
log_err("EFI: A capsule has not enough data\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("Capsule[%d] (guid:%pUl)\n",
|
||||||
|
i, &capsule->capsule_guid);
|
||||||
|
if (!guidcmp(&capsule->capsule_guid,
|
||||||
|
&efi_guid_firmware_management_capsule_id)) {
|
||||||
|
ret = efi_capsule_update_firmware(capsule);
|
||||||
|
} else {
|
||||||
|
log_err("EFI: not support capsule type: %pUl\n",
|
||||||
|
&capsule->capsule_guid);
|
||||||
|
ret = EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return EFI_EXIT(ret);
|
return EFI_EXIT(ret);
|
||||||
@ -265,7 +494,7 @@ static efi_status_t find_boot_device(void)
|
|||||||
if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
|
if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
|
||||||
/* BootNext does exist here */
|
/* BootNext does exist here */
|
||||||
if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) {
|
if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) {
|
||||||
printf("BootNext must be 16-bit integer\n");
|
log_err("BootNext must be 16-bit integer\n");
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
sprintf((char *)boot_var, "Boot%04X", bootnext);
|
sprintf((char *)boot_var, "Boot%04X", bootnext);
|
||||||
@ -323,7 +552,7 @@ out:
|
|||||||
u16 *path_str;
|
u16 *path_str;
|
||||||
|
|
||||||
path_str = efi_dp_str(boot_dev);
|
path_str = efi_dp_str(boot_dev);
|
||||||
EFI_PRINT("EFI Capsule: bootdev is %ls\n", path_str);
|
log_debug("EFI Capsule: bootdev is %ls\n", path_str);
|
||||||
efi_free_pool(path_str);
|
efi_free_pool(path_str);
|
||||||
|
|
||||||
volume = efi_fs_from_path(boot_dev);
|
volume = efi_fs_from_path(boot_dev);
|
||||||
@ -363,7 +592,7 @@ static efi_status_t efi_capsule_scan_dir(u16 ***files, unsigned int *num)
|
|||||||
|
|
||||||
ret = find_boot_device();
|
ret = find_boot_device();
|
||||||
if (ret == EFI_NOT_FOUND) {
|
if (ret == EFI_NOT_FOUND) {
|
||||||
EFI_PRINT("EFI Capsule: bootdev is not set\n");
|
log_debug("EFI Capsule: bootdev is not set\n");
|
||||||
*num = 0;
|
*num = 0;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
} else if (ret != EFI_SUCCESS) {
|
} else if (ret != EFI_SUCCESS) {
|
||||||
@ -619,20 +848,19 @@ efi_status_t efi_launch_capsules(void)
|
|||||||
|
|
||||||
/* Launch capsules */
|
/* Launch capsules */
|
||||||
for (i = 0, ++index; i < nfiles; i++, index++) {
|
for (i = 0, ++index; i < nfiles; i++, index++) {
|
||||||
EFI_PRINT("capsule from %ls ...\n", files[i]);
|
log_debug("capsule from %ls ...\n", files[i]);
|
||||||
if (index > 0xffff)
|
if (index > 0xffff)
|
||||||
index = 0;
|
index = 0;
|
||||||
ret = efi_capsule_read_file(files[i], &capsule);
|
ret = efi_capsule_read_file(files[i], &capsule);
|
||||||
if (ret == EFI_SUCCESS) {
|
if (ret == EFI_SUCCESS) {
|
||||||
ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0));
|
ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0));
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
printf("EFI Capsule update failed at %ls\n",
|
log_err("EFI Capsule update failed at %ls\n",
|
||||||
files[i]);
|
files[i]);
|
||||||
|
|
||||||
free(capsule);
|
free(capsule);
|
||||||
} else {
|
} else {
|
||||||
printf("EFI: reading capsule failed: %ls\n",
|
log_err("EFI: reading capsule failed: %ls\n", files[i]);
|
||||||
files[i]);
|
|
||||||
}
|
}
|
||||||
/* create CapsuleXXXX */
|
/* create CapsuleXXXX */
|
||||||
set_capsule_result(index, capsule, ret);
|
set_capsule_result(index, capsule, ret);
|
||||||
@ -640,8 +868,8 @@ efi_status_t efi_launch_capsules(void)
|
|||||||
/* delete a capsule either in case of success or failure */
|
/* delete a capsule either in case of success or failure */
|
||||||
ret = efi_capsule_delete_file(files[i]);
|
ret = efi_capsule_delete_file(files[i]);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
printf("EFI: deleting a capsule file failed: %ls\n",
|
log_err("EFI: deleting a capsule file failed: %ls\n",
|
||||||
files[i]);
|
files[i]);
|
||||||
}
|
}
|
||||||
efi_capsule_scan_done();
|
efi_capsule_scan_done();
|
||||||
|
|
||||||
|
@ -159,6 +159,10 @@ static efi_status_t efi_init_os_indications(void)
|
|||||||
os_indications_supported |=
|
os_indications_supported |=
|
||||||
EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
|
EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT))
|
||||||
|
os_indications_supported |=
|
||||||
|
EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED;
|
||||||
|
|
||||||
return efi_set_variable_int(L"OsIndicationsSupported",
|
return efi_set_variable_int(L"OsIndicationsSupported",
|
||||||
&efi_global_variable_guid,
|
&efi_global_variable_guid,
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
Loading…
Reference in New Issue
Block a user