Message ID | 20200427094829.1140-4-takahiro.akashi@linaro.org |
---|---|
State | New |
Headers | show |
Series | efi_loader: add capsule update support | expand |
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.akashi at 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; > >
Heinrich, On Sun, May 17, 2020 at 10:02:08AM +0200, Heinrich Schuchardt wrote: > 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.akashi at 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? The lines above come from my secure boot patch, while my capsule patch is based on pre-v2020.07-rc1 in which my secure boot patch has not been merged when I posted capsule patch. > > > > +#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 Okay, as I said somewhere else, I've forgot to add some function descriptions in v1. > > +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(). I don't get your point. This kind of description, like "See the UEFI ...," are often seen in efi_boottime.c and others. > > + * > > + * @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. The only thing that we should do now is to export "efi_set_variable_common." (I don't know if Ilias' StandaloneMM will accept READ_ONLY attribute.) Please note that there is also an instance that should be read-only in efi_init_secure_boot(). -Takahiro Akashi > 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; > > > > >
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 */ +#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( + struct 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; +} + +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 + */ +/** + * 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. + * + * @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. + * + * @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 + 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;
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.akashi at 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