blob: 5a754c9cd0304d4b77a7e7f3b054c253fb896266 [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
Sughosh Ganua1d9f672022-04-15 11:29:37 +053059__weak void set_dfu_alt_info(char *interface, char *devstr)
60{
61 env_set("dfu_alt_info", update_info.dfu_string);
62}
63
Masahisa Kojima45a18f02023-06-07 14:41:52 +090064/**
65 * efi_firmware_get_image_type_id - get image_type_id
66 * @image_index: image index
67 *
68 * Return the image_type_id identified by the image index.
69 *
70 * Return: pointer to the image_type_id, NULL if image_index is invalid
71 */
72static
73efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
74{
75 int i;
76 struct efi_fw_image *fw_array;
77
78 fw_array = update_info.images;
79 for (i = 0; i < update_info.num_images; i++) {
80 if (fw_array[i].image_index == image_index)
81 return &fw_array[i].image_type_id;
82 }
83
84 return NULL;
85}
86
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +090087/* Place holder; not supported */
88static
89efi_status_t EFIAPI efi_firmware_get_image_unsupported(
90 struct efi_firmware_management_protocol *this,
91 u8 image_index,
92 void *image,
93 efi_uintn_t *image_size)
94{
95 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
96
97 return EFI_EXIT(EFI_UNSUPPORTED);
98}
99
100/* Place holder; not supported */
101static
102efi_status_t EFIAPI efi_firmware_check_image_unsupported(
103 struct efi_firmware_management_protocol *this,
104 u8 image_index,
105 const void *image,
106 efi_uintn_t *image_size,
107 u32 *image_updatable)
108{
109 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
110 image_updatable);
111
112 return EFI_EXIT(EFI_UNSUPPORTED);
113}
114
115/* Place holder; not supported */
116static
117efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
118 struct efi_firmware_management_protocol *this,
119 u32 *package_version,
120 u16 **package_version_name,
121 u32 *package_version_name_maxlen,
122 u64 *attributes_supported,
123 u64 *attributes_setting)
124{
125 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
126 package_version_name, package_version_name_maxlen,
127 attributes_supported, attributes_setting);
128
129 return EFI_EXIT(EFI_UNSUPPORTED);
130}
131
132/* Place holder; not supported */
133static
134efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
135 struct efi_firmware_management_protocol *this,
136 const void *image,
137 efi_uintn_t *image_size,
138 const void *vendor_code,
139 u32 package_version,
140 const u16 *package_version_name)
141{
142 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
143 package_version, package_version_name);
144
145 return EFI_EXIT(EFI_UNSUPPORTED);
146}
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900147
148/**
Masahisa Kojima941353c2023-06-07 14:41:54 +0900149 * efi_firmware_get_lsv_from_dtb - get lowest supported version from dtb
150 * @image_index: Image index
151 * @image_type_id: Image type id
152 * @lsv: Pointer to store the lowest supported version
153 *
154 * Read the firmware version information from dtb.
155 */
156static void efi_firmware_get_lsv_from_dtb(u8 image_index,
157 efi_guid_t *image_type_id, u32 *lsv)
158{
159 const void *fdt = gd->fdt_blob;
160 const fdt32_t *val;
161 const char *guid_str;
162 int len, offset, index;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900163 int parent, ret;
Masahisa Kojima941353c2023-06-07 14:41:54 +0900164
165 *lsv = 0;
166
167 parent = fdt_subnode_offset(fdt, 0, "firmware-version");
168 if (parent < 0)
169 return;
170
171 fdt_for_each_subnode(offset, fdt, parent) {
172 efi_guid_t guid;
173
174 guid_str = fdt_getprop(fdt, offset, "image-type-id", &len);
175 if (!guid_str)
176 continue;
Masahisa Kojima73a5a262023-07-31 17:53:02 +0900177 ret = uuid_str_to_bin(guid_str, guid.b, UUID_STR_FORMAT_GUID);
178 if (ret < 0) {
179 log_warning("Wrong image-type-id format.\n");
180 continue;
181 }
Masahisa Kojima941353c2023-06-07 14:41:54 +0900182
183 val = fdt_getprop(fdt, offset, "image-index", &len);
184 if (!val)
185 continue;
186 index = fdt32_to_cpu(*val);
187
188 if (!guidcmp(&guid, image_type_id) && index == image_index) {
189 val = fdt_getprop(fdt, offset,
190 "lowest-supported-version", &len);
191 if (val)
192 *lsv = fdt32_to_cpu(*val);
193 }
194 }
195}
196
197/**
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900198 * efi_firmware_fill_version_info - fill the version information
199 * @image_info: Image information
200 * @fw_array: Pointer to size of new image
201 *
202 * Fill the version information into image_info strucrure.
203 *
204 */
205static
206void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_info,
207 struct efi_fw_image *fw_array)
208{
209 u16 varname[13]; /* u"FmpStateXXXX" */
210 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900211 efi_uintn_t size, expected_size;
212 uint num_banks = 1;
213 uint active_index = 0;
214 struct fmp_state *var_state;
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900215
Masahisa Kojima941353c2023-06-07 14:41:54 +0900216 efi_firmware_get_lsv_from_dtb(fw_array->image_index,
217 &fw_array->image_type_id,
218 &image_info->lowest_supported_image_version);
219
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900220 image_info->version_name = NULL; /* not supported */
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900221 image_info->last_attempt_version = 0;
222 image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900223 image_info->version = 0;
224
225 /* get the fw_version */
226 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
227 fw_array->image_index);
228 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
229 ret = fwu_get_active_index(&active_index);
230 if (ret)
231 return;
232
233 num_banks = CONFIG_FWU_NUM_BANKS;
234 }
235
236 size = num_banks * sizeof(*var_state);
237 expected_size = size;
238 var_state = calloc(1, size);
239 if (!var_state)
240 return;
241
242 ret = efi_get_variable_int(varname, &fw_array->image_type_id,
243 NULL, &size, var_state, NULL);
244 if (ret == EFI_SUCCESS && expected_size == size)
245 image_info->version = var_state[active_index].fw_version;
246
247 free(var_state);
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900248}
249
250/**
Caleb Connolly3744e472024-08-30 13:34:33 +0100251 * efi_gen_capsule_guids - generate GUIDs for the images
252 *
253 * Generate the image_type_id for each image in the update_info.images array
254 * using the first compatible from the device tree and a salt
255 * UUID defined at build time.
256 *
257 * Returns: status code
258 */
259static efi_status_t efi_gen_capsule_guids(void)
260{
261 int ret, i;
262 struct uuid namespace;
263 const char *compatible; /* Full array including null bytes */
264 struct efi_fw_image *fw_array;
265
266 fw_array = update_info.images;
267 /* Check if we need to run (there are images and we didn't already generate their IDs) */
268 if (!update_info.num_images ||
269 memchr_inv(&fw_array[0].image_type_id, 0, sizeof(fw_array[0].image_type_id)))
270 return EFI_SUCCESS;
271
272 ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_GUID,
273 (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
274 if (ret) {
275 log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
276 return EFI_INVALID_PARAMETER;
277 }
278
279 compatible = ofnode_read_string(ofnode_root(), "compatible");
280 if (!compatible) {
281 log_debug("%s: model or compatible not defined\n", __func__);
282 return EFI_INVALID_PARAMETER;
283 }
284
285 for (i = 0; i < update_info.num_images; i++) {
Ilias Apalodimas33cfbc02024-12-03 18:13:37 +0200286 if (!fw_array[i].fw_name) {
287 log_err("fw_name is not defined. Not generating capsule GUIDs\n");
288 return EFI_INVALID_PARAMETER;
289 }
Caleb Connolly3744e472024-08-30 13:34:33 +0100290 gen_v5_guid(&namespace,
291 &fw_array[i].image_type_id,
292 compatible, strlen(compatible),
293 fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
294 NULL);
295
296 log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
297 &fw_array[i].image_type_id);
298 }
299
300 return EFI_SUCCESS;
301}
302
303/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530304 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900305 * @image_info_size: Size of @image_info
306 * @image_info: Image information
307 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530308 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900309 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530310 * @package_version: Package version
311 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900312 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530313 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900314 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530315 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900316 *
317 * Return status code
318 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530319static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900320 efi_uintn_t *image_info_size,
321 struct efi_firmware_image_descriptor *image_info,
322 u32 *descriptor_version,
323 u8 *descriptor_count,
324 efi_uintn_t *descriptor_size,
325 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530326 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900327{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530328 size_t total_size;
329 struct efi_fw_image *fw_array;
Caleb Connolly3744e472024-08-30 13:34:33 +0100330 int i, ret;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900331
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900332 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900333
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900334 if (*image_info_size < total_size) {
335 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900336
337 return EFI_BUFFER_TOO_SMALL;
338 }
339 *image_info_size = total_size;
340
Caleb Connolly3744e472024-08-30 13:34:33 +0100341 ret = efi_gen_capsule_guids();
342 if (ret != EFI_SUCCESS)
343 return ret;
344
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530345 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900346 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900347 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900348 *descriptor_size = sizeof(*image_info);
349 *package_version = 0xffffffff; /* not supported */
350 *package_version_name = NULL; /* not supported */
351
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900352 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530353 image_info[i].image_index = fw_array[i].image_index;
354 image_info[i].image_type_id = fw_array[i].image_type_id;
355 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530356 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900357
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900358 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
359
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900360 image_info[i].size = 0;
361 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530362 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
363 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900364 image_info[i].attributes_setting =
365 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530366
367 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530368 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530369 image_info[0].attributes_setting |=
370 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
371
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900372 image_info[i].hardware_instance = 1;
373 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900374 }
375
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900376 return EFI_SUCCESS;
377}
378
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200379/**
380 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
381 * @p_image: Pointer to new image
382 * @p_image_size: Pointer to size of new image
383 *
384 * Authenticate the capsule if authentication is enabled.
385 * The image pointer and the image size are updated in case of success.
386 *
387 * Return: status code
388 */
389static
390efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
391 efi_uintn_t *p_image_size)
392{
393 const void *image = *p_image;
394 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200395 void *capsule_payload;
396 efi_status_t status;
397 efi_uintn_t capsule_payload_size;
398
399 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
400 capsule_payload = NULL;
401 capsule_payload_size = 0;
402 status = efi_capsule_authenticate(image, image_size,
403 &capsule_payload,
404 &capsule_payload_size);
405
406 if (status == EFI_SECURITY_VIOLATION) {
407 printf("Capsule authentication check failed. Aborting update\n");
408 return status;
409 } else if (status != EFI_SUCCESS) {
410 return status;
411 }
412
413 debug("Capsule authentication successful\n");
414 image = capsule_payload;
415 image_size = capsule_payload_size;
416 } else {
417 debug("Capsule authentication disabled. ");
418 debug("Updating capsule without authenticating.\n");
419 }
420
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200421 *p_image = image;
422 *p_image_size = image_size;
423 return EFI_SUCCESS;
424}
425
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900426/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900427 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
428 * @state: Pointer to fmp state
429 * @image_index: image index
430 *
431 * Update the FmpStateXXXX variable with the firmware update state.
432 *
433 * Return: status code
434 */
435static
436efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
437{
438 u16 varname[13]; /* u"FmpStateXXXX" */
439 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900440 uint num_banks = 1;
441 uint update_bank = 0;
442 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900443 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900444 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900445
446 image_type_id = efi_firmware_get_image_type_id(image_index);
447 if (!image_type_id)
448 return EFI_INVALID_PARAMETER;
449
450 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
451 image_index);
452
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900453 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
454 ret = fwu_plat_get_update_index(&update_bank);
455 if (ret)
456 return EFI_INVALID_PARAMETER;
457
458 num_banks = CONFIG_FWU_NUM_BANKS;
459 }
460
461 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900462 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900463 if (!var_state)
464 return EFI_OUT_OF_RESOURCES;
465
466 /*
467 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
468 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900469 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900470 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
471 var_state, NULL);
472 if (ret != EFI_SUCCESS)
473 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900474
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900475 /*
476 * Only the fw_version is set here.
477 * lowest_supported_version in FmpState variable is ignored since
478 * it can be tampered if the file based EFI variable storage is used.
479 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900480 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900481
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900482 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900483 ret = efi_set_variable_int(varname, image_type_id,
484 EFI_VARIABLE_READ_ONLY |
485 EFI_VARIABLE_NON_VOLATILE |
486 EFI_VARIABLE_BOOTSERVICE_ACCESS |
487 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900488 size, var_state, false);
489
490 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900491
492 return ret;
493}
494
495/**
496 * efi_firmware_get_fw_version - get fw_version from FMP payload header
497 * @p_image: Pointer to new image
498 * @p_image_size: Pointer to size of new image
499 * @state: Pointer to fmp state
500 *
501 * Parse the FMP payload header and fill the fmp_state structure.
502 * If no FMP payload header is found, fmp_state structure is not updated.
503 *
504 */
505static void efi_firmware_get_fw_version(const void **p_image,
506 efi_uintn_t *p_image_size,
507 struct fmp_state *state)
508{
509 const struct fmp_payload_header *header;
510 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
511
512 header = *p_image;
513 if (header->signature == fmp_hdr_signature) {
514 /* FMP header is inserted above the capsule payload */
515 state->fw_version = header->fw_version;
516
517 *p_image += header->header_size;
518 *p_image_size -= header->header_size;
519 }
520}
521
522/**
523 * efi_firmware_verify_image - verify image
524 * @p_image: Pointer to new image
525 * @p_image_size: Pointer to size of new image
526 * @image_index: Image index
527 * @state: Pointer to fmp state
528 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900529 * Verify the capsule authentication and check if the fw_version
530 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900531 *
532 * Return: status code
533 */
534static
535efi_status_t efi_firmware_verify_image(const void **p_image,
536 efi_uintn_t *p_image_size,
537 u8 image_index,
538 struct fmp_state *state)
539{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900540 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900541 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900542 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900543
544 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900545 if (ret != EFI_SUCCESS)
546 return ret;
547
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900548 efi_firmware_get_fw_version(p_image, p_image_size, state);
549
Masahisa Kojima94f47802023-06-07 14:41:55 +0900550 image_type_id = efi_firmware_get_image_type_id(image_index);
551 if (!image_type_id)
552 return EFI_INVALID_PARAMETER;
553
554 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
555 if (state->fw_version < lsv) {
556 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
557 state->fw_version, lsv);
558 return EFI_INVALID_PARAMETER;
559 }
560
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900561 return ret;
562}
563
564/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530565 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900566 * firmware image
567 * @this: Protocol instance
568 * @image_info_size: Size of @image_info
569 * @image_info: Image information
570 * @descriptor_version: Pointer to version number
571 * @descriptor_count: Pointer to number of descriptors
572 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200573 * @package_version: Package version
574 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900575 *
576 * Return information bout the current firmware image in @image_info.
577 * @image_info will consist of a number of descriptors.
578 * Each descriptor will be created based on "dfu_alt_info" variable.
579 *
580 * Return status code
581 */
582static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530583efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900584 struct efi_firmware_management_protocol *this,
585 efi_uintn_t *image_info_size,
586 struct efi_firmware_image_descriptor *image_info,
587 u32 *descriptor_version,
588 u8 *descriptor_count,
589 efi_uintn_t *descriptor_size,
590 u32 *package_version,
591 u16 **package_version_name)
592{
593 efi_status_t ret;
594
595 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
596 image_info_size, image_info,
597 descriptor_version, descriptor_count, descriptor_size,
598 package_version, package_version_name);
599
600 if (!image_info_size)
601 return EFI_EXIT(EFI_INVALID_PARAMETER);
602
603 if (*image_info_size &&
604 (!image_info || !descriptor_version || !descriptor_count ||
605 !descriptor_size || !package_version || !package_version_name))
606 return EFI_EXIT(EFI_INVALID_PARAMETER);
607
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530608 ret = efi_fill_image_desc_array(image_info_size, image_info,
609 descriptor_version, descriptor_count,
610 descriptor_size, package_version,
611 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900612
613 return EFI_EXIT(ret);
614}
615
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530616#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
617/*
618 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
619 * method with existing FIT image format, and handles
620 * - multiple regions of firmware via DFU
621 * but doesn't support
622 * - versioning of firmware image
623 * - package information
624 */
625
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900626/**
627 * efi_firmware_fit_set_image - update the firmware image
628 * @this: Protocol instance
629 * @image_index: Image index number
630 * @image: New image
631 * @image_size: Size of new image
632 * @vendor_code: Vendor-specific update policy
633 * @progress: Function to report the progress of update
634 * @abort_reason: Pointer to string of abort reason
635 *
636 * Update the firmware to new image, using dfu. The new image should
637 * have FIT image format commonly used in U-Boot.
638 * @vendor_code, @progress and @abort_reason are not supported.
639 *
640 * Return: status code
641 */
642static
643efi_status_t EFIAPI efi_firmware_fit_set_image(
644 struct efi_firmware_management_protocol *this,
645 u8 image_index,
646 const void *image,
647 efi_uintn_t image_size,
648 const void *vendor_code,
649 efi_status_t (*progress)(efi_uintn_t completion),
650 u16 **abort_reason)
651{
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200652 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900653 struct fmp_state state = { 0 };
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200654
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100655 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900656 image_size, vendor_code, progress, abort_reason);
657
658 if (!image || image_index != 1)
659 return EFI_EXIT(EFI_INVALID_PARAMETER);
660
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900661 status = efi_firmware_verify_image(&image, &image_size, image_index,
662 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200663 if (status != EFI_SUCCESS)
664 return EFI_EXIT(status);
665
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900666 if (fit_update(image))
667 return EFI_EXIT(EFI_DEVICE_ERROR);
668
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900669 efi_firmware_set_fmp_state_var(&state, image_index);
670
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900671 return EFI_EXIT(EFI_SUCCESS);
672}
673
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900674const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530675 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900676 .get_image = efi_firmware_get_image_unsupported,
677 .set_image = efi_firmware_fit_set_image,
678 .check_image = efi_firmware_check_image_unsupported,
679 .get_package_info = efi_firmware_get_package_info_unsupported,
680 .set_package_info = efi_firmware_set_package_info_unsupported,
681};
682#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900683
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900684#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
685/*
686 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
687 * method with raw data.
688 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900689
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900690/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900691 * efi_firmware_raw_set_image - update the firmware image
692 * @this: Protocol instance
693 * @image_index: Image index number
694 * @image: New image
695 * @image_size: Size of new image
696 * @vendor_code: Vendor-specific update policy
697 * @progress: Function to report the progress of update
698 * @abort_reason: Pointer to string of abort reason
699 *
700 * Update the firmware to new image, using dfu. The new image should
701 * be a single raw image.
702 * @vendor_code, @progress and @abort_reason are not supported.
703 *
704 * Return: status code
705 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900706static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900707efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900708 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900709 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900710 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900711 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900712 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900713 efi_status_t (*progress)(efi_uintn_t completion),
714 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900715{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530716 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900717 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530718 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900719 struct fmp_state state = { 0 };
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530720
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100721 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900722 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900723
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900724 if (!image)
725 return EFI_EXIT(EFI_INVALID_PARAMETER);
726
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900727 status = efi_firmware_verify_image(&image, &image_size, image_index,
728 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200729 if (status != EFI_SUCCESS)
730 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530731
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900732 /*
733 * dfu_alt_num is assigned from 0 while image_index starts from 1.
734 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
735 * is not used.
736 */
737 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530738 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
739 /*
740 * Based on the value of update bank, derive the
741 * image index value.
742 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900743 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530744 if (ret) {
745 log_debug("Unable to get FWU image_index\n");
746 return EFI_EXIT(EFI_DEVICE_ERROR);
747 }
748 }
749
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900750 if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900751 NULL, NULL))
752 return EFI_EXIT(EFI_DEVICE_ERROR);
753
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900754 efi_firmware_set_fmp_state_var(&state, image_index);
755
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900756 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900757}
758
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900759const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530760 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900761 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900762 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900763 .check_image = efi_firmware_check_image_unsupported,
764 .get_package_info = efi_firmware_get_package_info_unsupported,
765 .set_package_info = efi_firmware_set_package_info_unsupported,
766};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900767#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */