Am 13. August 2026 07:50:17 MESZ schrieb Balaji Selvanathan 
<[email protected]>:
>The last_attempt_version and last_attempt_status fields in struct
>fmp_state were carried but never populated, so the ESRT last-attempt
>information exposed to the OS stayed at its boot-time defaults
>regardless of what happened during an update.
>
>Add the plumbing to maintain them: a helper to record the attempted
>version and status, a mapping from internal efi_status_t codes to the
>UEFI LAST_ATTEMPT_STATUS_* values, and reads/writes of the two fields
>in efi_firmware_fill_version_info() and efi_firmware_set_fmp_state_var().
>fw_version is now only advanced on a successful update so a failed
>attempt no longer overwrites the recorded good version.
>
>Signed-off-by: Balaji Selvanathan <[email protected]>
>---
> lib/efi_loader/efi_firmware.c | 74 +++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 68 insertions(+), 6 deletions(-)
>
>diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
>index b41969c70fd..cbe8bcd7c64 100644
>--- a/lib/efi_loader/efi_firmware.c
>+++ b/lib/efi_loader/efi_firmware.c
>@@ -52,9 +52,9 @@ struct fmp_payload_header {
>  */
> struct fmp_state {
>       u32 fw_version;
>-      u32 lowest_supported_version; /* not used */
>-      u32 last_attempt_version; /* not used */
>-      u32 last_attempt_status; /* not used */
>+      u32 lowest_supported_version; /* not used - read from DTB for security 
>*/
>+      u32 last_attempt_version;     /* used for esrt tracking */

Thank you for improving the ESRT reporting.

Please, provide a description explaining which information is contained in the 
field.

>+      u32 last_attempt_status;      /* used for esrt tracking */

ditto


> };
> 
> /**
>@@ -190,6 +190,49 @@ static void efi_firmware_get_lsv_from_dtb(u8 image_index,
>       }
> }
> 
>+/**
>+ * efi_firmware_set_last_attempt - set last attempt information
>+ * @state:            Pointer to fmp state
>+ * @attempt_version:  Version that was attempted

version of what?

How about:

Firmware version of the last attempted capsule update.

>+ * @attempt_status:   Status of the attempt

With type u32 and "Status" I would have no clue which values to expect and what 
they might mean.

In the description you could refer to the enum containing 
LAST_ATTEMPT_STATUS_SUCCESS et al.

Best regards

Heinrich

>+ *
>+ * Set the last attempt version and status in the fmp_state structure.
>+ */
>+static void efi_firmware_set_last_attempt(struct fmp_state *state,
>+                                        u32 attempt_version,
>+                                        u32 attempt_status)
>+{
>+      state->last_attempt_version = attempt_version;
>+      state->last_attempt_status = attempt_status;
>+}
>+
>+/**
>+ * efi_firmware_map_error_to_status - map internal errors to UEFI status codes
>+ * @error:    Internal error code
>+ *
>+ * Map U-Boot internal error codes to UEFI-compliant last attempt status 
>codes.
>+ *
>+ * Return: UEFI last attempt status code
>+ */
>+static u32 efi_firmware_map_error_to_status(efi_status_t error)
>+{
>+      switch (error) {
>+      case EFI_SUCCESS:
>+              return LAST_ATTEMPT_STATUS_SUCCESS;
>+      case EFI_OUT_OF_RESOURCES:
>+              return LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
>+      case EFI_INVALID_PARAMETER:
>+              return LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
>+      case EFI_SECURITY_VIOLATION:
>+              return LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
>+      case EFI_UNSUPPORTED:
>+              return LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
>+      case EFI_DEVICE_ERROR:
>+      default:
>+              return LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
>+      }
>+}
>+
> /**
>  * efi_firmware_fill_version_info - fill the version information
>  * @image_info:               Image information
>@@ -237,8 +280,15 @@ void efi_firmware_fill_version_info(struct 
>efi_firmware_image_descriptor *image_
> 
>       ret = efi_get_variable_int(varname, &fw_array->image_type_id,
>                                  NULL, &size, var_state, NULL);
>-      if (ret == EFI_SUCCESS && expected_size == size)
>+      if (ret == EFI_SUCCESS && expected_size == size) {
>               image_info->version = var_state[active_index].fw_version;
>+              image_info->last_attempt_version = 
>var_state[active_index].last_attempt_version;
>+              image_info->last_attempt_status = 
>var_state[active_index].last_attempt_status;
>+      } else {
>+              /* Default values if no previous state exists */
>+              image_info->last_attempt_version = 0;
>+              image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
>+      }
> 
>       free(var_state);
> }
>@@ -427,6 +477,10 @@ efi_status_t efi_firmware_capsule_authenticate(const void 
>**p_image,
>  * @image_index:      image index
>  *
>  * Update the FmpStateXXXX variable with the firmware update state.
>+ * On successful update (last_attempt_status == LAST_ATTEMPT_STATUS_SUCCESS),
>+ * updates fw_version to the new version.
>+ * On failed update, preserves the old fw_version.
>+ * Always updates last_attempt_version and last_attempt_status.
>  *
>  * Return:            status code
>  */
>@@ -471,11 +525,19 @@ efi_status_t efi_firmware_set_fmp_state_var(struct 
>fmp_state *state, u8 image_in
>               memset(var_state, 0, num_banks * sizeof(*var_state));
> 
>       /*
>-       * Only the fw_version is set here.
>+       * Set fw_version and last attempt information.
>        * lowest_supported_version in FmpState variable is ignored since
>        * it can be tampered if the file based EFI variable storage is used.
>+       *
>+       * Only update fw_version if the update succeeded.
>+       * On failure, preserve the old fw_version to maintain accurate ESRT 
>state.
>        */
>-      var_state[update_bank].fw_version = state->fw_version;
>+      if (state->last_attempt_status == LAST_ATTEMPT_STATUS_SUCCESS)
>+              var_state[update_bank].fw_version = state->fw_version;
>+      /* else: keep existing fw_version (don't update on failure) */
>+
>+      var_state[update_bank].last_attempt_version = 
>state->last_attempt_version;
>+      var_state[update_bank].last_attempt_status = state->last_attempt_status;
> 
>       size = num_banks * sizeof(*var_state);
>       ret = efi_set_variable_int(varname, image_type_id,
>

Reply via email to