blob: d44dc09813e36604aac0cc77983ec8ffc2d9cff9 [file] [log] [blame]
AKASHI Takahirof4818e62020-11-30 18:12:12 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * EFI Firmware management protocol
4 *
5 * Copyright (c) 2020 Linaro Limited
6 * Author: AKASHI Takahiro
7 */
8
Heinrich Schuchardt955a3212025-01-16 20:26:59 +01009#define LOG_CATEGORY LOGC_EFI
10
AKASHI Takahirof4818e62020-11-30 18:12:12 +090011#include <charset.h>
12#include <dfu.h>
13#include <efi_loader.h>
Masahisa Kojima45a18f02023-06-07 14:41:52 +090014#include <efi_variable.h>
Sughosh Ganu1cadae22022-10-21 18:16:03 +053015#include <fwu.h>
AKASHI Takahirof4818e62020-11-30 18:12:12 +090016#include <image.h>
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053017#include <signatures.h>
18
AKASHI Takahirof4818e62020-11-30 18:12:12 +090019#include <linux/list.h>
20
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053021#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
22
23/**
24 * struct fmp_payload_header - EDK2 header for the FMP payload
25 *
26 * This structure describes the header which is preprended to the
27 * FMP payload by the edk2 capsule generation scripts.
28 *
29 * @signature: Header signature used to identify the header
30 * @header_size: Size of the structure
31 * @fw_version: Firmware versions used
32 * @lowest_supported_version: Lowest supported version
33 */
34struct fmp_payload_header {
35 u32 signature;
36 u32 header_size;
37 u32 fw_version;
38 u32 lowest_supported_version;
39};
40
Masahisa Kojima45a18f02023-06-07 14:41:52 +090041/**
42 * struct fmp_state - fmp firmware update state
43 *
44 * This structure describes the state of the firmware update
45 * through FMP protocol.
46 *
47 * @fw_version: Firmware versions used
48 * @lowest_supported_version: Lowest supported version
49 * @last_attempt_version: Last attempt version
50 * @last_attempt_status: Last attempt status
51 */
52struct fmp_state {
53 u32 fw_version;
54 u32 lowest_supported_version; /* not used */
55 u32 last_attempt_version; /* not used */
56 u32 last_attempt_status; /* not used */
57};
58
Masahisa Kojima45a18f02023-06-07 14:41:52 +090059/**
60 * efi_firmware_get_image_type_id - get image_type_id
61 * @image_index: image index
62 *
63 * Return the image_type_id identified by the image index.
64 *
65 * Return: pointer to the image_type_id, NULL if image_index is invalid
66 */
67static
68efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
69{
70 int i;
71 struct efi_fw_image *fw_array;
72
73 fw_array = update_info.images;
74 for (i = 0; i < update_info.num_images; i++) {
75 if (fw_array[i].image_index == image_index)
76 return &fw_array[i].image_type_id;
77 }
78
79 return NULL;
80}
81
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +090082/* Place holder; not supported */
83static
84efi_status_t EFIAPI efi_firmware_get_image_unsupported(
85 struct efi_firmware_management_protocol *this,
86 u8 image_index,
87 void *image,
88 efi_uintn_t *image_size)
89{
90 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
91
92 return EFI_EXIT(EFI_UNSUPPORTED);
93}
94
95/* Place holder; not supported */
96static
97efi_status_t EFIAPI efi_firmware_check_image_unsupported(
98 struct efi_firmware_management_protocol *this,
99 u8 image_index,
100 const void *image,
101 efi_uintn_t *image_size,
102 u32 *image_updatable)
103{
104 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
105 image_updatable);
106
107 return EFI_EXIT(EFI_UNSUPPORTED);
108}
109
110/* Place holder; not supported */
111static
112efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
113 struct efi_firmware_management_protocol *this,
114 u32 *package_version,
115 u16 **package_version_name,
116 u32 *package_version_name_maxlen,
117 u64 *attributes_supported,
118 u64 *attributes_setting)
119{
120 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
121 package_version_name, package_version_name_maxlen,
122 attributes_supported, attributes_setting);
123
124 return EFI_EXIT(EFI_UNSUPPORTED);
125}
126
127/* Place holder; not supported */
128static
129efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
130 struct efi_firmware_management_protocol *this,
131 const void *image,
132 efi_uintn_t *image_size,
133 const void *vendor_code,
134 u32 package_version,
135 const u16 *package_version_name)
136{
137 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
138 package_version, package_version_name);
139
140 return EFI_EXIT(EFI_UNSUPPORTED);
141}
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900142
143/**
Masahisa Kojima941353c2023-06-07 14:41:54 +0900144 * efi_firmware_get_lsv_from_dtb - get lowest supported version from dtb
145 * @image_index: Image index
146 * @image_type_id: Image type id
147 * @lsv: Pointer to store the lowest supported version
148 *
149 * Read the firmware version information from dtb.
150 */
151static void efi_firmware_get_lsv_from_dtb(u8 image_index,
152 efi_guid_t *image_type_id, u32 *lsv)
153{
154 const void *fdt = gd->fdt_blob;
155 const fdt32_t *val;
156 const char *guid_str;
157 int len, offset, index;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900158 int parent, ret;
Masahisa Kojima941353c2023-06-07 14:41:54 +0900159
160 *lsv = 0;
161
162 parent = fdt_subnode_offset(fdt, 0, "firmware-version");
163 if (parent < 0)
164 return;
165
166 fdt_for_each_subnode(offset, fdt, parent) {
167 efi_guid_t guid;
168
169 guid_str = fdt_getprop(fdt, offset, "image-type-id", &len);
170 if (!guid_str)
171 continue;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900172 ret = uuid_str_to_bin(guid_str, guid.b, UUID_STR_FORMAT_GUID);
173 if (ret < 0) {
174 log_warning("Wrong image-type-id format.\n");
175 continue;
176 }
Masahisa Kojima941353c2023-06-07 14:41:54 +0900177
178 val = fdt_getprop(fdt, offset, "image-index", &len);
179 if (!val)
180 continue;
181 index = fdt32_to_cpu(*val);
182
183 if (!guidcmp(&guid, image_type_id) && index == image_index) {
184 val = fdt_getprop(fdt, offset,
185 "lowest-supported-version", &len);
186 if (val)
187 *lsv = fdt32_to_cpu(*val);
188 }
189 }
190}
191
192/**
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900193 * efi_firmware_fill_version_info - fill the version information
194 * @image_info: Image information
195 * @fw_array: Pointer to size of new image
196 *
197 * Fill the version information into image_info strucrure.
198 *
199 */
200static
201void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_info,
202 struct efi_fw_image *fw_array)
203{
204 u16 varname[13]; /* u"FmpStateXXXX" */
205 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900206 efi_uintn_t size, expected_size;
207 uint num_banks = 1;
208 uint active_index = 0;
209 struct fmp_state *var_state;
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900210
Masahisa Kojima941353c2023-06-07 14:41:54 +0900211 efi_firmware_get_lsv_from_dtb(fw_array->image_index,
212 &fw_array->image_type_id,
213 &image_info->lowest_supported_image_version);
214
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900215 image_info->version_name = NULL; /* not supported */
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900216 image_info->last_attempt_version = 0;
217 image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900218 image_info->version = 0;
219
220 /* get the fw_version */
221 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
222 fw_array->image_index);
223 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
224 ret = fwu_get_active_index(&active_index);
225 if (ret)
226 return;
227
228 num_banks = CONFIG_FWU_NUM_BANKS;
229 }
230
231 size = num_banks * sizeof(*var_state);
232 expected_size = size;
233 var_state = calloc(1, size);
234 if (!var_state)
235 return;
236
237 ret = efi_get_variable_int(varname, &fw_array->image_type_id,
238 NULL, &size, var_state, NULL);
239 if (ret == EFI_SUCCESS && expected_size == size)
240 image_info->version = var_state[active_index].fw_version;
241
242 free(var_state);
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900243}
244
245/**
Caleb Connolly3744e472024-08-30 13:34:33 +0100246 * efi_gen_capsule_guids - generate GUIDs for the images
247 *
248 * Generate the image_type_id for each image in the update_info.images array
249 * using the first compatible from the device tree and a salt
250 * UUID defined at build time.
251 *
252 * Returns: status code
253 */
254static efi_status_t efi_gen_capsule_guids(void)
255{
256 int ret, i;
257 struct uuid namespace;
258 const char *compatible; /* Full array including null bytes */
259 struct efi_fw_image *fw_array;
260
261 fw_array = update_info.images;
262 /* Check if we need to run (there are images and we didn't already generate their IDs) */
263 if (!update_info.num_images ||
264 memchr_inv(&fw_array[0].image_type_id, 0, sizeof(fw_array[0].image_type_id)))
265 return EFI_SUCCESS;
266
267 ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_GUID,
268 (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
269 if (ret) {
270 log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
271 return EFI_INVALID_PARAMETER;
272 }
273
274 compatible = ofnode_read_string(ofnode_root(), "compatible");
275 if (!compatible) {
276 log_debug("%s: model or compatible not defined\n", __func__);
277 return EFI_INVALID_PARAMETER;
278 }
279
280 for (i = 0; i < update_info.num_images; i++) {
Ilias Apalodimas33cfbc02024-12-03 18:13:37 +0200281 if (!fw_array[i].fw_name) {
282 log_err("fw_name is not defined. Not generating capsule GUIDs\n");
283 return EFI_INVALID_PARAMETER;
284 }
Caleb Connolly3744e472024-08-30 13:34:33 +0100285 gen_v5_guid(&namespace,
286 &fw_array[i].image_type_id,
287 compatible, strlen(compatible),
288 fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
289 NULL);
290
291 log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
292 &fw_array[i].image_type_id);
293 }
294
295 return EFI_SUCCESS;
296}
297
298/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530299 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900300 * @image_info_size: Size of @image_info
301 * @image_info: Image information
302 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530303 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900304 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530305 * @package_version: Package version
306 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900307 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530308 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900309 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530310 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900311 *
312 * Return status code
313 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530314static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900315 efi_uintn_t *image_info_size,
316 struct efi_firmware_image_descriptor *image_info,
317 u32 *descriptor_version,
318 u8 *descriptor_count,
319 efi_uintn_t *descriptor_size,
320 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530321 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900322{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530323 size_t total_size;
324 struct efi_fw_image *fw_array;
Caleb Connolly3744e472024-08-30 13:34:33 +0100325 int i, ret;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900326
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900327 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900328
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900329 if (*image_info_size < total_size) {
330 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900331
332 return EFI_BUFFER_TOO_SMALL;
333 }
334 *image_info_size = total_size;
335
Caleb Connolly3744e472024-08-30 13:34:33 +0100336 ret = efi_gen_capsule_guids();
337 if (ret != EFI_SUCCESS)
338 return ret;
339
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530340 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900341 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900342 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900343 *descriptor_size = sizeof(*image_info);
344 *package_version = 0xffffffff; /* not supported */
345 *package_version_name = NULL; /* not supported */
346
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900347 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530348 image_info[i].image_index = fw_array[i].image_index;
349 image_info[i].image_type_id = fw_array[i].image_type_id;
350 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530351 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900352
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900353 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
354
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900355 image_info[i].size = 0;
356 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530357 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
358 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900359 image_info[i].attributes_setting =
360 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530361
362 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530363 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530364 image_info[0].attributes_setting |=
365 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
366
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900367 image_info[i].hardware_instance = 1;
368 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900369 }
370
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900371 return EFI_SUCCESS;
372}
373
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200374/**
375 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
376 * @p_image: Pointer to new image
377 * @p_image_size: Pointer to size of new image
378 *
379 * Authenticate the capsule if authentication is enabled.
380 * The image pointer and the image size are updated in case of success.
381 *
382 * Return: status code
383 */
384static
385efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
386 efi_uintn_t *p_image_size)
387{
388 const void *image = *p_image;
389 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200390 void *capsule_payload;
391 efi_status_t status;
392 efi_uintn_t capsule_payload_size;
393
394 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
395 capsule_payload = NULL;
396 capsule_payload_size = 0;
397 status = efi_capsule_authenticate(image, image_size,
398 &capsule_payload,
399 &capsule_payload_size);
400
401 if (status == EFI_SECURITY_VIOLATION) {
402 printf("Capsule authentication check failed. Aborting update\n");
403 return status;
404 } else if (status != EFI_SUCCESS) {
405 return status;
406 }
407
408 debug("Capsule authentication successful\n");
409 image = capsule_payload;
410 image_size = capsule_payload_size;
411 } else {
412 debug("Capsule authentication disabled. ");
413 debug("Updating capsule without authenticating.\n");
414 }
415
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200416 *p_image = image;
417 *p_image_size = image_size;
418 return EFI_SUCCESS;
419}
420
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900421/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900422 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
423 * @state: Pointer to fmp state
424 * @image_index: image index
425 *
426 * Update the FmpStateXXXX variable with the firmware update state.
427 *
428 * Return: status code
429 */
430static
431efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
432{
433 u16 varname[13]; /* u"FmpStateXXXX" */
434 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900435 uint num_banks = 1;
436 uint update_bank = 0;
437 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900438 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900439 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900440
441 image_type_id = efi_firmware_get_image_type_id(image_index);
442 if (!image_type_id)
443 return EFI_INVALID_PARAMETER;
444
445 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
446 image_index);
447
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900448 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
449 ret = fwu_plat_get_update_index(&update_bank);
450 if (ret)
451 return EFI_INVALID_PARAMETER;
452
453 num_banks = CONFIG_FWU_NUM_BANKS;
454 }
455
456 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900457 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900458 if (!var_state)
459 return EFI_OUT_OF_RESOURCES;
460
461 /*
462 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
463 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900464 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900465 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
466 var_state, NULL);
467 if (ret != EFI_SUCCESS)
468 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900469
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900470 /*
471 * Only the fw_version is set here.
472 * lowest_supported_version in FmpState variable is ignored since
473 * it can be tampered if the file based EFI variable storage is used.
474 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900475 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900476
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900477 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900478 ret = efi_set_variable_int(varname, image_type_id,
479 EFI_VARIABLE_READ_ONLY |
480 EFI_VARIABLE_NON_VOLATILE |
481 EFI_VARIABLE_BOOTSERVICE_ACCESS |
482 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900483 size, var_state, false);
484
485 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900486
487 return ret;
488}
489
490/**
491 * efi_firmware_get_fw_version - get fw_version from FMP payload header
492 * @p_image: Pointer to new image
493 * @p_image_size: Pointer to size of new image
494 * @state: Pointer to fmp state
495 *
496 * Parse the FMP payload header and fill the fmp_state structure.
497 * If no FMP payload header is found, fmp_state structure is not updated.
498 *
499 */
500static void efi_firmware_get_fw_version(const void **p_image,
501 efi_uintn_t *p_image_size,
502 struct fmp_state *state)
503{
504 const struct fmp_payload_header *header;
505 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
506
507 header = *p_image;
508 if (header->signature == fmp_hdr_signature) {
509 /* FMP header is inserted above the capsule payload */
510 state->fw_version = header->fw_version;
511
512 *p_image += header->header_size;
513 *p_image_size -= header->header_size;
514 }
515}
516
517/**
518 * efi_firmware_verify_image - verify image
519 * @p_image: Pointer to new image
520 * @p_image_size: Pointer to size of new image
521 * @image_index: Image index
522 * @state: Pointer to fmp state
523 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900524 * Verify the capsule authentication and check if the fw_version
525 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900526 *
527 * Return: status code
528 */
529static
530efi_status_t efi_firmware_verify_image(const void **p_image,
531 efi_uintn_t *p_image_size,
532 u8 image_index,
533 struct fmp_state *state)
534{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900535 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900536 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900537 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900538
539 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900540 if (ret != EFI_SUCCESS)
541 return ret;
542
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900543 efi_firmware_get_fw_version(p_image, p_image_size, state);
544
Masahisa Kojima94f47802023-06-07 14:41:55 +0900545 image_type_id = efi_firmware_get_image_type_id(image_index);
546 if (!image_type_id)
547 return EFI_INVALID_PARAMETER;
548
549 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
550 if (state->fw_version < lsv) {
551 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
552 state->fw_version, lsv);
553 return EFI_INVALID_PARAMETER;
554 }
555
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900556 return ret;
557}
558
559/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530560 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900561 * firmware image
562 * @this: Protocol instance
563 * @image_info_size: Size of @image_info
564 * @image_info: Image information
565 * @descriptor_version: Pointer to version number
566 * @descriptor_count: Pointer to number of descriptors
567 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200568 * @package_version: Package version
569 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900570 *
571 * Return information bout the current firmware image in @image_info.
572 * @image_info will consist of a number of descriptors.
573 * Each descriptor will be created based on "dfu_alt_info" variable.
574 *
575 * Return status code
576 */
577static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530578efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900579 struct efi_firmware_management_protocol *this,
580 efi_uintn_t *image_info_size,
581 struct efi_firmware_image_descriptor *image_info,
582 u32 *descriptor_version,
583 u8 *descriptor_count,
584 efi_uintn_t *descriptor_size,
585 u32 *package_version,
586 u16 **package_version_name)
587{
588 efi_status_t ret;
589
590 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
591 image_info_size, image_info,
592 descriptor_version, descriptor_count, descriptor_size,
593 package_version, package_version_name);
594
595 if (!image_info_size)
596 return EFI_EXIT(EFI_INVALID_PARAMETER);
597
598 if (*image_info_size &&
599 (!image_info || !descriptor_version || !descriptor_count ||
600 !descriptor_size || !package_version || !package_version_name))
601 return EFI_EXIT(EFI_INVALID_PARAMETER);
602
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530603 ret = efi_fill_image_desc_array(image_info_size, image_info,
604 descriptor_version, descriptor_count,
605 descriptor_size, package_version,
606 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900607
608 return EFI_EXIT(ret);
609}
610
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530611#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
612/*
613 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
614 * method with existing FIT image format, and handles
615 * - multiple regions of firmware via DFU
616 * but doesn't support
617 * - versioning of firmware image
618 * - package information
619 */
620
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900621/**
622 * efi_firmware_fit_set_image - update the firmware image
623 * @this: Protocol instance
624 * @image_index: Image index number
625 * @image: New image
626 * @image_size: Size of new image
627 * @vendor_code: Vendor-specific update policy
628 * @progress: Function to report the progress of update
629 * @abort_reason: Pointer to string of abort reason
630 *
631 * Update the firmware to new image, using dfu. The new image should
632 * have FIT image format commonly used in U-Boot.
633 * @vendor_code, @progress and @abort_reason are not supported.
634 *
635 * Return: status code
636 */
637static
638efi_status_t EFIAPI efi_firmware_fit_set_image(
639 struct efi_firmware_management_protocol *this,
640 u8 image_index,
641 const void *image,
642 efi_uintn_t image_size,
643 const void *vendor_code,
644 efi_status_t (*progress)(efi_uintn_t completion),
645 u16 **abort_reason)
646{
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600647 int ret;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200648 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900649 struct fmp_state state = { 0 };
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600650 char *orig_dfu_env;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200651
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100652 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900653 image_size, vendor_code, progress, abort_reason);
654
655 if (!image || image_index != 1)
656 return EFI_EXIT(EFI_INVALID_PARAMETER);
657
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900658 status = efi_firmware_verify_image(&image, &image_size, image_index,
659 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200660 if (status != EFI_SUCCESS)
661 return EFI_EXIT(status);
662
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600663 orig_dfu_env = env_get("dfu_alt_info");
664 if (orig_dfu_env) {
665 orig_dfu_env = strdup(orig_dfu_env);
666 if (!orig_dfu_env) {
667 log_err("strdup() failed!\n");
668 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
669 }
670 }
671 if (env_set("dfu_alt_info", update_info.dfu_string)) {
672 log_err("Unable to set env variable \"dfu_alt_info\"!\n");
673 free(orig_dfu_env);
674 return EFI_EXIT(EFI_DEVICE_ERROR);
675 }
676
677 ret = fit_update(image);
678
679 if (env_set("dfu_alt_info", orig_dfu_env))
680 log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n");
681
682 free(orig_dfu_env);
683
684 if (ret)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900685 return EFI_EXIT(EFI_DEVICE_ERROR);
686
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900687 efi_firmware_set_fmp_state_var(&state, image_index);
688
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900689 return EFI_EXIT(EFI_SUCCESS);
690}
691
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900692const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530693 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900694 .get_image = efi_firmware_get_image_unsupported,
695 .set_image = efi_firmware_fit_set_image,
696 .check_image = efi_firmware_check_image_unsupported,
697 .get_package_info = efi_firmware_get_package_info_unsupported,
698 .set_package_info = efi_firmware_set_package_info_unsupported,
699};
700#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900701
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900702#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
703/*
704 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
705 * method with raw data.
706 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900707
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900708/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900709 * efi_firmware_raw_set_image - update the firmware image
710 * @this: Protocol instance
711 * @image_index: Image index number
712 * @image: New image
713 * @image_size: Size of new image
714 * @vendor_code: Vendor-specific update policy
715 * @progress: Function to report the progress of update
716 * @abort_reason: Pointer to string of abort reason
717 *
718 * Update the firmware to new image, using dfu. The new image should
719 * be a single raw image.
720 * @vendor_code, @progress and @abort_reason are not supported.
721 *
722 * Return: status code
723 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900724static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900725efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900726 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900727 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900728 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900729 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900730 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900731 efi_status_t (*progress)(efi_uintn_t completion),
732 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900733{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530734 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900735 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530736 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900737 struct fmp_state state = { 0 };
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600738 char *orig_dfu_env;
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530739
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100740 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900741 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900742
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900743 if (!image)
744 return EFI_EXIT(EFI_INVALID_PARAMETER);
745
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900746 status = efi_firmware_verify_image(&image, &image_size, image_index,
747 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200748 if (status != EFI_SUCCESS)
749 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530750
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900751 /*
752 * dfu_alt_num is assigned from 0 while image_index starts from 1.
753 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
754 * is not used.
755 */
756 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530757 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
758 /*
759 * Based on the value of update bank, derive the
760 * image index value.
761 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900762 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530763 if (ret) {
764 log_debug("Unable to get FWU image_index\n");
765 return EFI_EXIT(EFI_DEVICE_ERROR);
766 }
767 }
768
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600769 orig_dfu_env = env_get("dfu_alt_info");
770 if (orig_dfu_env) {
771 orig_dfu_env = strdup(orig_dfu_env);
772 if (!orig_dfu_env) {
773 log_err("strdup() failed!\n");
774 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
775 }
776 }
777 if (env_set("dfu_alt_info", update_info.dfu_string)) {
778 log_err("Unable to set env variable \"dfu_alt_info\"!\n");
779 free(orig_dfu_env);
780 return EFI_EXIT(EFI_DEVICE_ERROR);
781 }
782
783 ret = dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
784 NULL, NULL);
785
786 if (env_set("dfu_alt_info", orig_dfu_env))
787 log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n");
788
789 free(orig_dfu_env);
790
791 if (ret)
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900792 return EFI_EXIT(EFI_DEVICE_ERROR);
793
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900794 efi_firmware_set_fmp_state_var(&state, image_index);
795
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900796 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900797}
798
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900799const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530800 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900801 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900802 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900803 .check_image = efi_firmware_check_image_unsupported,
804 .get_package_info = efi_firmware_get_package_info_unsupported,
805 .set_package_info = efi_firmware_set_package_info_unsupported,
806};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900807#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */