1 // SPDX-License-Identifier: GPL-2.0+
3 * EFI Firmware management protocol
5 * Copyright (c) 2020 Linaro Limited
6 * Author: AKASHI Takahiro
12 #include <efi_loader.h>
14 #include <signatures.h>
16 #include <linux/list.h>
18 #define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
21 * struct fmp_payload_header - EDK2 header for the FMP payload
23 * This structure describes the header which is preprended to the
24 * FMP payload by the edk2 capsule generation scripts.
26 * @signature: Header signature used to identify the header
27 * @header_size: Size of the structure
28 * @fw_version: Firmware versions used
29 * @lowest_supported_version: Lowest supported version
31 struct fmp_payload_header {
35 u32 lowest_supported_version;
38 /* Place holder; not supported */
40 efi_status_t EFIAPI efi_firmware_get_image_unsupported(
41 struct efi_firmware_management_protocol *this,
44 efi_uintn_t *image_size)
46 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
48 return EFI_EXIT(EFI_UNSUPPORTED);
51 /* Place holder; not supported */
53 efi_status_t EFIAPI efi_firmware_check_image_unsupported(
54 struct efi_firmware_management_protocol *this,
57 efi_uintn_t *image_size,
60 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
63 return EFI_EXIT(EFI_UNSUPPORTED);
66 /* Place holder; not supported */
68 efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
69 struct efi_firmware_management_protocol *this,
71 u16 **package_version_name,
72 u32 *package_version_name_maxlen,
73 u64 *attributes_supported,
74 u64 *attributes_setting)
76 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
77 package_version_name, package_version_name_maxlen,
78 attributes_supported, attributes_setting);
80 return EFI_EXIT(EFI_UNSUPPORTED);
83 /* Place holder; not supported */
85 efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
86 struct efi_firmware_management_protocol *this,
88 efi_uintn_t *image_size,
89 const void *vendor_code,
91 const u16 *package_version_name)
93 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
94 package_version, package_version_name);
96 return EFI_EXIT(EFI_UNSUPPORTED);
100 * efi_get_dfu_info - return information about the current firmware image
101 * @this: Protocol instance
102 * @image_info_size: Size of @image_info
103 * @image_info: Image information
104 * @descriptor_version: Pointer to version number
105 * @descriptor_count: Pointer to number of descriptors
106 * @descriptor_size: Pointer to descriptor size
107 * package_version: Package version
108 * package_version_name: Package version's name
109 * image_type: Image type GUID
111 * Return information bout the current firmware image in @image_info.
112 * @image_info will consist of a number of descriptors.
113 * Each descriptor will be created based on "dfu_alt_info" variable.
117 static efi_status_t efi_get_dfu_info(
118 efi_uintn_t *image_info_size,
119 struct efi_firmware_image_descriptor *image_info,
120 u32 *descriptor_version,
121 u8 *descriptor_count,
122 efi_uintn_t *descriptor_size,
123 u32 *package_version,
124 u16 **package_version_name,
125 const efi_guid_t *image_type)
127 struct dfu_entity *dfu;
128 size_t names_len, total_size;
132 dfu_init_env_entities(NULL, NULL);
136 list_for_each_entry(dfu, &dfu_list, list) {
137 names_len += (utf8_utf16_strlen(dfu->name) + 1) * 2;
141 log_warning("Probably dfu_alt_info not defined\n");
142 *image_info_size = 0;
148 total_size = sizeof(*image_info) * dfu_num + names_len;
150 * we will assume that sizeof(*image_info) * dfu_name
151 * is, at least, a multiple of 2. So the start address for
152 * image_id_name would be aligned with 2 bytes.
154 if (*image_info_size < total_size) {
155 *image_info_size = total_size;
158 return EFI_BUFFER_TOO_SMALL;
160 *image_info_size = total_size;
162 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
163 *descriptor_count = dfu_num;
164 *descriptor_size = sizeof(*image_info);
165 *package_version = 0xffffffff; /* not supported */
166 *package_version_name = NULL; /* not supported */
168 /* DFU alt number should correspond to image_index */
170 /* Name area starts just after descriptors */
171 name = (u16 *)((u8 *)image_info + sizeof(*image_info) * dfu_num);
173 list_for_each_entry(dfu, &dfu_list, list) {
174 image_info[i].image_index = dfu->alt + 1;
175 image_info[i].image_type_id = *image_type;
176 image_info[i].image_id = dfu->alt;
178 /* copy the DFU entity name */
179 utf8_utf16_strcpy(&next, dfu->name);
180 image_info[i].image_id_name = name;
183 image_info[i].version = 0; /* not supported */
184 image_info[i].version_name = NULL; /* not supported */
185 image_info[i].size = 0;
186 image_info[i].attributes_supported =
187 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
188 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
189 image_info[i].attributes_setting =
190 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
192 /* Check if the capsule authentication is enabled */
193 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
194 image_info[0].attributes_setting |=
195 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
197 image_info[i].lowest_supported_image_version = 0;
198 image_info[i].last_attempt_version = 0;
199 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
200 image_info[i].hardware_instance = 1;
201 image_info[i].dependencies = NULL;
211 #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
213 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
214 * method with existing FIT image format, and handles
215 * - multiple regions of firmware via DFU
216 * but doesn't support
217 * - versioning of firmware image
218 * - package information
220 const efi_guid_t efi_firmware_image_type_uboot_fit =
221 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
224 * efi_firmware_fit_get_image_info - return information about the current
226 * @this: Protocol instance
227 * @image_info_size: Size of @image_info
228 * @image_info: Image information
229 * @descriptor_version: Pointer to version number
230 * @descriptor_count: Pointer to number of descriptors
231 * @descriptor_size: Pointer to descriptor size
232 * package_version: Package version
233 * package_version_name: Package version's name
235 * Return information bout the current firmware image in @image_info.
236 * @image_info will consist of a number of descriptors.
237 * Each descriptor will be created based on "dfu_alt_info" variable.
242 efi_status_t EFIAPI efi_firmware_fit_get_image_info(
243 struct efi_firmware_management_protocol *this,
244 efi_uintn_t *image_info_size,
245 struct efi_firmware_image_descriptor *image_info,
246 u32 *descriptor_version,
247 u8 *descriptor_count,
248 efi_uintn_t *descriptor_size,
249 u32 *package_version,
250 u16 **package_version_name)
254 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
255 image_info_size, image_info,
256 descriptor_version, descriptor_count, descriptor_size,
257 package_version, package_version_name);
259 if (!image_info_size)
260 return EFI_EXIT(EFI_INVALID_PARAMETER);
262 if (*image_info_size &&
263 (!image_info || !descriptor_version || !descriptor_count ||
264 !descriptor_size || !package_version || !package_version_name))
265 return EFI_EXIT(EFI_INVALID_PARAMETER);
267 ret = efi_get_dfu_info(image_info_size, image_info,
268 descriptor_version, descriptor_count,
270 package_version, package_version_name,
271 &efi_firmware_image_type_uboot_fit);
273 return EFI_EXIT(ret);
277 * efi_firmware_fit_set_image - update the firmware image
278 * @this: Protocol instance
279 * @image_index: Image index number
281 * @image_size: Size of new image
282 * @vendor_code: Vendor-specific update policy
283 * @progress: Function to report the progress of update
284 * @abort_reason: Pointer to string of abort reason
286 * Update the firmware to new image, using dfu. The new image should
287 * have FIT image format commonly used in U-Boot.
288 * @vendor_code, @progress and @abort_reason are not supported.
290 * Return: status code
293 efi_status_t EFIAPI efi_firmware_fit_set_image(
294 struct efi_firmware_management_protocol *this,
297 efi_uintn_t image_size,
298 const void *vendor_code,
299 efi_status_t (*progress)(efi_uintn_t completion),
302 EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
303 image_size, vendor_code, progress, abort_reason);
305 if (!image || image_index != 1)
306 return EFI_EXIT(EFI_INVALID_PARAMETER);
308 if (fit_update(image))
309 return EFI_EXIT(EFI_DEVICE_ERROR);
311 return EFI_EXIT(EFI_SUCCESS);
314 const struct efi_firmware_management_protocol efi_fmp_fit = {
315 .get_image_info = efi_firmware_fit_get_image_info,
316 .get_image = efi_firmware_get_image_unsupported,
317 .set_image = efi_firmware_fit_set_image,
318 .check_image = efi_firmware_check_image_unsupported,
319 .get_package_info = efi_firmware_get_package_info_unsupported,
320 .set_package_info = efi_firmware_set_package_info_unsupported,
322 #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
324 #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
326 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
327 * method with raw data.
329 const efi_guid_t efi_firmware_image_type_uboot_raw =
330 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
333 * efi_firmware_raw_get_image_info - return information about the current
335 * @this: Protocol instance
336 * @image_info_size: Size of @image_info
337 * @image_info: Image information
338 * @descriptor_version: Pointer to version number
339 * @descriptor_count: Pointer to number of descriptors
340 * @descriptor_size: Pointer to descriptor size
341 * package_version: Package version
342 * package_version_name: Package version's name
344 * Return information bout the current firmware image in @image_info.
345 * @image_info will consist of a number of descriptors.
346 * Each descriptor will be created based on "dfu_alt_info" variable.
351 efi_status_t EFIAPI efi_firmware_raw_get_image_info(
352 struct efi_firmware_management_protocol *this,
353 efi_uintn_t *image_info_size,
354 struct efi_firmware_image_descriptor *image_info,
355 u32 *descriptor_version,
356 u8 *descriptor_count,
357 efi_uintn_t *descriptor_size,
358 u32 *package_version,
359 u16 **package_version_name)
361 efi_status_t ret = EFI_SUCCESS;
363 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
364 image_info_size, image_info,
365 descriptor_version, descriptor_count, descriptor_size,
366 package_version, package_version_name);
368 if (!image_info_size)
369 return EFI_EXIT(EFI_INVALID_PARAMETER);
371 if (*image_info_size &&
372 (!image_info || !descriptor_version || !descriptor_count ||
373 !descriptor_size || !package_version || !package_version_name))
374 return EFI_EXIT(EFI_INVALID_PARAMETER);
376 ret = efi_get_dfu_info(image_info_size, image_info,
377 descriptor_version, descriptor_count,
379 package_version, package_version_name,
380 &efi_firmware_image_type_uboot_raw);
382 return EFI_EXIT(ret);
386 * efi_firmware_raw_set_image - update the firmware image
387 * @this: Protocol instance
388 * @image_index: Image index number
390 * @image_size: Size of new image
391 * @vendor_code: Vendor-specific update policy
392 * @progress: Function to report the progress of update
393 * @abort_reason: Pointer to string of abort reason
395 * Update the firmware to new image, using dfu. The new image should
396 * be a single raw image.
397 * @vendor_code, @progress and @abort_reason are not supported.
399 * Return: status code
402 efi_status_t EFIAPI efi_firmware_raw_set_image(
403 struct efi_firmware_management_protocol *this,
406 efi_uintn_t image_size,
407 const void *vendor_code,
408 efi_status_t (*progress)(efi_uintn_t completion),
411 u32 fmp_hdr_signature;
412 struct fmp_payload_header *header;
413 void *capsule_payload;
415 efi_uintn_t capsule_payload_size;
417 EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
418 image_size, vendor_code, progress, abort_reason);
421 return EFI_EXIT(EFI_INVALID_PARAMETER);
423 /* Authenticate the capsule if authentication enabled */
424 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
425 capsule_payload = NULL;
426 capsule_payload_size = 0;
427 status = efi_capsule_authenticate(image, image_size,
429 &capsule_payload_size);
431 if (status == EFI_SECURITY_VIOLATION) {
432 printf("Capsule authentication check failed. Aborting update\n");
433 return EFI_EXIT(status);
434 } else if (status != EFI_SUCCESS) {
435 return EFI_EXIT(status);
438 debug("Capsule authentication successfull\n");
439 image = capsule_payload;
440 image_size = capsule_payload_size;
442 debug("Capsule authentication disabled. ");
443 debug("Updating capsule without authenticating.\n");
446 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
447 header = (void *)image;
449 if (!memcmp(&header->signature, &fmp_hdr_signature,
450 sizeof(fmp_hdr_signature))) {
452 * When building the capsule with the scripts in
453 * edk2, a FMP header is inserted above the capsule
454 * payload. Compensate for this header to get the
455 * actual payload that is to be updated.
457 image += header->header_size;
458 image_size -= header->header_size;
462 if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
464 return EFI_EXIT(EFI_DEVICE_ERROR);
466 return EFI_EXIT(EFI_SUCCESS);
469 const struct efi_firmware_management_protocol efi_fmp_raw = {
470 .get_image_info = efi_firmware_raw_get_image_info,
471 .get_image = efi_firmware_get_image_unsupported,
472 .set_image = efi_firmware_raw_set_image,
473 .check_image = efi_firmware_check_image_unsupported,
474 .get_package_info = efi_firmware_get_package_info_unsupported,
475 .set_package_info = efi_firmware_set_package_info_unsupported,
477 #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */