blob: ba5aba098c0fcac04b5ecb46c76627953c4b6381 [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/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530249 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900250 * @image_info_size: Size of @image_info
251 * @image_info: Image information
252 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530253 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900254 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530255 * @package_version: Package version
256 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900257 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530258 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900259 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530260 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900261 *
262 * Return status code
263 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530264static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900265 efi_uintn_t *image_info_size,
266 struct efi_firmware_image_descriptor *image_info,
267 u32 *descriptor_version,
268 u8 *descriptor_count,
269 efi_uintn_t *descriptor_size,
270 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530271 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900272{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530273 size_t total_size;
274 struct efi_fw_image *fw_array;
275 int i;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900276
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900277 total_size = sizeof(*image_info) * update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900278
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900279 if (*image_info_size < total_size) {
280 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900281
282 return EFI_BUFFER_TOO_SMALL;
283 }
284 *image_info_size = total_size;
285
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530286 fw_array = update_info.images;
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900287 *descriptor_count = update_info.num_images;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900288 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900289 *descriptor_size = sizeof(*image_info);
290 *package_version = 0xffffffff; /* not supported */
291 *package_version_name = NULL; /* not supported */
292
Masahisa Kojima5d2438b2023-06-07 14:41:51 +0900293 for (i = 0; i < update_info.num_images; i++) {
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530294 image_info[i].image_index = fw_array[i].image_index;
295 image_info[i].image_type_id = fw_array[i].image_type_id;
296 image_info[i].image_id = fw_array[i].image_index;
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530297 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900298
Masahisa Kojimaff96fa12023-06-07 14:41:53 +0900299 efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
300
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900301 image_info[i].size = 0;
302 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530303 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
304 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900305 image_info[i].attributes_setting =
306 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530307
308 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530309 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530310 image_info[0].attributes_setting |=
311 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
312
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900313 image_info[i].hardware_instance = 1;
314 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900315 }
316
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900317 return EFI_SUCCESS;
318}
319
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200320/**
321 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
322 * @p_image: Pointer to new image
323 * @p_image_size: Pointer to size of new image
324 *
325 * Authenticate the capsule if authentication is enabled.
326 * The image pointer and the image size are updated in case of success.
327 *
328 * Return: status code
329 */
330static
331efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
332 efi_uintn_t *p_image_size)
333{
334 const void *image = *p_image;
335 efi_uintn_t image_size = *p_image_size;
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200336 void *capsule_payload;
337 efi_status_t status;
338 efi_uintn_t capsule_payload_size;
339
340 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
341 capsule_payload = NULL;
342 capsule_payload_size = 0;
343 status = efi_capsule_authenticate(image, image_size,
344 &capsule_payload,
345 &capsule_payload_size);
346
347 if (status == EFI_SECURITY_VIOLATION) {
348 printf("Capsule authentication check failed. Aborting update\n");
349 return status;
350 } else if (status != EFI_SUCCESS) {
351 return status;
352 }
353
354 debug("Capsule authentication successful\n");
355 image = capsule_payload;
356 image_size = capsule_payload_size;
357 } else {
358 debug("Capsule authentication disabled. ");
359 debug("Updating capsule without authenticating.\n");
360 }
361
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200362 *p_image = image;
363 *p_image_size = image_size;
364 return EFI_SUCCESS;
365}
366
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900367/**
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900368 * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
369 * @state: Pointer to fmp state
370 * @image_index: image index
371 *
372 * Update the FmpStateXXXX variable with the firmware update state.
373 *
374 * Return: status code
375 */
376static
377efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
378{
379 u16 varname[13]; /* u"FmpStateXXXX" */
380 efi_status_t ret;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900381 uint num_banks = 1;
382 uint update_bank = 0;
383 efi_uintn_t size;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900384 efi_guid_t *image_type_id;
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900385 struct fmp_state *var_state;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900386
387 image_type_id = efi_firmware_get_image_type_id(image_index);
388 if (!image_type_id)
389 return EFI_INVALID_PARAMETER;
390
391 efi_create_indexed_name(varname, sizeof(varname), "FmpState",
392 image_index);
393
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900394 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
395 ret = fwu_plat_get_update_index(&update_bank);
396 if (ret)
397 return EFI_INVALID_PARAMETER;
398
399 num_banks = CONFIG_FWU_NUM_BANKS;
400 }
401
402 size = num_banks * sizeof(*var_state);
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900403 var_state = malloc(size);
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900404 if (!var_state)
405 return EFI_OUT_OF_RESOURCES;
406
407 /*
408 * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
409 * variable has not been set yet.
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900410 */
Masahisa Kojima6187c7c2024-01-29 11:51:14 +0900411 ret = efi_get_variable_int(varname, image_type_id, NULL, &size,
412 var_state, NULL);
413 if (ret != EFI_SUCCESS)
414 memset(var_state, 0, num_banks * sizeof(*var_state));
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900415
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900416 /*
417 * Only the fw_version is set here.
418 * lowest_supported_version in FmpState variable is ignored since
419 * it can be tampered if the file based EFI variable storage is used.
420 */
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900421 var_state[update_bank].fw_version = state->fw_version;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900422
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900423 size = num_banks * sizeof(*var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900424 ret = efi_set_variable_int(varname, image_type_id,
425 EFI_VARIABLE_READ_ONLY |
426 EFI_VARIABLE_NON_VOLATILE |
427 EFI_VARIABLE_BOOTSERVICE_ACCESS |
428 EFI_VARIABLE_RUNTIME_ACCESS,
Masahisa Kojimac6319bd2024-01-11 14:35:40 +0900429 size, var_state, false);
430
431 free(var_state);
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900432
433 return ret;
434}
435
436/**
437 * efi_firmware_get_fw_version - get fw_version from FMP payload header
438 * @p_image: Pointer to new image
439 * @p_image_size: Pointer to size of new image
440 * @state: Pointer to fmp state
441 *
442 * Parse the FMP payload header and fill the fmp_state structure.
443 * If no FMP payload header is found, fmp_state structure is not updated.
444 *
445 */
446static void efi_firmware_get_fw_version(const void **p_image,
447 efi_uintn_t *p_image_size,
448 struct fmp_state *state)
449{
450 const struct fmp_payload_header *header;
451 u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
452
453 header = *p_image;
454 if (header->signature == fmp_hdr_signature) {
455 /* FMP header is inserted above the capsule payload */
456 state->fw_version = header->fw_version;
457
458 *p_image += header->header_size;
459 *p_image_size -= header->header_size;
460 }
461}
462
463/**
464 * efi_firmware_verify_image - verify image
465 * @p_image: Pointer to new image
466 * @p_image_size: Pointer to size of new image
467 * @image_index: Image index
468 * @state: Pointer to fmp state
469 *
Masahisa Kojima94f47802023-06-07 14:41:55 +0900470 * Verify the capsule authentication and check if the fw_version
471 * is equal or greater than the lowest supported version.
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900472 *
473 * Return: status code
474 */
475static
476efi_status_t efi_firmware_verify_image(const void **p_image,
477 efi_uintn_t *p_image_size,
478 u8 image_index,
479 struct fmp_state *state)
480{
Masahisa Kojima94f47802023-06-07 14:41:55 +0900481 u32 lsv;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900482 efi_status_t ret;
Masahisa Kojima94f47802023-06-07 14:41:55 +0900483 efi_guid_t *image_type_id;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900484
485 ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
Masahisa Kojima94f47802023-06-07 14:41:55 +0900486 if (ret != EFI_SUCCESS)
487 return ret;
488
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900489 efi_firmware_get_fw_version(p_image, p_image_size, state);
490
Masahisa Kojima94f47802023-06-07 14:41:55 +0900491 image_type_id = efi_firmware_get_image_type_id(image_index);
492 if (!image_type_id)
493 return EFI_INVALID_PARAMETER;
494
495 efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
496 if (state->fw_version < lsv) {
497 log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
498 state->fw_version, lsv);
499 return EFI_INVALID_PARAMETER;
500 }
501
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900502 return ret;
503}
504
505/**
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530506 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900507 * firmware image
508 * @this: Protocol instance
509 * @image_info_size: Size of @image_info
510 * @image_info: Image information
511 * @descriptor_version: Pointer to version number
512 * @descriptor_count: Pointer to number of descriptors
513 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200514 * @package_version: Package version
515 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900516 *
517 * Return information bout the current firmware image in @image_info.
518 * @image_info will consist of a number of descriptors.
519 * Each descriptor will be created based on "dfu_alt_info" variable.
520 *
521 * Return status code
522 */
523static
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530524efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900525 struct efi_firmware_management_protocol *this,
526 efi_uintn_t *image_info_size,
527 struct efi_firmware_image_descriptor *image_info,
528 u32 *descriptor_version,
529 u8 *descriptor_count,
530 efi_uintn_t *descriptor_size,
531 u32 *package_version,
532 u16 **package_version_name)
533{
534 efi_status_t ret;
535
536 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
537 image_info_size, image_info,
538 descriptor_version, descriptor_count, descriptor_size,
539 package_version, package_version_name);
540
541 if (!image_info_size)
542 return EFI_EXIT(EFI_INVALID_PARAMETER);
543
544 if (*image_info_size &&
545 (!image_info || !descriptor_version || !descriptor_count ||
546 !descriptor_size || !package_version || !package_version_name))
547 return EFI_EXIT(EFI_INVALID_PARAMETER);
548
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530549 ret = efi_fill_image_desc_array(image_info_size, image_info,
550 descriptor_version, descriptor_count,
551 descriptor_size, package_version,
552 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900553
554 return EFI_EXIT(ret);
555}
556
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530557#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
558/*
559 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
560 * method with existing FIT image format, and handles
561 * - multiple regions of firmware via DFU
562 * but doesn't support
563 * - versioning of firmware image
564 * - package information
565 */
566
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900567/**
568 * efi_firmware_fit_set_image - update the firmware image
569 * @this: Protocol instance
570 * @image_index: Image index number
571 * @image: New image
572 * @image_size: Size of new image
573 * @vendor_code: Vendor-specific update policy
574 * @progress: Function to report the progress of update
575 * @abort_reason: Pointer to string of abort reason
576 *
577 * Update the firmware to new image, using dfu. The new image should
578 * have FIT image format commonly used in U-Boot.
579 * @vendor_code, @progress and @abort_reason are not supported.
580 *
581 * Return: status code
582 */
583static
584efi_status_t EFIAPI efi_firmware_fit_set_image(
585 struct efi_firmware_management_protocol *this,
586 u8 image_index,
587 const void *image,
588 efi_uintn_t image_size,
589 const void *vendor_code,
590 efi_status_t (*progress)(efi_uintn_t completion),
591 u16 **abort_reason)
592{
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200593 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900594 struct fmp_state state = { 0 };
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200595
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100596 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900597 image_size, vendor_code, progress, abort_reason);
598
599 if (!image || image_index != 1)
600 return EFI_EXIT(EFI_INVALID_PARAMETER);
601
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900602 status = efi_firmware_verify_image(&image, &image_size, image_index,
603 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200604 if (status != EFI_SUCCESS)
605 return EFI_EXIT(status);
606
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900607 if (fit_update(image))
608 return EFI_EXIT(EFI_DEVICE_ERROR);
609
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900610 efi_firmware_set_fmp_state_var(&state, image_index);
611
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900612 return EFI_EXIT(EFI_SUCCESS);
613}
614
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900615const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530616 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900617 .get_image = efi_firmware_get_image_unsupported,
618 .set_image = efi_firmware_fit_set_image,
619 .check_image = efi_firmware_check_image_unsupported,
620 .get_package_info = efi_firmware_get_package_info_unsupported,
621 .set_package_info = efi_firmware_set_package_info_unsupported,
622};
623#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900624
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900625#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
626/*
627 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
628 * method with raw data.
629 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900630
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900631/**
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900632 * efi_firmware_raw_set_image - update the firmware image
633 * @this: Protocol instance
634 * @image_index: Image index number
635 * @image: New image
636 * @image_size: Size of new image
637 * @vendor_code: Vendor-specific update policy
638 * @progress: Function to report the progress of update
639 * @abort_reason: Pointer to string of abort reason
640 *
641 * Update the firmware to new image, using dfu. The new image should
642 * be a single raw image.
643 * @vendor_code, @progress and @abort_reason are not supported.
644 *
645 * Return: status code
646 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900647static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900648efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900649 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900650 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900651 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900652 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900653 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900654 efi_status_t (*progress)(efi_uintn_t completion),
655 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900656{
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530657 int ret;
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900658 u8 dfu_alt_num;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530659 efi_status_t status;
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900660 struct fmp_state state = { 0 };
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530661
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100662 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900663 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900664
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900665 if (!image)
666 return EFI_EXIT(EFI_INVALID_PARAMETER);
667
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900668 status = efi_firmware_verify_image(&image, &image_size, image_index,
669 &state);
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200670 if (status != EFI_SUCCESS)
671 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530672
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900673 /*
674 * dfu_alt_num is assigned from 0 while image_index starts from 1.
675 * dfu_alt_num is calculated by (image_index - 1) when multi bank update
676 * is not used.
677 */
678 dfu_alt_num = image_index - 1;
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530679 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
680 /*
681 * Based on the value of update bank, derive the
682 * image index value.
683 */
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900684 ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
Sughosh Ganu1cadae22022-10-21 18:16:03 +0530685 if (ret) {
686 log_debug("Unable to get FWU image_index\n");
687 return EFI_EXIT(EFI_DEVICE_ERROR);
688 }
689 }
690
Masahisa Kojimac1c48e42024-01-11 14:35:39 +0900691 if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900692 NULL, NULL))
693 return EFI_EXIT(EFI_DEVICE_ERROR);
694
Masahisa Kojima45a18f02023-06-07 14:41:52 +0900695 efi_firmware_set_fmp_state_var(&state, image_index);
696
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900697 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900698}
699
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900700const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu4ed72612022-06-01 23:30:41 +0530701 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900702 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900703 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900704 .check_image = efi_firmware_check_image_unsupported,
705 .get_package_info = efi_firmware_get_package_info_unsupported,
706 .set_package_info = efi_firmware_set_package_info_unsupported,
707};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900708#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */