blob: 75501e21557577c00f561d8f1a00c16fa388b56b [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>
Tom Rini22856382025-05-14 16:46:03 -060015#include <env.h>
Sughosh Ganu1cadae22022-10-21 18:16:03 +053016#include <fwu.h>
AKASHI Takahirof4818e62020-11-30 18:12:12 +090017#include <image.h>
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053018#include <signatures.h>
19
AKASHI Takahirof4818e62020-11-30 18:12:12 +090020#include <linux/list.h>
21
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053022#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
23
24/**
25 * struct fmp_payload_header - EDK2 header for the FMP payload
26 *
27 * This structure describes the header which is preprended to the
28 * FMP payload by the edk2 capsule generation scripts.
29 *
30 * @signature: Header signature used to identify the header
31 * @header_size: Size of the structure
32 * @fw_version: Firmware versions used
33 * @lowest_supported_version: Lowest supported version
34 */
35struct fmp_payload_header {
36 u32 signature;
37 u32 header_size;
38 u32 fw_version;
39 u32 lowest_supported_version;
40};
41
Masahisa Kojima45a18f02023-06-07 14:41:52 +090042/**
43 * struct fmp_state - fmp firmware update state
44 *
45 * This structure describes the state of the firmware update
46 * through FMP protocol.
47 *
48 * @fw_version: Firmware versions used
49 * @lowest_supported_version: Lowest supported version
50 * @last_attempt_version: Last attempt version
51 * @last_attempt_status: Last attempt status
52 */
53struct fmp_state {
54 u32 fw_version;
55 u32 lowest_supported_version; /* not used */
56 u32 last_attempt_version; /* not used */
57 u32 last_attempt_status; /* not used */
58};
59
Masahisa Kojima45a18f02023-06-07 14:41:52 +090060/**
61 * efi_firmware_get_image_type_id - get image_type_id
62 * @image_index: image index
63 *
64 * Return the image_type_id identified by the image index.
65 *
66 * Return: pointer to the image_type_id, NULL if image_index is invalid
67 */
68static
69efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
70{
71 int i;
72 struct efi_fw_image *fw_array;
73
74 fw_array = update_info.images;
75 for (i = 0; i < update_info.num_images; i++) {
76 if (fw_array[i].image_index == image_index)
77 return &fw_array[i].image_type_id;
78 }
79
80 return NULL;
81}
82
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +090083/* Place holder; not supported */
84static
85efi_status_t EFIAPI efi_firmware_get_image_unsupported(
86 struct efi_firmware_management_protocol *this,
87 u8 image_index,
88 void *image,
89 efi_uintn_t *image_size)
90{
91 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
92
93 return EFI_EXIT(EFI_UNSUPPORTED);
94}
95
96/* Place holder; not supported */
97static
98efi_status_t EFIAPI efi_firmware_check_image_unsupported(
99 struct efi_firmware_management_protocol *this,
100 u8 image_index,
101 const void *image,
102 efi_uintn_t *image_size,
103 u32 *image_updatable)
104{
105 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
106 image_updatable);
107
108 return EFI_EXIT(EFI_UNSUPPORTED);
109}
110
111/* Place holder; not supported */
112static
113efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
114 struct efi_firmware_management_protocol *this,
115 u32 *package_version,
116 u16 **package_version_name,
117 u32 *package_version_name_maxlen,
118 u64 *attributes_supported,
119 u64 *attributes_setting)
120{
121 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
122 package_version_name, package_version_name_maxlen,
123 attributes_supported, attributes_setting);
124
125 return EFI_EXIT(EFI_UNSUPPORTED);
126}
127
128/* Place holder; not supported */
129static
130efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
131 struct efi_firmware_management_protocol *this,
132 const void *image,
133 efi_uintn_t *image_size,
134 const void *vendor_code,
135 u32 package_version,
136 const u16 *package_version_name)
137{
138 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
139 package_version, package_version_name);
140
141 return EFI_EXIT(EFI_UNSUPPORTED);
142}
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900143
144/**
Masahisa Kojima941353c2023-06-07 14:41:54 +0900145 * efi_firmware_get_lsv_from_dtb - get lowest supported version from dtb
146 * @image_index: Image index
147 * @image_type_id: Image type id
148 * @lsv: Pointer to store the lowest supported version
149 *
150 * Read the firmware version information from dtb.
151 */
152static void efi_firmware_get_lsv_from_dtb(u8 image_index,
153 efi_guid_t *image_type_id, u32 *lsv)
154{
155 const void *fdt = gd->fdt_blob;
156 const fdt32_t *val;
157 const char *guid_str;
158 int len, offset, index;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900159 int parent, ret;
Masahisa Kojima941353c2023-06-07 14:41:54 +0900160
161 *lsv = 0;
162
163 parent = fdt_subnode_offset(fdt, 0, "firmware-version");
164 if (parent < 0)
165 return;
166
167 fdt_for_each_subnode(offset, fdt, parent) {
168 efi_guid_t guid;
169
170 guid_str = fdt_getprop(fdt, offset, "image-type-id", &len);
171 if (!guid_str)
172 continue;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900173 ret = uuid_str_to_bin(guid_str, guid.b, UUID_STR_FORMAT_GUID);
174 if (ret < 0) {
175 log_warning("Wrong image-type-id format.\n");
176 continue;
177 }
Masahisa Kojima941353c2023-06-07 14:41:54 +0900178
179 val = fdt_getprop(fdt, offset, "image-index", &len);
180 if (!val)
181 continue;
182 index = fdt32_to_cpu(*val);
183
184 if (!guidcmp(&guid, image_type_id) && index == image_index) {
185 val = fdt_getprop(fdt, offset,
186 "lowest-supported-version", &len);
187 if (val)
188 *lsv = fdt32_to_cpu(*val);
189 }
190 }
191}
192
193/**
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900194 * efi_firmware_fill_version_info - fill the version information
195 * @image_info: Image information
196 * @fw_array: Pointer to size of new image
197 *
198 * Fill the version information into image_info strucrure.
199 *
200 */
201static
202void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_info,
203 struct efi_fw_image *fw_array)
204{
205 u16 varname[13]; /* u"FmpStateXXXX" */
206 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900207 efi_uintn_t size, expected_size;
208 uint num_banks = 1;
209 uint active_index = 0;
210 struct fmp_state *var_state;
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900211
Masahisa Kojima941353c2023-06-07 14:41:54 +0900212 efi_firmware_get_lsv_from_dtb(fw_array->image_index,
213 &fw_array->image_type_id,
214 &image_info->lowest_supported_image_version);
215
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900216 image_info->version_name = NULL; /* not supported */
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900217 image_info->last_attempt_version = 0;
218 image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900219 image_info->version = 0;
220
221 /* get the fw_version */
222 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
223 fw_array->image_index);
224 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
225 ret = fwu_get_active_index(&active_index);
226 if (ret)
227 return;
228
229 num_banks = CONFIG_FWU_NUM_BANKS;
230 }
231
232 size = num_banks * sizeof(*var_state);
233 expected_size = size;
234 var_state = calloc(1, size);
235 if (!var_state)
236 return;
237
238 ret = efi_get_variable_int(varname, &fw_array->image_type_id,
239 NULL, &size, var_state, NULL);
240 if (ret == EFI_SUCCESS && expected_size == size)
241 image_info->version = var_state[active_index].fw_version;
242
243 free(var_state);
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900244}
245
246/**
Caleb Connolly3744e472024-08-30 13:34:33 +0100247 * efi_gen_capsule_guids - generate GUIDs for the images
248 *
249 * Generate the image_type_id for each image in the update_info.images array
250 * using the first compatible from the device tree and a salt
251 * UUID defined at build time.
252 *
253 * Returns: status code
254 */
255static efi_status_t efi_gen_capsule_guids(void)
256{
257 int ret, i;
258 struct uuid namespace;
259 const char *compatible; /* Full array including null bytes */
260 struct efi_fw_image *fw_array;
261
262 fw_array = update_info.images;
263 /* Check if we need to run (there are images and we didn't already generate their IDs) */
264 if (!update_info.num_images ||
265 memchr_inv(&fw_array[0].image_type_id, 0, sizeof(fw_array[0].image_type_id)))
266 return EFI_SUCCESS;
267
268 ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_GUID,
269 (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
270 if (ret) {
271 log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
272 return EFI_INVALID_PARAMETER;
273 }
274
275 compatible = ofnode_read_string(ofnode_root(), "compatible");
276 if (!compatible) {
277 log_debug("%s: model or compatible not defined\n", __func__);
278 return EFI_INVALID_PARAMETER;
279 }
280
281 for (i = 0; i < update_info.num_images; i++) {
Ilias Apalodimas33cfbc02024-12-03 18:13:37 +0200282 if (!fw_array[i].fw_name) {
283 log_err("fw_name is not defined. Not generating capsule GUIDs\n");
284 return EFI_INVALID_PARAMETER;
285 }
Caleb Connolly3744e472024-08-30 13:34:33 +0100286 gen_v5_guid(&namespace,
287 &fw_array[i].image_type_id,
288 compatible, strlen(compatible),
289 fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
290 NULL);
291
292 log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
293 &fw_array[i].image_type_id);
294 }
295
296 return EFI_SUCCESS;
297}
298
299/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530300 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900301 * @image_info_size: Size of @image_info
302 * @image_info: Image information
303 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530304 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900305 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530306 * @package_version: Package version
307 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900308 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530309 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900310 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530311 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900312 *
313 * Return status code
314 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530315static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900316 efi_uintn_t *image_info_size,
317 struct efi_firmware_image_descriptor *image_info,
318 u32 *descriptor_version,
319 u8 *descriptor_count,
320 efi_uintn_t *descriptor_size,
321 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530322 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900323{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530324 size_t total_size;
325 struct efi_fw_image *fw_array;
Caleb Connolly3744e472024-08-30 13:34:33 +0100326 int i, ret;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900327
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900328 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900329
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900330 if (*image_info_size < total_size) {
331 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900332
333 return EFI_BUFFER_TOO_SMALL;
334 }
335 *image_info_size = total_size;
336
Caleb Connolly3744e472024-08-30 13:34:33 +0100337 ret = efi_gen_capsule_guids();
338 if (ret != EFI_SUCCESS)
339 return ret;
340
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530341 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900342 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900343 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900344 *descriptor_size = sizeof(*image_info);
345 *package_version = 0xffffffff; /* not supported */
346 *package_version_name = NULL; /* not supported */
347
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900348 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530349 image_info[i].image_index = fw_array[i].image_index;
350 image_info[i].image_type_id = fw_array[i].image_type_id;
351 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530352 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900353
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900354 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
355
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900356 image_info[i].size = 0;
357 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530358 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
359 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900360 image_info[i].attributes_setting =
361 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530362
363 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530364 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530365 image_info[0].attributes_setting |=
366 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
367
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900368 image_info[i].hardware_instance = 1;
369 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900370 }
371
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900372 return EFI_SUCCESS;
373}
374
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200375/**
376 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
377 * @p_image: Pointer to new image
378 * @p_image_size: Pointer to size of new image
379 *
380 * Authenticate the capsule if authentication is enabled.
381 * The image pointer and the image size are updated in case of success.
382 *
383 * Return: status code
384 */
385static
386efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
387 efi_uintn_t *p_image_size)
388{
389 const void *image = *p_image;
390 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200391 void *capsule_payload;
392 efi_status_t status;
393 efi_uintn_t capsule_payload_size;
394
395 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
396 capsule_payload = NULL;
397 capsule_payload_size = 0;
398 status = efi_capsule_authenticate(image, image_size,
399 &capsule_payload,
400 &capsule_payload_size);
401
402 if (status == EFI_SECURITY_VIOLATION) {
403 printf("Capsule authentication check failed. Aborting update\n");
404 return status;
405 } else if (status != EFI_SUCCESS) {
406 return status;
407 }
408
409 debug("Capsule authentication successful\n");
410 image = capsule_payload;
411 image_size = capsule_payload_size;
412 } else {
413 debug("Capsule authentication disabled. ");
414 debug("Updating capsule without authenticating.\n");
415 }
416
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200417 *p_image = image;
418 *p_image_size = image_size;
419 return EFI_SUCCESS;
420}
421
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900422/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900423 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
424 * @state: Pointer to fmp state
425 * @image_index: image index
426 *
427 * Update the FmpStateXXXX variable with the firmware update state.
428 *
429 * Return: status code
430 */
431static
432efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
433{
434 u16 varname[13]; /* u"FmpStateXXXX" */
435 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900436 uint num_banks = 1;
437 uint update_bank = 0;
438 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900439 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900440 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900441
442 image_type_id = efi_firmware_get_image_type_id(image_index);
443 if (!image_type_id)
444 return EFI_INVALID_PARAMETER;
445
446 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
447 image_index);
448
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900449 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
450 ret = fwu_plat_get_update_index(&update_bank);
451 if (ret)
452 return EFI_INVALID_PARAMETER;
453
454 num_banks = CONFIG_FWU_NUM_BANKS;
455 }
456
457 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900458 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900459 if (!var_state)
460 return EFI_OUT_OF_RESOURCES;
461
462 /*
463 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
464 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900465 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900466 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
467 var_state, NULL);
468 if (ret != EFI_SUCCESS)
469 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900470
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900471 /*
472 * Only the fw_version is set here.
473 * lowest_supported_version in FmpState variable is ignored since
474 * it can be tampered if the file based EFI variable storage is used.
475 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900476 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900477
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900478 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900479 ret = efi_set_variable_int(varname, image_type_id,
480 EFI_VARIABLE_READ_ONLY |
481 EFI_VARIABLE_NON_VOLATILE |
482 EFI_VARIABLE_BOOTSERVICE_ACCESS |
483 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900484 size, var_state, false);
485
486 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900487
488 return ret;
489}
490
491/**
492 * efi_firmware_get_fw_version - get fw_version from FMP payload header
493 * @p_image: Pointer to new image
494 * @p_image_size: Pointer to size of new image
495 * @state: Pointer to fmp state
496 *
497 * Parse the FMP payload header and fill the fmp_state structure.
498 * If no FMP payload header is found, fmp_state structure is not updated.
499 *
500 */
501static void efi_firmware_get_fw_version(const void **p_image,
502 efi_uintn_t *p_image_size,
503 struct fmp_state *state)
504{
505 const struct fmp_payload_header *header;
506 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
507
508 header = *p_image;
509 if (header->signature == fmp_hdr_signature) {
510 /* FMP header is inserted above the capsule payload */
511 state->fw_version = header->fw_version;
512
513 *p_image += header->header_size;
514 *p_image_size -= header->header_size;
515 }
516}
517
518/**
519 * efi_firmware_verify_image - verify image
520 * @p_image: Pointer to new image
521 * @p_image_size: Pointer to size of new image
522 * @image_index: Image index
523 * @state: Pointer to fmp state
524 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900525 * Verify the capsule authentication and check if the fw_version
526 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900527 *
528 * Return: status code
529 */
530static
531efi_status_t efi_firmware_verify_image(const void **p_image,
532 efi_uintn_t *p_image_size,
533 u8 image_index,
534 struct fmp_state *state)
535{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900536 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900537 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900538 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900539
540 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900541 if (ret != EFI_SUCCESS)
542 return ret;
543
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900544 efi_firmware_get_fw_version(p_image, p_image_size, state);
545
Masahisa Kojima94f47802023-06-07 14:41:55 +0900546 image_type_id = efi_firmware_get_image_type_id(image_index);
547 if (!image_type_id)
548 return EFI_INVALID_PARAMETER;
549
550 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
551 if (state->fw_version < lsv) {
552 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
553 state->fw_version, lsv);
554 return EFI_INVALID_PARAMETER;
555 }
556
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900557 return ret;
558}
559
560/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530561 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900562 * firmware image
563 * @this: Protocol instance
564 * @image_info_size: Size of @image_info
565 * @image_info: Image information
566 * @descriptor_version: Pointer to version number
567 * @descriptor_count: Pointer to number of descriptors
568 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200569 * @package_version: Package version
570 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900571 *
572 * Return information bout the current firmware image in @image_info.
573 * @image_info will consist of a number of descriptors.
574 * Each descriptor will be created based on "dfu_alt_info" variable.
575 *
576 * Return status code
577 */
578static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530579efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900580 struct efi_firmware_management_protocol *this,
581 efi_uintn_t *image_info_size,
582 struct efi_firmware_image_descriptor *image_info,
583 u32 *descriptor_version,
584 u8 *descriptor_count,
585 efi_uintn_t *descriptor_size,
586 u32 *package_version,
587 u16 **package_version_name)
588{
589 efi_status_t ret;
590
591 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
592 image_info_size, image_info,
593 descriptor_version, descriptor_count, descriptor_size,
594 package_version, package_version_name);
595
596 if (!image_info_size)
597 return EFI_EXIT(EFI_INVALID_PARAMETER);
598
599 if (*image_info_size &&
600 (!image_info || !descriptor_version || !descriptor_count ||
601 !descriptor_size || !package_version || !package_version_name))
602 return EFI_EXIT(EFI_INVALID_PARAMETER);
603
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530604 ret = efi_fill_image_desc_array(image_info_size, image_info,
605 descriptor_version, descriptor_count,
606 descriptor_size, package_version,
607 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900608
609 return EFI_EXIT(ret);
610}
611
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530612#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
613/*
614 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
615 * method with existing FIT image format, and handles
616 * - multiple regions of firmware via DFU
617 * but doesn't support
618 * - versioning of firmware image
619 * - package information
620 */
621
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900622/**
623 * efi_firmware_fit_set_image - update the firmware image
624 * @this: Protocol instance
625 * @image_index: Image index number
626 * @image: New image
627 * @image_size: Size of new image
628 * @vendor_code: Vendor-specific update policy
629 * @progress: Function to report the progress of update
630 * @abort_reason: Pointer to string of abort reason
631 *
632 * Update the firmware to new image, using dfu. The new image should
633 * have FIT image format commonly used in U-Boot.
634 * @vendor_code, @progress and @abort_reason are not supported.
635 *
636 * Return: status code
637 */
638static
639efi_status_t EFIAPI efi_firmware_fit_set_image(
640 struct efi_firmware_management_protocol *this,
641 u8 image_index,
642 const void *image,
643 efi_uintn_t image_size,
644 const void *vendor_code,
645 efi_status_t (*progress)(efi_uintn_t completion),
646 u16 **abort_reason)
647{
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600648 int ret;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200649 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900650 struct fmp_state state = { 0 };
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600651 char *orig_dfu_env;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200652
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100653 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900654 image_size, vendor_code, progress, abort_reason);
655
656 if (!image || image_index != 1)
657 return EFI_EXIT(EFI_INVALID_PARAMETER);
658
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900659 status = efi_firmware_verify_image(&image, &image_size, image_index,
660 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200661 if (status != EFI_SUCCESS)
662 return EFI_EXIT(status);
663
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600664 orig_dfu_env = env_get("dfu_alt_info");
665 if (orig_dfu_env) {
666 orig_dfu_env = strdup(orig_dfu_env);
667 if (!orig_dfu_env) {
668 log_err("strdup() failed!\n");
669 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
670 }
671 }
672 if (env_set("dfu_alt_info", update_info.dfu_string)) {
673 log_err("Unable to set env variable \"dfu_alt_info\"!\n");
674 free(orig_dfu_env);
675 return EFI_EXIT(EFI_DEVICE_ERROR);
676 }
677
678 ret = fit_update(image);
679
680 if (env_set("dfu_alt_info", orig_dfu_env))
681 log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n");
682
683 free(orig_dfu_env);
684
685 if (ret)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900686 return EFI_EXIT(EFI_DEVICE_ERROR);
687
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900688 efi_firmware_set_fmp_state_var(&state, image_index);
689
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900690 return EFI_EXIT(EFI_SUCCESS);
691}
692
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900693const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530694 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900695 .get_image = efi_firmware_get_image_unsupported,
696 .set_image = efi_firmware_fit_set_image,
697 .check_image = efi_firmware_check_image_unsupported,
698 .get_package_info = efi_firmware_get_package_info_unsupported,
699 .set_package_info = efi_firmware_set_package_info_unsupported,
700};
701#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900702
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900703#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
704/*
705 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
706 * method with raw data.
707 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900708
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900709/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900710 * efi_firmware_raw_set_image - update the firmware image
711 * @this: Protocol instance
712 * @image_index: Image index number
713 * @image: New image
714 * @image_size: Size of new image
715 * @vendor_code: Vendor-specific update policy
716 * @progress: Function to report the progress of update
717 * @abort_reason: Pointer to string of abort reason
718 *
719 * Update the firmware to new image, using dfu. The new image should
720 * be a single raw image.
721 * @vendor_code, @progress and @abort_reason are not supported.
722 *
723 * Return: status code
724 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900725static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900726efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900727 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900728 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900729 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900730 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900731 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900732 efi_status_t (*progress)(efi_uintn_t completion),
733 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900734{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530735 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900736 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530737 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900738 struct fmp_state state = { 0 };
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600739 char *orig_dfu_env;
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530740
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100741 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900742 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900743
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900744 if (!image)
745 return EFI_EXIT(EFI_INVALID_PARAMETER);
746
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900747 status = efi_firmware_verify_image(&image, &image_size, image_index,
748 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200749 if (status != EFI_SUCCESS)
750 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530751
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900752 /*
753 * dfu_alt_num is assigned from 0 while image_index starts from 1.
754 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
755 * is not used.
756 */
757 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530758 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
759 /*
760 * Based on the value of update bank, derive the
761 * image index value.
762 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900763 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530764 if (ret) {
765 log_debug("Unable to get FWU image_index\n");
766 return EFI_EXIT(EFI_DEVICE_ERROR);
767 }
768 }
769
Jonathan Humphreysc0c0f7c2025-02-26 16:35:46 -0600770 orig_dfu_env = env_get("dfu_alt_info");
771 if (orig_dfu_env) {
772 orig_dfu_env = strdup(orig_dfu_env);
773 if (!orig_dfu_env) {
774 log_err("strdup() failed!\n");
775 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
776 }
777 }
778 if (env_set("dfu_alt_info", update_info.dfu_string)) {
779 log_err("Unable to set env variable \"dfu_alt_info\"!\n");
780 free(orig_dfu_env);
781 return EFI_EXIT(EFI_DEVICE_ERROR);
782 }
783
784 ret = dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
785 NULL, NULL);
786
787 if (env_set("dfu_alt_info", orig_dfu_env))
788 log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n");
789
790 free(orig_dfu_env);
791
792 if (ret)
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900793 return EFI_EXIT(EFI_DEVICE_ERROR);
794
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900795 efi_firmware_set_fmp_state_var(&state, image_index);
796
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900797 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900798}
799
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900800const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530801 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900802 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900803 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900804 .check_image = efi_firmware_check_image_unsupported,
805 .get_package_info = efi_firmware_get_package_info_unsupported,
806 .set_package_info = efi_firmware_set_package_info_unsupported,
807};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900808#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */