blob: 0ce6c1e34f0259fa1a754dc3f26ad114fdb1b1fa [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
9#include <common.h>
10#include <charset.h>
11#include <dfu.h>
12#include <efi_loader.h>
13#include <image.h>
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053014#include <signatures.h>
15
AKASHI Takahirof4818e62020-11-30 18:12:12 +090016#include <linux/list.h>
17
Sughosh Ganu7221c6e2020-12-30 19:27:05 +053018#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
19
20/**
21 * struct fmp_payload_header - EDK2 header for the FMP payload
22 *
23 * This structure describes the header which is preprended to the
24 * FMP payload by the edk2 capsule generation scripts.
25 *
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
30 */
31struct fmp_payload_header {
32 u32 signature;
33 u32 header_size;
34 u32 fw_version;
35 u32 lowest_supported_version;
36};
37
Sughosh Ganua1d9f672022-04-15 11:29:37 +053038__weak void set_dfu_alt_info(char *interface, char *devstr)
39{
40 env_set("dfu_alt_info", update_info.dfu_string);
41}
42
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +090043/* Place holder; not supported */
44static
45efi_status_t EFIAPI efi_firmware_get_image_unsupported(
46 struct efi_firmware_management_protocol *this,
47 u8 image_index,
48 void *image,
49 efi_uintn_t *image_size)
50{
51 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
52
53 return EFI_EXIT(EFI_UNSUPPORTED);
54}
55
56/* Place holder; not supported */
57static
58efi_status_t EFIAPI efi_firmware_check_image_unsupported(
59 struct efi_firmware_management_protocol *this,
60 u8 image_index,
61 const void *image,
62 efi_uintn_t *image_size,
63 u32 *image_updatable)
64{
65 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
66 image_updatable);
67
68 return EFI_EXIT(EFI_UNSUPPORTED);
69}
70
71/* Place holder; not supported */
72static
73efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
74 struct efi_firmware_management_protocol *this,
75 u32 *package_version,
76 u16 **package_version_name,
77 u32 *package_version_name_maxlen,
78 u64 *attributes_supported,
79 u64 *attributes_setting)
80{
81 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
82 package_version_name, package_version_name_maxlen,
83 attributes_supported, attributes_setting);
84
85 return EFI_EXIT(EFI_UNSUPPORTED);
86}
87
88/* Place holder; not supported */
89static
90efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
91 struct efi_firmware_management_protocol *this,
92 const void *image,
93 efi_uintn_t *image_size,
94 const void *vendor_code,
95 u32 package_version,
96 const u16 *package_version_name)
97{
98 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
99 package_version, package_version_name);
100
101 return EFI_EXIT(EFI_UNSUPPORTED);
102}
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900103
104/**
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530105 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900106 * @image_info_size: Size of @image_info
107 * @image_info: Image information
108 * @descriptor_version: Pointer to version number
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530109 * @descriptor_count: Image count
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900110 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530111 * @package_version: Package version
112 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900113 *
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530114 * Return information about the current firmware image in @image_info.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900115 * @image_info will consist of a number of descriptors.
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530116 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900117 *
118 * Return status code
119 */
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530120static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900121 efi_uintn_t *image_info_size,
122 struct efi_firmware_image_descriptor *image_info,
123 u32 *descriptor_version,
124 u8 *descriptor_count,
125 efi_uintn_t *descriptor_size,
126 u32 *package_version,
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530127 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900128{
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530129 size_t total_size;
130 struct efi_fw_image *fw_array;
131 int i;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900132
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530133 total_size = sizeof(*image_info) * num_image_type_guids;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900134
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900135 if (*image_info_size < total_size) {
136 *image_info_size = total_size;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900137
138 return EFI_BUFFER_TOO_SMALL;
139 }
140 *image_info_size = total_size;
141
Sughosh Ganuc212fc72022-05-31 12:45:33 +0530142 fw_array = update_info.images;
143 *descriptor_count = num_image_type_guids;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900144 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900145 *descriptor_size = sizeof(*image_info);
146 *package_version = 0xffffffff; /* not supported */
147 *package_version_name = NULL; /* not supported */
148
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530149 for (i = 0; i < num_image_type_guids; i++) {
150 image_info[i].image_index = fw_array[i].image_index;
151 image_info[i].image_type_id = fw_array[i].image_type_id;
152 image_info[i].image_id = fw_array[i].image_index;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900153
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530154 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900155
156 image_info[i].version = 0; /* not supported */
157 image_info[i].version_name = NULL; /* not supported */
158 image_info[i].size = 0;
159 image_info[i].attributes_supported =
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530160 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
161 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900162 image_info[i].attributes_setting =
163 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530164
165 /* Check if the capsule authentication is enabled */
Sughosh Ganud1bd8492021-04-12 20:35:23 +0530166 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530167 image_info[0].attributes_setting |=
168 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
169
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900170 image_info[i].lowest_supported_image_version = 0;
171 image_info[i].last_attempt_version = 0;
172 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
173 image_info[i].hardware_instance = 1;
174 image_info[i].dependencies = NULL;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900175 }
176
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900177 return EFI_SUCCESS;
178}
179
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200180/**
181 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
182 * @p_image: Pointer to new image
183 * @p_image_size: Pointer to size of new image
184 *
185 * Authenticate the capsule if authentication is enabled.
186 * The image pointer and the image size are updated in case of success.
187 *
188 * Return: status code
189 */
190static
191efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
192 efi_uintn_t *p_image_size)
193{
194 const void *image = *p_image;
195 efi_uintn_t image_size = *p_image_size;
196 u32 fmp_hdr_signature;
197 struct fmp_payload_header *header;
198 void *capsule_payload;
199 efi_status_t status;
200 efi_uintn_t capsule_payload_size;
201
202 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
203 capsule_payload = NULL;
204 capsule_payload_size = 0;
205 status = efi_capsule_authenticate(image, image_size,
206 &capsule_payload,
207 &capsule_payload_size);
208
209 if (status == EFI_SECURITY_VIOLATION) {
210 printf("Capsule authentication check failed. Aborting update\n");
211 return status;
212 } else if (status != EFI_SUCCESS) {
213 return status;
214 }
215
216 debug("Capsule authentication successful\n");
217 image = capsule_payload;
218 image_size = capsule_payload_size;
219 } else {
220 debug("Capsule authentication disabled. ");
221 debug("Updating capsule without authenticating.\n");
222 }
223
224 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
225 header = (void *)image;
226
227 if (!memcmp(&header->signature, &fmp_hdr_signature,
228 sizeof(fmp_hdr_signature))) {
229 /*
230 * When building the capsule with the scripts in
231 * edk2, a FMP header is inserted above the capsule
232 * payload. Compensate for this header to get the
233 * actual payload that is to be updated.
234 */
235 image += header->header_size;
236 image_size -= header->header_size;
237 }
238
239 *p_image = image;
240 *p_image_size = image_size;
241 return EFI_SUCCESS;
242}
243
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900244#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
245/*
246 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
247 * method with existing FIT image format, and handles
248 * - multiple regions of firmware via DFU
249 * but doesn't support
250 * - versioning of firmware image
251 * - package information
252 */
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900253
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900254/**
255 * efi_firmware_fit_get_image_info - return information about the current
256 * firmware image
257 * @this: Protocol instance
258 * @image_info_size: Size of @image_info
259 * @image_info: Image information
260 * @descriptor_version: Pointer to version number
261 * @descriptor_count: Pointer to number of descriptors
262 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200263 * @package_version: Package version
264 * @package_version_name: Package version's name
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900265 *
266 * Return information bout the current firmware image in @image_info.
267 * @image_info will consist of a number of descriptors.
268 * Each descriptor will be created based on "dfu_alt_info" variable.
269 *
270 * Return status code
271 */
272static
273efi_status_t EFIAPI efi_firmware_fit_get_image_info(
274 struct efi_firmware_management_protocol *this,
275 efi_uintn_t *image_info_size,
276 struct efi_firmware_image_descriptor *image_info,
277 u32 *descriptor_version,
278 u8 *descriptor_count,
279 efi_uintn_t *descriptor_size,
280 u32 *package_version,
281 u16 **package_version_name)
282{
283 efi_status_t ret;
284
285 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
286 image_info_size, image_info,
287 descriptor_version, descriptor_count, descriptor_size,
288 package_version, package_version_name);
289
290 if (!image_info_size)
291 return EFI_EXIT(EFI_INVALID_PARAMETER);
292
293 if (*image_info_size &&
294 (!image_info || !descriptor_version || !descriptor_count ||
295 !descriptor_size || !package_version || !package_version_name))
296 return EFI_EXIT(EFI_INVALID_PARAMETER);
297
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530298 ret = efi_fill_image_desc_array(image_info_size, image_info,
299 descriptor_version, descriptor_count,
300 descriptor_size, package_version,
301 package_version_name);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900302
303 return EFI_EXIT(ret);
304}
305
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900306/**
307 * efi_firmware_fit_set_image - update the firmware image
308 * @this: Protocol instance
309 * @image_index: Image index number
310 * @image: New image
311 * @image_size: Size of new image
312 * @vendor_code: Vendor-specific update policy
313 * @progress: Function to report the progress of update
314 * @abort_reason: Pointer to string of abort reason
315 *
316 * Update the firmware to new image, using dfu. The new image should
317 * have FIT image format commonly used in U-Boot.
318 * @vendor_code, @progress and @abort_reason are not supported.
319 *
320 * Return: status code
321 */
322static
323efi_status_t EFIAPI efi_firmware_fit_set_image(
324 struct efi_firmware_management_protocol *this,
325 u8 image_index,
326 const void *image,
327 efi_uintn_t image_size,
328 const void *vendor_code,
329 efi_status_t (*progress)(efi_uintn_t completion),
330 u16 **abort_reason)
331{
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200332 efi_status_t status;
333
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100334 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900335 image_size, vendor_code, progress, abort_reason);
336
337 if (!image || image_index != 1)
338 return EFI_EXIT(EFI_INVALID_PARAMETER);
339
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200340 status = efi_firmware_capsule_authenticate(&image, &image_size);
341 if (status != EFI_SUCCESS)
342 return EFI_EXIT(status);
343
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900344 if (fit_update(image))
345 return EFI_EXIT(EFI_DEVICE_ERROR);
346
347 return EFI_EXIT(EFI_SUCCESS);
348}
349
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900350const struct efi_firmware_management_protocol efi_fmp_fit = {
351 .get_image_info = efi_firmware_fit_get_image_info,
352 .get_image = efi_firmware_get_image_unsupported,
353 .set_image = efi_firmware_fit_set_image,
354 .check_image = efi_firmware_check_image_unsupported,
355 .get_package_info = efi_firmware_get_package_info_unsupported,
356 .set_package_info = efi_firmware_set_package_info_unsupported,
357};
358#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900359
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900360#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
361/*
362 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
363 * method with raw data.
364 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900365
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900366/**
367 * efi_firmware_raw_get_image_info - return information about the current
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200368 * firmware image
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900369 * @this: Protocol instance
370 * @image_info_size: Size of @image_info
371 * @image_info: Image information
372 * @descriptor_version: Pointer to version number
373 * @descriptor_count: Pointer to number of descriptors
374 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé0f3c9222022-05-25 11:20:22 +0200375 * @package_version: Package version
376 * @package_version_name: Package version's name
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900377 *
378 * Return information bout the current firmware image in @image_info.
379 * @image_info will consist of a number of descriptors.
380 * Each descriptor will be created based on "dfu_alt_info" variable.
381 *
382 * Return status code
383 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900384static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900385efi_status_t EFIAPI efi_firmware_raw_get_image_info(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900386 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900387 efi_uintn_t *image_info_size,
388 struct efi_firmware_image_descriptor *image_info,
389 u32 *descriptor_version,
390 u8 *descriptor_count,
391 efi_uintn_t *descriptor_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900392 u32 *package_version,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900393 u16 **package_version_name)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900394{
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900395 efi_status_t ret = EFI_SUCCESS;
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900396
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900397 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
398 image_info_size, image_info,
399 descriptor_version, descriptor_count, descriptor_size,
400 package_version, package_version_name);
401
402 if (!image_info_size)
403 return EFI_EXIT(EFI_INVALID_PARAMETER);
404
405 if (*image_info_size &&
406 (!image_info || !descriptor_version || !descriptor_count ||
407 !descriptor_size || !package_version || !package_version_name))
408 return EFI_EXIT(EFI_INVALID_PARAMETER);
409
Sughosh Ganu2a9fd7d2022-04-15 11:29:35 +0530410 ret = efi_fill_image_desc_array(image_info_size, image_info,
411 descriptor_version, descriptor_count,
412 descriptor_size, package_version,
413 package_version_name);
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900414
415 return EFI_EXIT(ret);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900416}
417
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900418/**
419 * efi_firmware_raw_set_image - update the firmware image
420 * @this: Protocol instance
421 * @image_index: Image index number
422 * @image: New image
423 * @image_size: Size of new image
424 * @vendor_code: Vendor-specific update policy
425 * @progress: Function to report the progress of update
426 * @abort_reason: Pointer to string of abort reason
427 *
428 * Update the firmware to new image, using dfu. The new image should
429 * be a single raw image.
430 * @vendor_code, @progress and @abort_reason are not supported.
431 *
432 * Return: status code
433 */
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900434static
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900435efi_status_t EFIAPI efi_firmware_raw_set_image(
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900436 struct efi_firmware_management_protocol *this,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900437 u8 image_index,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900438 const void *image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900439 efi_uintn_t image_size,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900440 const void *vendor_code,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900441 efi_status_t (*progress)(efi_uintn_t completion),
442 u16 **abort_reason)
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900443{
Sughosh Ganuc9a821b2020-12-30 19:27:10 +0530444 efi_status_t status;
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530445
Heinrich Schuchardt94f09e02022-02-03 20:13:17 +0100446 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900447 image_size, vendor_code, progress, abort_reason);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900448
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900449 if (!image)
450 return EFI_EXIT(EFI_INVALID_PARAMETER);
451
Vincent Stehlé6a4625e2022-05-31 09:55:34 +0200452 status = efi_firmware_capsule_authenticate(&image, &image_size);
453 if (status != EFI_SUCCESS)
454 return EFI_EXIT(status);
Sughosh Ganu7221c6e2020-12-30 19:27:05 +0530455
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900456 if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
457 NULL, NULL))
458 return EFI_EXIT(EFI_DEVICE_ERROR);
459
460 return EFI_EXIT(EFI_SUCCESS);
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900461}
462
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900463const struct efi_firmware_management_protocol efi_fmp_raw = {
464 .get_image_info = efi_firmware_raw_get_image_info,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900465 .get_image = efi_firmware_get_image_unsupported,
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900466 .set_image = efi_firmware_raw_set_image,
AKASHI Takahirof4818e62020-11-30 18:12:12 +0900467 .check_image = efi_firmware_check_image_unsupported,
468 .get_package_info = efi_firmware_get_package_info_unsupported,
469 .set_package_info = efi_firmware_set_package_info_unsupported,
470};
AKASHI Takahiro7ff3f3c2020-11-17 09:28:00 +0900471#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */