On 4/27/20 11:48 AM, AKASHI Takahiro wrote: > In this commit, skeleton functions for capsule-related API's are > added under CONFIG_EFI_UPDATE_CAPSULE configuration. > Detailed implementation for a specific capsule type will be added > in the succeeding patches. > > Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org> > --- > include/efi_api.h | 12 +++ > include/efi_loader.h | 15 ++++ > lib/efi_loader/Kconfig | 11 +++ > lib/efi_loader/Makefile | 1 + > lib/efi_loader/efi_capsule.c | 153 +++++++++++++++++++++++++++++++++++ > lib/efi_loader/efi_runtime.c | 104 ++++++++++++++---------- > lib/efi_loader/efi_setup.c | 31 +++++-- > 7 files changed, 276 insertions(+), 51 deletions(-) > create mode 100644 lib/efi_loader/efi_capsule.c > > diff --git a/include/efi_api.h b/include/efi_api.h > index 77d6bf2660b9..6fa3f4a887d2 100644 > --- a/include/efi_api.h > +++ b/include/efi_api.h > @@ -217,6 +217,10 @@ enum efi_reset_type { > #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 > #define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 > > +#define EFI_CAPSULE_REPORT_GUID \ > + EFI_GUID(0x39b68c46, 0xf7fb, 0x441b, 0xb6, 0xec, \ > + 0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3) > + > struct efi_capsule_header { > efi_guid_t capsule_guid; > u32 header_size; > @@ -224,6 +228,14 @@ struct efi_capsule_header { > u32 capsule_image_size; > } __packed; > > +struct efi_capsule_result_variable_header { > + u32 variable_total_size; > + u32 reserved; > + efi_guid_t capsule_guid; > + struct efi_time capsule_processed; > + efi_status_t capsule_status; > +} __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/include/efi_loader.h b/include/efi_loader.h > index d4510462d616..19ffc027c171 100644 > --- a/include/efi_loader.h > +++ b/include/efi_loader.h > @@ -196,6 +196,8 @@ extern const efi_guid_t efi_guid_cert_type_pkcs7; > > /* GUID of RNG protocol */ > extern const efi_guid_t efi_guid_rng_protocol; > +/* GUID of capsule update result */ > +extern const efi_guid_t efi_guid_capsule_report; > > extern unsigned int __efi_runtime_start, __efi_runtime_stop; > extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; > @@ -778,6 +780,19 @@ bool efi_image_parse(void *efi, size_t len, struct > efi_image_regions **regp, > WIN_CERTIFICATE **auth, size_t *auth_len); > #endif /* CONFIG_EFI_SECURE_BOOT */
This line does not exist in upstream. Instead we have: bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, WIN_CERTIFICATE **auth, size_t *auth_len); #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ Am I missing patches? Or do you have to rebase your series? > > +#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT > +/* Capsule update */ > +efi_status_t EFIAPI efi_update_capsule( > + struct efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 scatter_gather_list); > +efi_status_t EFIAPI efi_query_capsule_caps( > + efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 *maximum_capsule_size, > + u32 *reset_type); > +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */ > + > #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ > > /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ > diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig > index 7cc2d940f848..e2b08251f26a 100644 > --- a/lib/efi_loader/Kconfig > +++ b/lib/efi_loader/Kconfig > @@ -45,6 +45,17 @@ config EFI_SET_TIME > Provide the SetTime() runtime service at boottime. This service > can be used by an EFI application to adjust the real time clock. > > +config EFI_HAVE_CAPSULE_SUPPORT > + bool > + > +config EFI_RUNTIME_UPDATE_CAPSULE > + bool "UpdateCapsule() runtime service" > + default n > + select EFI_HAVE_CAPSULE_SUPPORT > + help > + Select this option if you want to use UpdateCapsule and > + QueryCapsuleCapabilities API's. > + > config EFI_DEVICE_PATH_TO_TEXT > bool "Device path to text protocol" > default y > diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile > index eff3c25ec301..2ee1e683d9c5 100644 > --- a/lib/efi_loader/Makefile > +++ b/lib/efi_loader/Makefile > @@ -22,6 +22,7 @@ endif > obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o > obj-y += efi_bootmgr.o > obj-y += efi_boottime.o > +obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o > obj-y += efi_console.o > obj-y += efi_device_path.o > obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o > diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c > new file mode 100644 > index 000000000000..fb104bb92a6c > --- /dev/null > +++ b/lib/efi_loader/efi_capsule.c > @@ -0,0 +1,153 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * EFI Capsule > + * > + * Copyright (c) 2018 Linaro Limited > + * Author: AKASHI Takahiro > + */ > + > +#include <common.h> > +#include <efi_loader.h> > +#include <fs.h> > +#include <malloc.h> > +#include <sort.h> > + > +const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID; > + > +static __maybe_unused int get_last_capsule(void) > +{ > + u16 value16[11]; /* "CapsuleXXXX": non-null-terminated */ > + char value[11], *p; > + efi_uintn_t size; > + unsigned long num = 0xffff; > + efi_status_t ret; > + > + size = sizeof(value16); > + ret = EFI_CALL(efi_get_variable(L"CapsuleLast", > + &efi_guid_capsule_report, > + NULL, &size, value16)); > + if (ret != EFI_SUCCESS || u16_strncmp(value16, L"Capsule", 7)) > + goto err; > + > + p = value; > + utf16_utf8_strcpy(&p, value16); > + strict_strtoul(&value[7], 16, &num); > +err: > + return (int)num; > +} > + Missing function description > +static __maybe_unused > +void set_capsule_result(int num, struct efi_capsule_header *capsule, > + efi_status_t return_status) > +{ > + char variable_name[12]; > + u16 variable_name16[12], *p; > + struct efi_capsule_result_variable_header result; > + struct efi_time time; > + efi_status_t ret; > + > + sprintf(variable_name, "Capsule%04X", num); > + p = variable_name16; > + utf8_utf16_strncpy(&p, variable_name, 11); > + result.variable_total_size = sizeof(result); > + result.capsule_guid = capsule->capsule_guid; > + ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL)); > + if (ret == EFI_SUCCESS) > + memcpy(&result.capsule_processed, &time, sizeof(time)); > + else > + memset(&result.capsule_processed, 0, sizeof(time)); > + result.capsule_status = return_status; > + ret = EFI_CALL(efi_set_variable(variable_name16, > + &efi_guid_capsule_report, > + EFI_VARIABLE_NON_VOLATILE | > + EFI_VARIABLE_BOOTSERVICE_ACCESS | > + EFI_VARIABLE_RUNTIME_ACCESS, > + sizeof(result), &result)); > + if (ret) > + printf("EFI: creating %s failed\n", variable_name); > +} > + > +/* > + * Launch a capsule Please, stick to the style described in https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#function-documentation > + */ > +/** > + * efi_update_capsule() - process information from operating system > + * > + * This function implements the UpdateCapsule() runtime service. > + * > + * See the Unified Extensible Firmware Interface (UEFI) specification for > + * details. > + * > + * @capsule_header_array: pointer to array of virtual pointers > + * @capsule_count: number of pointers in capsule_header_array > + * @scatter_gather_list: pointer to arry of physical pointers > + * Return: status code > + */ > +efi_status_t EFIAPI efi_update_capsule( > + struct efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 scatter_gather_list) > +{ > + struct efi_capsule_header *capsule; > + unsigned int i; > + efi_status_t ret; > + > + EFI_ENTRY("%p, %lu, %llu\n", capsule_header_array, capsule_count, > + scatter_gather_list); > + > + if (!capsule_count) { > + ret = EFI_INVALID_PARAMETER; > + goto out; > + } > + > + ret = EFI_SUCCESS; > + for (i = 0, capsule = *capsule_header_array; i < capsule_count; > + i++, capsule = *(++capsule_header_array)) { > + } > +out: > + return EFI_EXIT(ret); > +} > + > +/** > + * efi_query_capsule_caps() - check if capsule is supported > + * > + * This function implements the QueryCapsuleCapabilities() runtime service. > + * > + * See the Unified Extensible Firmware Interface (UEFI) specification for > + * details. > + * > + * @capsule_header_array: pointer to array of virtual pointers > + * @capsule_count: number of pointers in capsule_header_array > + * @maximum_capsule_size: maximum capsule size > + * @reset_type: type of reset needed for capsule update > + * Return: status code > + */ > +efi_status_t EFIAPI efi_query_capsule_caps( > + struct efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 *maximum_capsule_size, > + u32 *reset_type) > +{ > + struct efi_capsule_header *capsule __attribute__((unused)); > + unsigned int i; > + efi_status_t ret; > + > + EFI_ENTRY("%p, %lu, %p, %p\n", capsule_header_array, capsule_count, > + maximum_capsule_size, reset_type); > + > + if (!maximum_capsule_size) { > + ret = EFI_INVALID_PARAMETER; > + goto out; > + } > + > + *maximum_capsule_size = U64_MAX; > + *reset_type = EFI_RESET_COLD; > + > + ret = EFI_SUCCESS; > + for (i = 0, capsule = *capsule_header_array; i < capsule_count; > + i++, capsule = *(++capsule_header_array)) { > + /* TODO */ > + } > +out: > + return EFI_EXIT(ret); > +} > diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c > index 6a25acbbcdf5..669e25a9589a 100644 > --- a/lib/efi_loader/efi_runtime.c > +++ b/lib/efi_loader/efi_runtime.c > @@ -130,6 +130,11 @@ efi_status_t efi_init_runtime_supported(void) > #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET > rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; > #endif > +#ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE > + rt_table->runtime_services_supported |= > + (EFI_RT_SUPPORTED_UPDATE_CAPSULE | > + EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES); > +#endif > > ret = efi_install_configuration_table(&efi_rt_properties_table_guid, > rt_table); > @@ -410,6 +415,50 @@ efi_status_t __weak __efi_runtime EFIAPI > efi_set_time(struct efi_time *time) > return EFI_UNSUPPORTED; > } > > +/** > + * efi_update_capsule_unsupported() - process information from operating > system > + * > + * This function implements the UpdateCapsule() runtime service. > + * > + * See the Unified Extensible Firmware Interface (UEFI) specification for > + * details. The description should differ from the description of efi_update_capsule(). > + * > + * @capsule_header_array: pointer to array of virtual pointers > + * @capsule_count: number of pointers in capsule_header_array > + * @scatter_gather_list: pointer to arry of physical pointers > + * Returns: status code > + */ > +efi_status_t __efi_runtime EFIAPI efi_update_capsule_unsupported( > + struct efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 scatter_gather_list) > +{ > + return EFI_UNSUPPORTED; > +} > + > +/** > + * efi_query_capsule_caps_unsupported() - check if capsule is supported > + * > + * This function implements the QueryCapsuleCapabilities() runtime service. > + * > + * See the Unified Extensible Firmware Interface (UEFI) specification for > + * details. The description should differ from the description of efi_query_capsule_caps(). > + * > + * @capsule_header_array: pointer to array of virtual pointers > + * @capsule_count: number of pointers in capsule_header_array > + * @maximum_capsule_size: maximum capsule size > + * @reset_type: type of reset needed for capsule update > + * Returns: status code > + */ > +efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps_unsupported( > + struct efi_capsule_header **capsule_header_array, > + efi_uintn_t capsule_count, > + u64 *maximum_capsule_size, > + u32 *reset_type) > +{ > + return EFI_UNSUPPORTED; > +} > + > /** > * efi_is_runtime_service_pointer() - check if pointer points to runtime > table > * > @@ -433,6 +482,12 @@ void efi_runtime_detach(void) > efi_runtime_services.reset_system = efi_reset_system; > efi_runtime_services.get_time = efi_get_time; > efi_runtime_services.set_time = efi_set_time; > +#ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE > + /* won't support at runtime */ > + efi_runtime_services.update_capsule = efi_update_capsule_unsupported; > + efi_runtime_services.query_capsule_caps = > + efi_query_capsule_caps_unsupported; > +#endif > > /* Update CRC32 */ > efi_update_table_header_crc32(&efi_runtime_services.hdr); > @@ -837,50 +892,6 @@ static efi_status_t __efi_runtime EFIAPI > efi_unimplemented(void) > return EFI_UNSUPPORTED; > } > > -/** > - * efi_update_capsule() - process information from operating system > - * > - * This function implements the UpdateCapsule() runtime service. > - * > - * See the Unified Extensible Firmware Interface (UEFI) specification for > - * details. > - * > - * @capsule_header_array: pointer to array of virtual pointers > - * @capsule_count: number of pointers in capsule_header_array > - * @scatter_gather_list: pointer to arry of physical pointers > - * Returns: status code > - */ > -efi_status_t __efi_runtime EFIAPI efi_update_capsule( > - struct efi_capsule_header **capsule_header_array, > - efi_uintn_t capsule_count, > - u64 scatter_gather_list) > -{ > - return EFI_UNSUPPORTED; > -} > - > -/** > - * efi_query_capsule_caps() - check if capsule is supported > - * > - * This function implements the QueryCapsuleCapabilities() runtime service. > - * > - * See the Unified Extensible Firmware Interface (UEFI) specification for > - * details. > - * > - * @capsule_header_array: pointer to array of virtual pointers > - * @capsule_count: number of pointers in capsule_header_array > - * @maximum_capsule_size: maximum capsule size > - * @reset_type: type of reset needed for capsule update > - * Returns: status code > - */ > -efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( > - struct efi_capsule_header **capsule_header_array, > - efi_uintn_t capsule_count, > - u64 *maximum_capsule_size, > - u32 *reset_type) > -{ > - return EFI_UNSUPPORTED; > -} > - > struct efi_runtime_services __efi_runtime_data efi_runtime_services = { > .hdr = { > .signature = EFI_RUNTIME_SERVICES_SIGNATURE, > @@ -898,7 +909,12 @@ struct efi_runtime_services __efi_runtime_data > efi_runtime_services = { > .set_variable = efi_set_variable, > .get_next_high_mono_count = (void *)&efi_unimplemented, > .reset_system = &efi_reset_system_boottime, > +#ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE > .update_capsule = efi_update_capsule, > .query_capsule_caps = efi_query_capsule_caps, > +#else > + .update_capsule = efi_update_capsule_unsupported, > + .query_capsule_caps = efi_query_capsule_caps_unsupported, > +#endif > .query_variable_info = efi_query_variable_info, > }; > diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c > index 1b648c84673a..8fe378bbfdfc 100644 > --- a/lib/efi_loader/efi_setup.c > +++ b/lib/efi_loader/efi_setup.c > @@ -115,6 +115,29 @@ static efi_status_t efi_init_secure_boot(void) > } > #endif /* CONFIG_EFI_SECURE_BOOT */ > > +/** > + * efi_init_os_indications() - indicate supported features for OS requests > + * > + * Set the OsIndicationsSupported variable. > + * > + * Return: status code > + */ > +static efi_status_t efi_init_os_indications(void) > +{ > + u64 os_indications_supported = 0; > + > +#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT > + os_indications_supported |= > + EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED; > +#endif Though the UEFI spec does not mention it I guess we will have to treat OsIndicationsSupported as read-only once we get that properly supported. Best regards Heinrich > + return EFI_CALL(efi_set_variable(L"OsIndicationsSupported", > + &efi_global_variable_guid, > + EFI_VARIABLE_BOOTSERVICE_ACCESS | > + EFI_VARIABLE_RUNTIME_ACCESS, > + sizeof(os_indications_supported), > + &os_indications_supported)); > +} > + > /** > * efi_init_obj_list() - Initialize and populate EFI object list > * > @@ -122,7 +145,6 @@ static efi_status_t efi_init_secure_boot(void) > */ > efi_status_t efi_init_obj_list(void) > { > - u64 os_indications_supported = 0; /* None */ > efi_status_t ret = EFI_SUCCESS; > > /* Initialize once only */ > @@ -146,12 +168,7 @@ efi_status_t efi_init_obj_list(void) > goto out; > > /* Indicate supported features */ > - ret = EFI_CALL(efi_set_variable(L"OsIndicationsSupported", > - &efi_global_variable_guid, > - EFI_VARIABLE_BOOTSERVICE_ACCESS | > - EFI_VARIABLE_RUNTIME_ACCESS, > - sizeof(os_indications_supported), > - &os_indications_supported)); > + ret = efi_init_os_indications(); > if (ret != EFI_SUCCESS) > goto out; > >