From patchwork Tue Mar 17 02:12:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 243726 List-Id: U-Boot discussion From: takahiro.akashi at linaro.org (AKASHI Takahiro) Date: Tue, 17 Mar 2020 11:12:43 +0900 Subject: [RFC 10/14] efi_loader: capsule: support variable update In-Reply-To: <20200317021247.5849-1-takahiro.akashi@linaro.org> References: <20200317021247.5849-1-takahiro.akashi@linaro.org> Message-ID: <20200317021247.5849-11-takahiro.akashi@linaro.org> See EBBR specification v1.0. A capsule tagged with the guid, EFI_VARIABLE_STORAGE_GUID, will be handled as a variable update object. What efi_update_capsule() basically does is to re-play SetVariable against each variable entry in a capsule. Signed-off-by: AKASHI Takahiro --- include/efi_api.h | 18 +++++++++++++++ lib/efi_loader/Kconfig | 7 ++++++ lib/efi_loader/efi_capsule.c | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/efi_api.h b/include/efi_api.h index e103369186a2..30807942380b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -229,6 +229,10 @@ enum efi_reset_type { EFI_GUID(0x6dcbd5ed, 0xe82d, 0x4c44, 0xbd, 0xa1, \ 0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a) +#define EFI_VARIABLE_STORAGE_GUID \ + EFI_GUID(0x1a3fb419, 0x2171, 0x458d, 0xb8, 0xb4, \ + 0xbe, 0xa3, 0x0c, 0x9f, 0x6b, 0xab) + struct efi_capsule_header { efi_guid_t capsule_guid; u32 header_size; @@ -283,6 +287,20 @@ struct efi_capsule_result_variable_fmp { // u16 capsule_target[]; } __packed; +struct efi_ebbr_variable { + u16 variable_name[64]; + efi_guid_t vendor_guid; + u32 attributes; + u32 data_size; + u8 data[]; +}; + +struct efi_ebbr_variable_bundle { + struct efi_capsule_header header; + u8 reserved[0]; + struct efi_ebbr_variable variables[]; +} __packed; + #define EFI_RT_SUPPORTED_GET_TIME 0x0001 #define EFI_RT_SUPPORTED_SET_TIME 0x0002 #define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004 diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 41b1e9b5543c..616e2acbe102 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -129,6 +129,13 @@ config EFI_CAPSULE_FIT_DEVICE help Define storage device for storing FIT image +config EFI_CAPSULE_UPDATE_VARIABLE + bool "Capsule based variable update" + default n + help + Select this option if you want to enable capsule-based + variable update support + endif config EFI_CAPSULE_ON_DISK diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index f3526beed681..1293270aea95 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -18,6 +18,7 @@ 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; +static const efi_guid_t efi_guid_variable_storage = EFI_VARIABLE_STORAGE_GUID; /* for file system access */ static struct efi_file_handle *bootdev_root; @@ -172,6 +173,45 @@ static efi_status_t efi_capsule_update_firmware( } #endif /* CONFIG_EFI_CAPSULE_UPDATE_FIRMWARE */ +#ifdef CONFIG_EFI_CAPSULE_UPDATE_VARIABLE +/* + * Execute a log of variable changes + */ +static efi_status_t +efi_capsule_update_variables(struct efi_ebbr_variable_bundle *bundle) +{ + struct efi_ebbr_variable *variable; + efi_status_t ret = EFI_SUCCESS; + + for (variable = (void *)bundle + bundle->header.header_size; + (void *)variable + < ((void *)bundle + bundle->header.capsule_image_size); + variable = (struct efi_ebbr_variable *) + ((void *)variable + + sizeof(*variable) + variable->data_size)) { + ret = efi_set_variable(variable->variable_name, + &variable->vendor_guid, + variable->attributes, + variable->data_size, + &variable->data); + /* Should NOT_FOUND always be treated as success? */ + if (ret == EFI_NOT_FOUND) + ret = EFI_SUCCESS; + EFI_PRINT("Capsule variable update %s: %ls\n", + ret == EFI_SUCCESS ? "succeeded" : "failed", + variable->variable_name); + } + + return ret; +} +#else +static efi_status_t +efi_capsule_update_variables(struct efi_ebbr_variable_bundle *bundle) +{ + return EFI_UNSUPPORTED; +} +#endif /* CONFIG_EFI_CAPSULE_UPDATE_VARIABLE */ + /* * Launch a capsule */ @@ -214,6 +254,11 @@ efi_status_t EFIAPI efi_update_capsule( ret = efi_capsule_update_firmware( (struct efi_firmware_management_capsule_header *) ((void *)capsule + sizeof(*capsule))); + else if (!guidcmp(&capsule->capsule_guid, + &efi_guid_variable_storage)) + ret = efi_capsule_update_variables( + (struct efi_ebbr_variable_bundle *) + capsule); else ret = EFI_UNSUPPORTED;