blob: 6650c2b8071def7bab88beacae84ee046b8795d0 [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++) {
284 gen_v5_guid(&namespace,
285 &fw_array[i].image_type_id,
286 compatible, strlen(compatible),
287 fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
288 NULL);
289
290 log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
291 &fw_array[i].image_type_id);
292 }
293
294 return EFI_SUCCESS;
295}
296
297/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530298 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900299 * @image_info_size: Size of @image_info
300 * @image_info: Image information
301 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530302 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900303 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530304 * @package_version: Package version
305 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900306 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530307 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900308 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530309 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900310 *
311 * Return status code
312 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530313static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900314 efi_uintn_t *image_info_size,
315 struct efi_firmware_image_descriptor *image_info,
316 u32 *descriptor_version,
317 u8 *descriptor_count,
318 efi_uintn_t *descriptor_size,
319 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530320 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900321{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530322 size_t total_size;
323 struct efi_fw_image *fw_array;
Caleb Connolly3744e472024-08-30 13:34:33 +0100324 int i, ret;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900325
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900326 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900327
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900328 if (*image_info_size < total_size) {
329 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900330
331 return EFI_BUFFER_TOO_SMALL;
332 }
333 *image_info_size = total_size;
334
Caleb Connolly3744e472024-08-30 13:34:33 +0100335 ret = efi_gen_capsule_guids();
336 if (ret != EFI_SUCCESS)
337 return ret;
338
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530339 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900340 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900341 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900342 *descriptor_size = sizeof(*image_info);
343 *package_version = 0xffffffff; /* not supported */
344 *package_version_name = NULL; /* not supported */
345
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900346 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530347 image_info[i].image_index = fw_array[i].image_index;
348 image_info[i].image_type_id = fw_array[i].image_type_id;
349 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530350 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900351
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900352 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
353
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900354 image_info[i].size = 0;
355 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530356 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
357 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900358 image_info[i].attributes_setting =
359 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530360
361 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530362 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530363 image_info[0].attributes_setting |=
364 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
365
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900366 image_info[i].hardware_instance = 1;
367 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900368 }
369
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900370 return EFI_SUCCESS;
371}
372
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200373/**
374 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
375 * @p_image: Pointer to new image
376 * @p_image_size: Pointer to size of new image
377 *
378 * Authenticate the capsule if authentication is enabled.
379 * The image pointer and the image size are updated in case of success.
380 *
381 * Return: status code
382 */
383static
384efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
385 efi_uintn_t *p_image_size)
386{
387 const void *image = *p_image;
388 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200389 void *capsule_payload;
390 efi_status_t status;
391 efi_uintn_t capsule_payload_size;
392
393 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
394 capsule_payload = NULL;
395 capsule_payload_size = 0;
396 status = efi_capsule_authenticate(image, image_size,
397 &capsule_payload,
398 &capsule_payload_size);
399
400 if (status == EFI_SECURITY_VIOLATION) {
401 printf("Capsule authentication check failed. Aborting update\n");
402 return status;
403 } else if (status != EFI_SUCCESS) {
404 return status;
405 }
406
407 debug("Capsule authentication successful\n");
408 image = capsule_payload;
409 image_size = capsule_payload_size;
410 } else {
411 debug("Capsule authentication disabled. ");
412 debug("Updating capsule without authenticating.\n");
413 }
414
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200415 *p_image = image;
416 *p_image_size = image_size;
417 return EFI_SUCCESS;
418}
419
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900420/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900421 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
422 * @state: Pointer to fmp state
423 * @image_index: image index
424 *
425 * Update the FmpStateXXXX variable with the firmware update state.
426 *
427 * Return: status code
428 */
429static
430efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
431{
432 u16 varname[13]; /* u"FmpStateXXXX" */
433 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900434 uint num_banks = 1;
435 uint update_bank = 0;
436 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900437 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900438 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900439
440 image_type_id = efi_firmware_get_image_type_id(image_index);
441 if (!image_type_id)
442 return EFI_INVALID_PARAMETER;
443
444 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
445 image_index);
446
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900447 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
448 ret = fwu_plat_get_update_index(&update_bank);
449 if (ret)
450 return EFI_INVALID_PARAMETER;
451
452 num_banks = CONFIG_FWU_NUM_BANKS;
453 }
454
455 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900456 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900457 if (!var_state)
458 return EFI_OUT_OF_RESOURCES;
459
460 /*
461 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
462 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900463 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900464 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
465 var_state, NULL);
466 if (ret != EFI_SUCCESS)
467 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900468
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900469 /*
470 * Only the fw_version is set here.
471 * lowest_supported_version in FmpState variable is ignored since
472 * it can be tampered if the file based EFI variable storage is used.
473 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900474 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900475
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900476 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900477 ret = efi_set_variable_int(varname, image_type_id,
478 EFI_VARIABLE_READ_ONLY |
479 EFI_VARIABLE_NON_VOLATILE |
480 EFI_VARIABLE_BOOTSERVICE_ACCESS |
481 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900482 size, var_state, false);
483
484 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900485
486 return ret;
487}
488
489/**
490 * efi_firmware_get_fw_version - get fw_version from FMP payload header
491 * @p_image: Pointer to new image
492 * @p_image_size: Pointer to size of new image
493 * @state: Pointer to fmp state
494 *
495 * Parse the FMP payload header and fill the fmp_state structure.
496 * If no FMP payload header is found, fmp_state structure is not updated.
497 *
498 */
499static void efi_firmware_get_fw_version(const void **p_image,
500 efi_uintn_t *p_image_size,
501 struct fmp_state *state)
502{
503 const struct fmp_payload_header *header;
504 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
505
506 header = *p_image;
507 if (header->signature == fmp_hdr_signature) {
508 /* FMP header is inserted above the capsule payload */
509 state->fw_version = header->fw_version;
510
511 *p_image += header->header_size;
512 *p_image_size -= header->header_size;
513 }
514}
515
516/**
517 * efi_firmware_verify_image - verify image
518 * @p_image: Pointer to new image
519 * @p_image_size: Pointer to size of new image
520 * @image_index: Image index
521 * @state: Pointer to fmp state
522 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900523 * Verify the capsule authentication and check if the fw_version
524 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900525 *
526 * Return: status code
527 */
528static
529efi_status_t efi_firmware_verify_image(const void **p_image,
530 efi_uintn_t *p_image_size,
531 u8 image_index,
532 struct fmp_state *state)
533{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900534 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900535 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900536 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900537
538 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900539 if (ret != EFI_SUCCESS)
540 return ret;
541
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900542 efi_firmware_get_fw_version(p_image, p_image_size, state);
543
Masahisa Kojima94f47802023-06-07 14:41:55 +0900544 image_type_id = efi_firmware_get_image_type_id(image_index);
545 if (!image_type_id)
546 return EFI_INVALID_PARAMETER;
547
548 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
549 if (state->fw_version < lsv) {
550 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
551 state->fw_version, lsv);
552 return EFI_INVALID_PARAMETER;
553 }
554
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900555 return ret;
556}
557
558/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530559 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900560 * firmware image
561 * @this: Protocol instance
562 * @image_info_size: Size of @image_info
563 * @image_info: Image information
564 * @descriptor_version: Pointer to version number
565 * @descriptor_count: Pointer to number of descriptors
566 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200567 * @package_version: Package version
568 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900569 *
570 * Return information bout the current firmware image in @image_info.
571 * @image_info will consist of a number of descriptors.
572 * Each descriptor will be created based on "dfu_alt_info" variable.
573 *
574 * Return status code
575 */
576static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530577efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900578 struct efi_firmware_management_protocol *this,
579 efi_uintn_t *image_info_size,
580 struct efi_firmware_image_descriptor *image_info,
581 u32 *descriptor_version,
582 u8 *descriptor_count,
583 efi_uintn_t *descriptor_size,
584 u32 *package_version,
585 u16 **package_version_name)
586{
587 efi_status_t ret;
588
589 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
590 image_info_size, image_info,
591 descriptor_version, descriptor_count, descriptor_size,
592 package_version, package_version_name);
593
594 if (!image_info_size)
595 return EFI_EXIT(EFI_INVALID_PARAMETER);
596
597 if (*image_info_size &&
598 (!image_info || !descriptor_version || !descriptor_count ||
599 !descriptor_size || !package_version || !package_version_name))
600 return EFI_EXIT(EFI_INVALID_PARAMETER);
601
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530602 ret = efi_fill_image_desc_array(image_info_size, image_info,
603 descriptor_version, descriptor_count,
604 descriptor_size, package_version,
605 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900606
607 return EFI_EXIT(ret);
608}
609
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530610#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
611/*
612 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
613 * method with existing FIT image format, and handles
614 * - multiple regions of firmware via DFU
615 * but doesn't support
616 * - versioning of firmware image
617 * - package information
618 */
619
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900620/**
621 * efi_firmware_fit_set_image - update the firmware image
622 * @this: Protocol instance
623 * @image_index: Image index number
624 * @image: New image
625 * @image_size: Size of new image
626 * @vendor_code: Vendor-specific update policy
627 * @progress: Function to report the progress of update
628 * @abort_reason: Pointer to string of abort reason
629 *
630 * Update the firmware to new image, using dfu. The new image should
631 * have FIT image format commonly used in U-Boot.
632 * @vendor_code, @progress and @abort_reason are not supported.
633 *
634 * Return: status code
635 */
636static
637efi_status_t EFIAPI efi_firmware_fit_set_image(
638 struct efi_firmware_management_protocol *this,
639 u8 image_index,
640 const void *image,
641 efi_uintn_t image_size,
642 const void *vendor_code,
643 efi_status_t (*progress)(efi_uintn_t completion),
644 u16 **abort_reason)
645{
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200646 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900647 struct fmp_state state = { 0 };
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200648
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100649 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900650 image_size, vendor_code, progress, abort_reason);
651
652 if (!image || image_index != 1)
653 return EFI_EXIT(EFI_INVALID_PARAMETER);
654
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900655 status = efi_firmware_verify_image(&image, &image_size, image_index,
656 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200657 if (status != EFI_SUCCESS)
658 return EFI_EXIT(status);
659
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900660 if (fit_update(image))
661 return EFI_EXIT(EFI_DEVICE_ERROR);
662
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900663 efi_firmware_set_fmp_state_var(&state, image_index);
664
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900665 return EFI_EXIT(EFI_SUCCESS);
666}
667
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900668const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530669 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900670 .get_image = efi_firmware_get_image_unsupported,
671 .set_image = efi_firmware_fit_set_image,
672 .check_image = efi_firmware_check_image_unsupported,
673 .get_package_info = efi_firmware_get_package_info_unsupported,
674 .set_package_info = efi_firmware_set_package_info_unsupported,
675};
676#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900677
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900678#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
679/*
680 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
681 * method with raw data.
682 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900683
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900684/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900685 * efi_firmware_raw_set_image - update the firmware image
686 * @this: Protocol instance
687 * @image_index: Image index number
688 * @image: New image
689 * @image_size: Size of new image
690 * @vendor_code: Vendor-specific update policy
691 * @progress: Function to report the progress of update
692 * @abort_reason: Pointer to string of abort reason
693 *
694 * Update the firmware to new image, using dfu. The new image should
695 * be a single raw image.
696 * @vendor_code, @progress and @abort_reason are not supported.
697 *
698 * Return: status code
699 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900700static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900701efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900702 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900703 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900704 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900705 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900706 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900707 efi_status_t (*progress)(efi_uintn_t completion),
708 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900709{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530710 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900711 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530712 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900713 struct fmp_state state = { 0 };
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530714
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100715 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900716 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900717
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900718 if (!image)
719 return EFI_EXIT(EFI_INVALID_PARAMETER);
720
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900721 status = efi_firmware_verify_image(&image, &image_size, image_index,
722 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200723 if (status != EFI_SUCCESS)
724 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530725
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900726 /*
727 * dfu_alt_num is assigned from 0 while image_index starts from 1.
728 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
729 * is not used.
730 */
731 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530732 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
733 /*
734 * Based on the value of update bank, derive the
735 * image index value.
736 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900737 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530738 if (ret) {
739 log_debug("Unable to get FWU image_index\n");
740 return EFI_EXIT(EFI_DEVICE_ERROR);
741 }
742 }
743
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900744 if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900745 NULL, NULL))
746 return EFI_EXIT(EFI_DEVICE_ERROR);
747
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900748 efi_firmware_set_fmp_state_var(&state, image_index);
749
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900750 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900751}
752
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900753const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530754 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900755 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900756 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900757 .check_image = efi_firmware_check_image_unsupported,
758 .get_package_info = efi_firmware_get_package_info_unsupported,
759 .set_package_info = efi_firmware_set_package_info_unsupported,
760};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900761#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */