From: Abdellatif El Khlifi <abdellatif.elkhl...@arm.com> Accept the FWU at ExitBootServices()
Provide the FWU_ACCEPT_IMAGE ABI and setup an event triggered on ExitBootServices(). This mechanism notifies Secure world that the system booted successfully by accepting the images in trial state. Also, add FWU_ARM_PSA_ACCEPT_IMAGES config to allow platforms to switch off image acceptance in ExitBootServices(). Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhl...@arm.com> Cc: Sughosh Ganu <sughosh.g...@linaro.org> Cc: Tom Rini <tr...@konsulko.com> Cc: Ilias Apalodimas <ilias.apalodi...@linaro.org> Cc: Simon Glass <s...@chromium.org> Cc: Michal Simek <michal.si...@amd.com> Cc: Marek Vasut <marek.vasut+rene...@mailbox.org> Cc: Casey Connolly <casey.conno...@linaro.org> --- Changelog of changes: =========================== v2: * As suggested by Michal: Add /** for marking kernel-doc format v1: * Accept the FWU at ExitBootServices() include/fwu_arm_psa.h | 22 +++- lib/fwu_updates/Kconfig | 8 ++ lib/fwu_updates/fwu_arm_psa.c | 183 ++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 1 deletion(-) diff --git a/include/fwu_arm_psa.h b/include/fwu_arm_psa.h index 00c78ba7e7c..6400cf44d1b 100644 --- a/include/fwu_arm_psa.h +++ b/include/fwu_arm_psa.h @@ -84,9 +84,10 @@ enum fwu_abis { FWU_WRITE_STREAM = 20, FWU_READ_STREAM = 21, FWU_COMMIT = 22, + FWU_ACCEPT_IMAGE = 23, /* To be updated when adding new FWU IDs */ FWU_FIRST_ID = FWU_DISCOVER, /* Lowest number ID */ - FWU_LAST_ID = FWU_COMMIT, /* Highest number ID */ + FWU_LAST_ID = FWU_ACCEPT_IMAGE, /* Highest number ID */ }; enum fwu_abi_errcode { @@ -311,6 +312,25 @@ struct __packed fwu_write_stream_resp { int status; }; +/** + * struct fwu_accept_image_args - fwu_accept_image ABI arguments + * @function_id: fwu_accept_image service ID + * @image_type_guid: GUID of the image to be accepted + */ +struct __packed fwu_accept_image_args { + u32 function_id; + u32 reserved; + efi_guid_t image_type_guid; +}; + +/** + * struct fwu_accept_image_resp - fwu_accept_image ABI returns + * @status: The ABI return status + */ +struct __packed fwu_accept_image_resp { + int status; +}; + /* * FWU directory information structures */ diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig index cdc96109f0a..958e54dec37 100644 --- a/lib/fwu_updates/Kconfig +++ b/lib/fwu_updates/Kconfig @@ -57,6 +57,14 @@ config FWU_ARM_PSA driver that supports the Arm PSA firmware update specification as mentioned in https://developer.arm.com/documentation/den0118/a/ +config FWU_ARM_PSA_ACCEPT_IMAGES + bool "Accept images at EFI ExitBootServices() level" + depends on FWU_ARM_PSA + default y + help + Select this option if reaching ExitBootServices() level means the boot succeeded + This option will add a callback at ExitBootServices() that accepts all the images. + config FWU_BUFFER_PAGES int "Number of 4KB pages in the FWU shared buffer" depends on FWU_ARM_PSA diff --git a/lib/fwu_updates/fwu_arm_psa.c b/lib/fwu_updates/fwu_arm_psa.c index 042bf7a0898..40746eee6ce 100644 --- a/lib/fwu_updates/fwu_arm_psa.c +++ b/lib/fwu_updates/fwu_arm_psa.c @@ -8,6 +8,7 @@ */ #include <arm_ffa.h> #include <dm.h> +#include <fwu.h> #include <fwu_arm_psa.h> #include <fwu.h> #include <log.h> @@ -113,6 +114,14 @@ static struct fwu_abi_errmap err_msg_map[FWU_ERRMAP_COUNT] = { "FWU_DENIED: The system is not in a Staging state", }, }, + [FWU_ID_TO_ERRMAP_ID(FWU_ACCEPT_IMAGE)] = { + { + [FWU_UNKNOWN] = + "FWU_UNKNOWN: Image with type=image_type_guid is not managed by the Update Agent", + [FWU_DENIED] = + "FWU_DENIED: The system has not booted with the active bank, or the image cannot be accepted before being activated", + }, + }, }; /** @@ -708,6 +717,36 @@ static int fwu_write_stream(u32 handle, const u8 *payload, u32 payload_size) return ret; } +/** + * fwu_accept() - fwu_accept_image ABI + * @guid: GUID of the image to be accepted + * + * Sets the status of the firmware image, with a given GUID + * to "accepted" in the active firmware bank. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int fwu_accept(const efi_guid_t *guid) +{ + struct fwu_accept_image_args *args = g_fwu_buf; + struct fwu_accept_image_resp *resp = g_fwu_buf; + char *svc_name = "FWU_ACCEPT_IMAGE"; + + if (!guid) + return -EINVAL; + + /* Filling the arguments in the shared buffer */ + args->function_id = FWU_ACCEPT_IMAGE; + + guidcpy(&args->image_type_guid, guid); + + /* Executing the FWU ABI through the FF-A bus */ + return fwu_invoke_svc(args->function_id, svc_name, + sizeof(*args), sizeof(*resp), NULL); +} + /** * fwu_update_image() - Update an image * @@ -1051,6 +1090,144 @@ failure: return ret; } +/** + * fwu_one_image_accepted() - Accept one image in trial state + * @img_entry: Pointer to the image entry. + * @active_idx: Active bank index. + * @image_number: Image number for logging purposes. + * + * Invoke FWU accept image ABI to accept the image. + * + * Return: + * + * true is returned on success, false on failure. + */ +static bool fwu_one_image_accepted(const struct fwu_image_entry *img_entry, + u32 active_idx, + u32 image_number) +{ + const struct fwu_image_bank_info *bank_info = + &img_entry->img_bank_info[active_idx]; + int fwu_ret; + + if (!bank_info->accepted) { + fwu_ret = fwu_accept(&bank_info->image_guid); + if (fwu_ret) { + log_err("FWU: Failed to accept image #%d\n", + image_number + 1); + return false; + } + log_debug("FWU: Image #%d accepted\n", image_number + 1); + } + + return true; +} + +/** + * fwu_all_images_accepted() - Accept any pending firmware update images + * @fwu_data: Pointer to FWU data structure + * + * Read from the metadata the acceptance state of each image. + * Then, accept the images which are not accepted yet. + * + * Return: + * + * true is returned on success, false on failure. + */ +static bool fwu_all_images_accepted(const struct fwu_data *fwu_data) +{ + int fwu_ret; + u32 active_idx; + u32 i; + bool accepted; + + fwu_ret = fwu_get_active_index(&active_idx); + if (fwu_ret) { + log_err("FWU: Failed to read boot index, err (%d)\n", + fwu_ret); + return false; + } + + for (i = 0 ; i < CONFIG_FWU_NUM_IMAGES_PER_BANK ; i++) { + accepted = fwu_one_image_accepted(&fwu_data->fwu_images[i], active_idx, i); + if (!accepted) + return false; + } + + return true; +} + +/** + * fwu_accept_notify_exit_boot_services() - ExitBootServices callback + * + * @event: callback event + * @context: callback context + * + * Reaching ExitBootServices() level means the boot succeeded. + * So, accept all the images. + * + * Return: + * + * EFI_SUCCESS on success. Otherwise, failure + */ +static void EFIAPI fwu_accept_notify_exit_boot_services(struct efi_event *event, + void *context) +{ + efi_status_t efi_ret = EFI_SUCCESS; + bool all_accepted; + struct fwu_data *fwu_data; + + EFI_ENTRY("%p, %p", event, context); + + fwu_data = fwu_get_data(); + if (!fwu_data) { + log_err("FWU: Cannot get FWU data\n"); + efi_ret = EFI_INVALID_PARAMETER; + goto out; + } + + if (fwu_data->trial_state) { + all_accepted = fwu_all_images_accepted(fwu_data); + if (!all_accepted) { + efi_ret = EFI_ACCESS_DENIED; + goto out; + } + + } else { + log_info("FWU: ExitBootServices: Booting in regular state\n"); + } + +out: + EFI_EXIT(efi_ret); +} + +/** + * fwu_setup_accept_event() - Setup the FWU accept event + * + * Create a FWU accept event triggered on ExitBootServices(). + * + * Return: + * + * 0 is returned on success. Otherwise, failure + */ +static int fwu_setup_accept_event(void) +{ + efi_status_t efi_ret; + struct efi_event *evt = NULL; + + efi_ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, + fwu_accept_notify_exit_boot_services, NULL, + &efi_guid_event_group_exit_boot_services, + &evt); + if (efi_ret != EFI_SUCCESS) { + log_err("FWU: Cannot install accept event %p, err (%lu)\n", evt, + efi_ret); + return -EPERM; + } + + return 0; +} + /** * fwu_agent_init() - Setup the FWU agent * @@ -1105,6 +1282,12 @@ int fwu_agent_init(void) if (ret) goto failure; + if (IS_ENABLED(CONFIG_FWU_ARM_PSA_ACCEPT_IMAGES)) { + ret = fwu_setup_accept_event(); + if (ret) + goto failure; + } + g_fwu_initialized = true; return 0; -- 2.25.1