blob: 112775daf4c3ede750ec2069d68163fc476df8e9 [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
AKASHI Takahirof4818e62020-11-30 18:12:12 +09009#include <charset.h>
10#include <dfu.h>
11#include <efi_loader.h>
Masahisa Kojima45a18f02023-06-07 14:41:52 +090012#include <efi_variable.h>
Sughosh Ganu1cadae22022-10-21 18:16:03 +053013#include <fwu.h>
AKASHI Takahirof4818e62020-11-30 18:12:12 +090014#include <image.h>
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053015#include <signatures.h>
16
AKASHI Takahirof4818e62020-11-30 18:12:12 +090017#include <linux/list.h>
18
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053019#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
20
21/**
22 * struct fmp_payload_header - EDK2 header for the FMP payload
23 *
24 * This structure describes the header which is preprended to the
25 * FMP payload by the edk2 capsule generation scripts.
26 *
27 * @signature: Header signature used to identify the header
28 * @header_size: Size of the structure
29 * @fw_version: Firmware versions used
30 * @lowest_supported_version: Lowest supported version
31 */
32struct fmp_payload_header {
33 u32 signature;
34 u32 header_size;
35 u32 fw_version;
36 u32 lowest_supported_version;
37};
38
Masahisa Kojima45a18f02023-06-07 14:41:52 +090039/**
40 * struct fmp_state - fmp firmware update state
41 *
42 * This structure describes the state of the firmware update
43 * through FMP protocol.
44 *
45 * @fw_version: Firmware versions used
46 * @lowest_supported_version: Lowest supported version
47 * @last_attempt_version: Last attempt version
48 * @last_attempt_status: Last attempt status
49 */
50struct fmp_state {
51 u32 fw_version;
52 u32 lowest_supported_version; /* not used */
53 u32 last_attempt_version; /* not used */
54 u32 last_attempt_status; /* not used */
55};
56
Sughosh Ganua1d9f672022-04-15 11:29:37 +053057__weak void set_dfu_alt_info(char *interface, char *devstr)
58{
59 env_set("dfu_alt_info", update_info.dfu_string);
60}
61
Masahisa Kojima45a18f02023-06-07 14:41:52 +090062/**
63 * efi_firmware_get_image_type_id - get image_type_id
64 * @image_index: image index
65 *
66 * Return the image_type_id identified by the image index.
67 *
68 * Return: pointer to the image_type_id, NULL if image_index is invalid
69 */
70static
71efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
72{
73 int i;
74 struct efi_fw_image *fw_array;
75
76 fw_array = update_info.images;
77 for (i = 0; i < update_info.num_images; i++) {
78 if (fw_array[i].image_index == image_index)
79 return &fw_array[i].image_type_id;
80 }
81
82 return NULL;
83}
84
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +090085/* Place holder; not supported */
86static
87efi_status_t EFIAPI efi_firmware_get_image_unsupported(
88 struct efi_firmware_management_protocol *this,
89 u8 image_index,
90 void *image,
91 efi_uintn_t *image_size)
92{
93 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
94
95 return EFI_EXIT(EFI_UNSUPPORTED);
96}
97
98/* Place holder; not supported */
99static
100efi_status_t EFIAPI efi_firmware_check_image_unsupported(
101 struct efi_firmware_management_protocol *this,
102 u8 image_index,
103 const void *image,
104 efi_uintn_t *image_size,
105 u32 *image_updatable)
106{
107 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
108 image_updatable);
109
110 return EFI_EXIT(EFI_UNSUPPORTED);
111}
112
113/* Place holder; not supported */
114static
115efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
116 struct efi_firmware_management_protocol *this,
117 u32 *package_version,
118 u16 **package_version_name,
119 u32 *package_version_name_maxlen,
120 u64 *attributes_supported,
121 u64 *attributes_setting)
122{
123 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
124 package_version_name, package_version_name_maxlen,
125 attributes_supported, attributes_setting);
126
127 return EFI_EXIT(EFI_UNSUPPORTED);
128}
129
130/* Place holder; not supported */
131static
132efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
133 struct efi_firmware_management_protocol *this,
134 const void *image,
135 efi_uintn_t *image_size,
136 const void *vendor_code,
137 u32 package_version,
138 const u16 *package_version_name)
139{
140 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
141 package_version, package_version_name);
142
143 return EFI_EXIT(EFI_UNSUPPORTED);
144}
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900145
146/**
Masahisa Kojima941353c2023-06-07 14:41:54 +0900147 * efi_firmware_get_lsv_from_dtb - get lowest supported version from dtb
148 * @image_index: Image index
149 * @image_type_id: Image type id
150 * @lsv: Pointer to store the lowest supported version
151 *
152 * Read the firmware version information from dtb.
153 */
154static void efi_firmware_get_lsv_from_dtb(u8 image_index,
155 efi_guid_t *image_type_id, u32 *lsv)
156{
157 const void *fdt = gd->fdt_blob;
158 const fdt32_t *val;
159 const char *guid_str;
160 int len, offset, index;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900161 int parent, ret;
Masahisa Kojima941353c2023-06-07 14:41:54 +0900162
163 *lsv = 0;
164
165 parent = fdt_subnode_offset(fdt, 0, "firmware-version");
166 if (parent < 0)
167 return;
168
169 fdt_for_each_subnode(offset, fdt, parent) {
170 efi_guid_t guid;
171
172 guid_str = fdt_getprop(fdt, offset, "image-type-id", &len);
173 if (!guid_str)
174 continue;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900175 ret = uuid_str_to_bin(guid_str, guid.b, UUID_STR_FORMAT_GUID);
176 if (ret < 0) {
177 log_warning("Wrong image-type-id format.\n");
178 continue;
179 }
Masahisa Kojima941353c2023-06-07 14:41:54 +0900180
181 val = fdt_getprop(fdt, offset, "image-index", &len);
182 if (!val)
183 continue;
184 index = fdt32_to_cpu(*val);
185
186 if (!guidcmp(&guid, image_type_id) && index == image_index) {
187 val = fdt_getprop(fdt, offset,
188 "lowest-supported-version", &len);
189 if (val)
190 *lsv = fdt32_to_cpu(*val);
191 }
192 }
193}
194
195/**
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900196 * efi_firmware_fill_version_info - fill the version information
197 * @image_info: Image information
198 * @fw_array: Pointer to size of new image
199 *
200 * Fill the version information into image_info strucrure.
201 *
202 */
203static
204void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_info,
205 struct efi_fw_image *fw_array)
206{
207 u16 varname[13]; /* u"FmpStateXXXX" */
208 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900209 efi_uintn_t size, expected_size;
210 uint num_banks = 1;
211 uint active_index = 0;
212 struct fmp_state *var_state;
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900213
Masahisa Kojima941353c2023-06-07 14:41:54 +0900214 efi_firmware_get_lsv_from_dtb(fw_array->image_index,
215 &fw_array->image_type_id,
216 &image_info->lowest_supported_image_version);
217
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900218 image_info->version_name = NULL; /* not supported */
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900219 image_info->last_attempt_version = 0;
220 image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900221 image_info->version = 0;
222
223 /* get the fw_version */
224 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
225 fw_array->image_index);
226 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
227 ret = fwu_get_active_index(&active_index);
228 if (ret)
229 return;
230
231 num_banks = CONFIG_FWU_NUM_BANKS;
232 }
233
234 size = num_banks * sizeof(*var_state);
235 expected_size = size;
236 var_state = calloc(1, size);
237 if (!var_state)
238 return;
239
240 ret = efi_get_variable_int(varname, &fw_array->image_type_id,
241 NULL, &size, var_state, NULL);
242 if (ret == EFI_SUCCESS && expected_size == size)
243 image_info->version = var_state[active_index].fw_version;
244
245 free(var_state);
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900246}
247
248/**
Caleb Connolly3744e472024-08-30 13:34:33 +0100249 * efi_gen_capsule_guids - generate GUIDs for the images
250 *
251 * Generate the image_type_id for each image in the update_info.images array
252 * using the first compatible from the device tree and a salt
253 * UUID defined at build time.
254 *
255 * Returns: status code
256 */
257static efi_status_t efi_gen_capsule_guids(void)
258{
259 int ret, i;
260 struct uuid namespace;
261 const char *compatible; /* Full array including null bytes */
262 struct efi_fw_image *fw_array;
263
264 fw_array = update_info.images;
265 /* Check if we need to run (there are images and we didn't already generate their IDs) */
266 if (!update_info.num_images ||
267 memchr_inv(&fw_array[0].image_type_id, 0, sizeof(fw_array[0].image_type_id)))
268 return EFI_SUCCESS;
269
270 ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_GUID,
271 (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
272 if (ret) {
273 log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
274 return EFI_INVALID_PARAMETER;
275 }
276
277 compatible = ofnode_read_string(ofnode_root(), "compatible");
278 if (!compatible) {
279 log_debug("%s: model or compatible not defined\n", __func__);
280 return EFI_INVALID_PARAMETER;
281 }
282
283 for (i = 0; i < update_info.num_images; i++) {
Ilias Apalodimas33cfbc02024-12-03 18:13:37 +0200284 if (!fw_array[i].fw_name) {
285 log_err("fw_name is not defined. Not generating capsule GUIDs\n");
286 return EFI_INVALID_PARAMETER;
287 }
Caleb Connolly3744e472024-08-30 13:34:33 +0100288 gen_v5_guid(&namespace,
289 &fw_array[i].image_type_id,
290 compatible, strlen(compatible),
291 fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
292 NULL);
293
294 log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
295 &fw_array[i].image_type_id);
296 }
297
298 return EFI_SUCCESS;
299}
300
301/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530302 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900303 * @image_info_size: Size of @image_info
304 * @image_info: Image information
305 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530306 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900307 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530308 * @package_version: Package version
309 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900310 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530311 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900312 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530313 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900314 *
315 * Return status code
316 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530317static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900318 efi_uintn_t *image_info_size,
319 struct efi_firmware_image_descriptor *image_info,
320 u32 *descriptor_version,
321 u8 *descriptor_count,
322 efi_uintn_t *descriptor_size,
323 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530324 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900325{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530326 size_t total_size;
327 struct efi_fw_image *fw_array;
Caleb Connolly3744e472024-08-30 13:34:33 +0100328 int i, ret;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900329
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900330 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900331
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900332 if (*image_info_size < total_size) {
333 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900334
335 return EFI_BUFFER_TOO_SMALL;
336 }
337 *image_info_size = total_size;
338
Caleb Connolly3744e472024-08-30 13:34:33 +0100339 ret = efi_gen_capsule_guids();
340 if (ret != EFI_SUCCESS)
341 return ret;
342
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530343 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900344 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900345 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900346 *descriptor_size = sizeof(*image_info);
347 *package_version = 0xffffffff; /* not supported */
348 *package_version_name = NULL; /* not supported */
349
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900350 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530351 image_info[i].image_index = fw_array[i].image_index;
352 image_info[i].image_type_id = fw_array[i].image_type_id;
353 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530354 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900355
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900356 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
357
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900358 image_info[i].size = 0;
359 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530360 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
361 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900362 image_info[i].attributes_setting =
363 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530364
365 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530366 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530367 image_info[0].attributes_setting |=
368 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
369
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900370 image_info[i].hardware_instance = 1;
371 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900372 }
373
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900374 return EFI_SUCCESS;
375}
376
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200377/**
378 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
379 * @p_image: Pointer to new image
380 * @p_image_size: Pointer to size of new image
381 *
382 * Authenticate the capsule if authentication is enabled.
383 * The image pointer and the image size are updated in case of success.
384 *
385 * Return: status code
386 */
387static
388efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
389 efi_uintn_t *p_image_size)
390{
391 const void *image = *p_image;
392 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200393 void *capsule_payload;
394 efi_status_t status;
395 efi_uintn_t capsule_payload_size;
396
397 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
398 capsule_payload = NULL;
399 capsule_payload_size = 0;
400 status = efi_capsule_authenticate(image, image_size,
401 &capsule_payload,
402 &capsule_payload_size);
403
404 if (status == EFI_SECURITY_VIOLATION) {
405 printf("Capsule authentication check failed. Aborting update\n");
406 return status;
407 } else if (status != EFI_SUCCESS) {
408 return status;
409 }
410
411 debug("Capsule authentication successful\n");
412 image = capsule_payload;
413 image_size = capsule_payload_size;
414 } else {
415 debug("Capsule authentication disabled. ");
416 debug("Updating capsule without authenticating.\n");
417 }
418
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200419 *p_image = image;
420 *p_image_size = image_size;
421 return EFI_SUCCESS;
422}
423
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900424/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900425 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
426 * @state: Pointer to fmp state
427 * @image_index: image index
428 *
429 * Update the FmpStateXXXX variable with the firmware update state.
430 *
431 * Return: status code
432 */
433static
434efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
435{
436 u16 varname[13]; /* u"FmpStateXXXX" */
437 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900438 uint num_banks = 1;
439 uint update_bank = 0;
440 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900441 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900442 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900443
444 image_type_id = efi_firmware_get_image_type_id(image_index);
445 if (!image_type_id)
446 return EFI_INVALID_PARAMETER;
447
448 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
449 image_index);
450
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900451 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
452 ret = fwu_plat_get_update_index(&update_bank);
453 if (ret)
454 return EFI_INVALID_PARAMETER;
455
456 num_banks = CONFIG_FWU_NUM_BANKS;
457 }
458
459 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900460 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900461 if (!var_state)
462 return EFI_OUT_OF_RESOURCES;
463
464 /*
465 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
466 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900467 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900468 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
469 var_state, NULL);
470 if (ret != EFI_SUCCESS)
471 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900472
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900473 /*
474 * Only the fw_version is set here.
475 * lowest_supported_version in FmpState variable is ignored since
476 * it can be tampered if the file based EFI variable storage is used.
477 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900478 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900479
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900480 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900481 ret = efi_set_variable_int(varname, image_type_id,
482 EFI_VARIABLE_READ_ONLY |
483 EFI_VARIABLE_NON_VOLATILE |
484 EFI_VARIABLE_BOOTSERVICE_ACCESS |
485 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900486 size, var_state, false);
487
488 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900489
490 return ret;
491}
492
493/**
494 * efi_firmware_get_fw_version - get fw_version from FMP payload header
495 * @p_image: Pointer to new image
496 * @p_image_size: Pointer to size of new image
497 * @state: Pointer to fmp state
498 *
499 * Parse the FMP payload header and fill the fmp_state structure.
500 * If no FMP payload header is found, fmp_state structure is not updated.
501 *
502 */
503static void efi_firmware_get_fw_version(const void **p_image,
504 efi_uintn_t *p_image_size,
505 struct fmp_state *state)
506{
507 const struct fmp_payload_header *header;
508 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
509
510 header = *p_image;
511 if (header->signature == fmp_hdr_signature) {
512 /* FMP header is inserted above the capsule payload */
513 state->fw_version = header->fw_version;
514
515 *p_image += header->header_size;
516 *p_image_size -= header->header_size;
517 }
518}
519
520/**
521 * efi_firmware_verify_image - verify image
522 * @p_image: Pointer to new image
523 * @p_image_size: Pointer to size of new image
524 * @image_index: Image index
525 * @state: Pointer to fmp state
526 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900527 * Verify the capsule authentication and check if the fw_version
528 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900529 *
530 * Return: status code
531 */
532static
533efi_status_t efi_firmware_verify_image(const void **p_image,
534 efi_uintn_t *p_image_size,
535 u8 image_index,
536 struct fmp_state *state)
537{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900538 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900539 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900540 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900541
542 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900543 if (ret != EFI_SUCCESS)
544 return ret;
545
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900546 efi_firmware_get_fw_version(p_image, p_image_size, state);
547
Masahisa Kojima94f47802023-06-07 14:41:55 +0900548 image_type_id = efi_firmware_get_image_type_id(image_index);
549 if (!image_type_id)
550 return EFI_INVALID_PARAMETER;
551
552 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
553 if (state->fw_version < lsv) {
554 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
555 state->fw_version, lsv);
556 return EFI_INVALID_PARAMETER;
557 }
558
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900559 return ret;
560}
561
562/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530563 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900564 * firmware image
565 * @this: Protocol instance
566 * @image_info_size: Size of @image_info
567 * @image_info: Image information
568 * @descriptor_version: Pointer to version number
569 * @descriptor_count: Pointer to number of descriptors
570 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200571 * @package_version: Package version
572 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900573 *
574 * Return information bout the current firmware image in @image_info.
575 * @image_info will consist of a number of descriptors.
576 * Each descriptor will be created based on "dfu_alt_info" variable.
577 *
578 * Return status code
579 */
580static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530581efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900582 struct efi_firmware_management_protocol *this,
583 efi_uintn_t *image_info_size,
584 struct efi_firmware_image_descriptor *image_info,
585 u32 *descriptor_version,
586 u8 *descriptor_count,
587 efi_uintn_t *descriptor_size,
588 u32 *package_version,
589 u16 **package_version_name)
590{
591 efi_status_t ret;
592
593 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
594 image_info_size, image_info,
595 descriptor_version, descriptor_count, descriptor_size,
596 package_version, package_version_name);
597
598 if (!image_info_size)
599 return EFI_EXIT(EFI_INVALID_PARAMETER);
600
601 if (*image_info_size &&
602 (!image_info || !descriptor_version || !descriptor_count ||
603 !descriptor_size || !package_version || !package_version_name))
604 return EFI_EXIT(EFI_INVALID_PARAMETER);
605
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530606 ret = efi_fill_image_desc_array(image_info_size, image_info,
607 descriptor_version, descriptor_count,
608 descriptor_size, package_version,
609 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900610
611 return EFI_EXIT(ret);
612}
613
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530614#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
615/*
616 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
617 * method with existing FIT image format, and handles
618 * - multiple regions of firmware via DFU
619 * but doesn't support
620 * - versioning of firmware image
621 * - package information
622 */
623
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900624/**
625 * efi_firmware_fit_set_image - update the firmware image
626 * @this: Protocol instance
627 * @image_index: Image index number
628 * @image: New image
629 * @image_size: Size of new image
630 * @vendor_code: Vendor-specific update policy
631 * @progress: Function to report the progress of update
632 * @abort_reason: Pointer to string of abort reason
633 *
634 * Update the firmware to new image, using dfu. The new image should
635 * have FIT image format commonly used in U-Boot.
636 * @vendor_code, @progress and @abort_reason are not supported.
637 *
638 * Return: status code
639 */
640static
641efi_status_t EFIAPI efi_firmware_fit_set_image(
642 struct efi_firmware_management_protocol *this,
643 u8 image_index,
644 const void *image,
645 efi_uintn_t image_size,
646 const void *vendor_code,
647 efi_status_t (*progress)(efi_uintn_t completion),
648 u16 **abort_reason)
649{
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200650 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900651 struct fmp_state state = { 0 };
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
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900664 if (fit_update(image))
665 return EFI_EXIT(EFI_DEVICE_ERROR);
666
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900667 efi_firmware_set_fmp_state_var(&state, image_index);
668
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900669 return EFI_EXIT(EFI_SUCCESS);
670}
671
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900672const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530673 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900674 .get_image = efi_firmware_get_image_unsupported,
675 .set_image = efi_firmware_fit_set_image,
676 .check_image = efi_firmware_check_image_unsupported,
677 .get_package_info = efi_firmware_get_package_info_unsupported,
678 .set_package_info = efi_firmware_set_package_info_unsupported,
679};
680#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900681
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900682#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
683/*
684 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
685 * method with raw data.
686 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900687
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900688/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900689 * efi_firmware_raw_set_image - update the firmware image
690 * @this: Protocol instance
691 * @image_index: Image index number
692 * @image: New image
693 * @image_size: Size of new image
694 * @vendor_code: Vendor-specific update policy
695 * @progress: Function to report the progress of update
696 * @abort_reason: Pointer to string of abort reason
697 *
698 * Update the firmware to new image, using dfu. The new image should
699 * be a single raw image.
700 * @vendor_code, @progress and @abort_reason are not supported.
701 *
702 * Return: status code
703 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900704static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900705efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900706 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900707 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900708 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900709 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900710 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900711 efi_status_t (*progress)(efi_uintn_t completion),
712 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900713{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530714 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900715 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530716 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900717 struct fmp_state state = { 0 };
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530718
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100719 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900720 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900721
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900722 if (!image)
723 return EFI_EXIT(EFI_INVALID_PARAMETER);
724
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900725 status = efi_firmware_verify_image(&image, &image_size, image_index,
726 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200727 if (status != EFI_SUCCESS)
728 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530729
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900730 /*
731 * dfu_alt_num is assigned from 0 while image_index starts from 1.
732 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
733 * is not used.
734 */
735 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530736 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
737 /*
738 * Based on the value of update bank, derive the
739 * image index value.
740 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900741 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530742 if (ret) {
743 log_debug("Unable to get FWU image_index\n");
744 return EFI_EXIT(EFI_DEVICE_ERROR);
745 }
746 }
747
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900748 if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900749 NULL, NULL))
750 return EFI_EXIT(EFI_DEVICE_ERROR);
751
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900752 efi_firmware_set_fmp_state_var(&state, image_index);
753
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900754 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900755}
756
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900757const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530758 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900759 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900760 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900761 .check_image = efi_firmware_check_image_unsupported,
762 .get_package_info = efi_firmware_get_package_info_unsupported,
763 .set_package_info = efi_firmware_set_package_info_unsupported,
764};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900765#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */