blob: 93e2b01c07a6c62c1ad6877febeb5cc120228f7e [file] [log] [blame]
AKASHI Takahirof27c2012020-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>
Sughosh Ganu86794052022-10-21 18:16:03 +053013#include <fwu.h>
AKASHI Takahirof27c2012020-11-30 18:12:12 +090014#include <image.h>
Sughosh Ganu675b62e2020-12-30 19:27:05 +053015#include <signatures.h>
16
AKASHI Takahirof27c2012020-11-30 18:12:12 +090017#include <linux/list.h>
18
Sughosh Ganu675b62e2020-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
Sughosh Ganua9e6f012022-04-15 11:29:37 +053039__weak void set_dfu_alt_info(char *interface, char *devstr)
40{
41 env_set("dfu_alt_info", update_info.dfu_string);
42}
43
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +090044/* Place holder; not supported */
45static
46efi_status_t EFIAPI efi_firmware_get_image_unsupported(
47 struct efi_firmware_management_protocol *this,
48 u8 image_index,
49 void *image,
50 efi_uintn_t *image_size)
51{
52 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
53
54 return EFI_EXIT(EFI_UNSUPPORTED);
55}
56
57/* Place holder; not supported */
58static
59efi_status_t EFIAPI efi_firmware_check_image_unsupported(
60 struct efi_firmware_management_protocol *this,
61 u8 image_index,
62 const void *image,
63 efi_uintn_t *image_size,
64 u32 *image_updatable)
65{
66 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
67 image_updatable);
68
69 return EFI_EXIT(EFI_UNSUPPORTED);
70}
71
72/* Place holder; not supported */
73static
74efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
75 struct efi_firmware_management_protocol *this,
76 u32 *package_version,
77 u16 **package_version_name,
78 u32 *package_version_name_maxlen,
79 u64 *attributes_supported,
80 u64 *attributes_setting)
81{
82 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
83 package_version_name, package_version_name_maxlen,
84 attributes_supported, attributes_setting);
85
86 return EFI_EXIT(EFI_UNSUPPORTED);
87}
88
89/* Place holder; not supported */
90static
91efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
92 struct efi_firmware_management_protocol *this,
93 const void *image,
94 efi_uintn_t *image_size,
95 const void *vendor_code,
96 u32 package_version,
97 const u16 *package_version_name)
98{
99 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
100 package_version, package_version_name);
101
102 return EFI_EXIT(EFI_UNSUPPORTED);
103}
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900104
105/**
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530106 * efi_fill_image_desc_array - populate image descriptor array
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900107 * @image_info_size: Size of @image_info
108 * @image_info: Image information
109 * @descriptor_version: Pointer to version number
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530110 * @descriptor_count: Image count
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900111 * @descriptor_size: Pointer to descriptor size
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530112 * @package_version: Package version
113 * @package_version_name: Package version's name
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900114 *
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530115 * Return information about the current firmware image in @image_info.
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900116 * @image_info will consist of a number of descriptors.
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530117 * Each descriptor will be created based on efi_fw_image array.
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900118 *
119 * Return status code
120 */
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530121static efi_status_t efi_fill_image_desc_array(
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900122 efi_uintn_t *image_info_size,
123 struct efi_firmware_image_descriptor *image_info,
124 u32 *descriptor_version,
125 u8 *descriptor_count,
126 efi_uintn_t *descriptor_size,
127 u32 *package_version,
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530128 u16 **package_version_name)
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900129{
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530130 size_t total_size;
131 struct efi_fw_image *fw_array;
132 int i;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900133
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530134 total_size = sizeof(*image_info) * num_image_type_guids;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900135
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900136 if (*image_info_size < total_size) {
137 *image_info_size = total_size;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900138
139 return EFI_BUFFER_TOO_SMALL;
140 }
141 *image_info_size = total_size;
142
Sughosh Ganu6a463bc2022-05-31 12:45:33 +0530143 fw_array = update_info.images;
144 *descriptor_count = num_image_type_guids;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900145 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900146 *descriptor_size = sizeof(*image_info);
147 *package_version = 0xffffffff; /* not supported */
148 *package_version_name = NULL; /* not supported */
149
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530150 for (i = 0; i < num_image_type_guids; i++) {
151 image_info[i].image_index = fw_array[i].image_index;
152 image_info[i].image_type_id = fw_array[i].image_type_id;
153 image_info[i].image_id = fw_array[i].image_index;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900154
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530155 image_info[i].image_id_name = fw_array[i].fw_name;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900156
157 image_info[i].version = 0; /* not supported */
158 image_info[i].version_name = NULL; /* not supported */
159 image_info[i].size = 0;
160 image_info[i].attributes_supported =
Sughosh Ganu88a2ef22020-12-30 19:27:10 +0530161 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
162 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900163 image_info[i].attributes_setting =
164 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
Sughosh Ganu88a2ef22020-12-30 19:27:10 +0530165
166 /* Check if the capsule authentication is enabled */
Sughosh Ganu6a2e26b2021-04-12 20:35:23 +0530167 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
Sughosh Ganu88a2ef22020-12-30 19:27:10 +0530168 image_info[0].attributes_setting |=
169 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
170
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900171 image_info[i].lowest_supported_image_version = 0;
172 image_info[i].last_attempt_version = 0;
173 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
174 image_info[i].hardware_instance = 1;
175 image_info[i].dependencies = NULL;
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900176 }
177
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900178 return EFI_SUCCESS;
179}
180
Vincent Stehlé8645aef2022-05-31 09:55:34 +0200181/**
182 * efi_firmware_capsule_authenticate - authenticate the capsule if enabled
183 * @p_image: Pointer to new image
184 * @p_image_size: Pointer to size of new image
185 *
186 * Authenticate the capsule if authentication is enabled.
187 * The image pointer and the image size are updated in case of success.
188 *
189 * Return: status code
190 */
191static
192efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
193 efi_uintn_t *p_image_size)
194{
195 const void *image = *p_image;
196 efi_uintn_t image_size = *p_image_size;
197 u32 fmp_hdr_signature;
198 struct fmp_payload_header *header;
199 void *capsule_payload;
200 efi_status_t status;
201 efi_uintn_t capsule_payload_size;
202
203 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) {
204 capsule_payload = NULL;
205 capsule_payload_size = 0;
206 status = efi_capsule_authenticate(image, image_size,
207 &capsule_payload,
208 &capsule_payload_size);
209
210 if (status == EFI_SECURITY_VIOLATION) {
211 printf("Capsule authentication check failed. Aborting update\n");
212 return status;
213 } else if (status != EFI_SUCCESS) {
214 return status;
215 }
216
217 debug("Capsule authentication successful\n");
218 image = capsule_payload;
219 image_size = capsule_payload_size;
220 } else {
221 debug("Capsule authentication disabled. ");
222 debug("Updating capsule without authenticating.\n");
223 }
224
225 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
226 header = (void *)image;
227
228 if (!memcmp(&header->signature, &fmp_hdr_signature,
229 sizeof(fmp_hdr_signature))) {
230 /*
231 * When building the capsule with the scripts in
232 * edk2, a FMP header is inserted above the capsule
233 * payload. Compensate for this header to get the
234 * actual payload that is to be updated.
235 */
236 image += header->header_size;
237 image_size -= header->header_size;
238 }
239
240 *p_image = image;
241 *p_image_size = image_size;
242 return EFI_SUCCESS;
243}
244
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900245/**
Sughosh Ganu556a1262022-06-01 23:30:41 +0530246 * efi_firmware_get_image_info - return information about the current
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900247 * firmware image
248 * @this: Protocol instance
249 * @image_info_size: Size of @image_info
250 * @image_info: Image information
251 * @descriptor_version: Pointer to version number
252 * @descriptor_count: Pointer to number of descriptors
253 * @descriptor_size: Pointer to descriptor size
Vincent Stehlé7751d2e2022-05-25 11:20:22 +0200254 * @package_version: Package version
255 * @package_version_name: Package version's name
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900256 *
257 * Return information bout the current firmware image in @image_info.
258 * @image_info will consist of a number of descriptors.
259 * Each descriptor will be created based on "dfu_alt_info" variable.
260 *
261 * Return status code
262 */
263static
Sughosh Ganu556a1262022-06-01 23:30:41 +0530264efi_status_t EFIAPI efi_firmware_get_image_info(
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900265 struct efi_firmware_management_protocol *this,
266 efi_uintn_t *image_info_size,
267 struct efi_firmware_image_descriptor *image_info,
268 u32 *descriptor_version,
269 u8 *descriptor_count,
270 efi_uintn_t *descriptor_size,
271 u32 *package_version,
272 u16 **package_version_name)
273{
274 efi_status_t ret;
275
276 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
277 image_info_size, image_info,
278 descriptor_version, descriptor_count, descriptor_size,
279 package_version, package_version_name);
280
281 if (!image_info_size)
282 return EFI_EXIT(EFI_INVALID_PARAMETER);
283
284 if (*image_info_size &&
285 (!image_info || !descriptor_version || !descriptor_count ||
286 !descriptor_size || !package_version || !package_version_name))
287 return EFI_EXIT(EFI_INVALID_PARAMETER);
288
Sughosh Ganu1ea06bc2022-04-15 11:29:35 +0530289 ret = efi_fill_image_desc_array(image_info_size, image_info,
290 descriptor_version, descriptor_count,
291 descriptor_size, package_version,
292 package_version_name);
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900293
294 return EFI_EXIT(ret);
295}
296
Sughosh Ganu556a1262022-06-01 23:30:41 +0530297#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
298/*
299 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
300 * method with existing FIT image format, and handles
301 * - multiple regions of firmware via DFU
302 * but doesn't support
303 * - versioning of firmware image
304 * - package information
305 */
306
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900307/**
308 * efi_firmware_fit_set_image - update the firmware image
309 * @this: Protocol instance
310 * @image_index: Image index number
311 * @image: New image
312 * @image_size: Size of new image
313 * @vendor_code: Vendor-specific update policy
314 * @progress: Function to report the progress of update
315 * @abort_reason: Pointer to string of abort reason
316 *
317 * Update the firmware to new image, using dfu. The new image should
318 * have FIT image format commonly used in U-Boot.
319 * @vendor_code, @progress and @abort_reason are not supported.
320 *
321 * Return: status code
322 */
323static
324efi_status_t EFIAPI efi_firmware_fit_set_image(
325 struct efi_firmware_management_protocol *this,
326 u8 image_index,
327 const void *image,
328 efi_uintn_t image_size,
329 const void *vendor_code,
330 efi_status_t (*progress)(efi_uintn_t completion),
331 u16 **abort_reason)
332{
Vincent Stehlé8645aef2022-05-31 09:55:34 +0200333 efi_status_t status;
334
Heinrich Schuchardtb1193fa2022-02-03 20:13:17 +0100335 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900336 image_size, vendor_code, progress, abort_reason);
337
338 if (!image || image_index != 1)
339 return EFI_EXIT(EFI_INVALID_PARAMETER);
340
Vincent Stehlé8645aef2022-05-31 09:55:34 +0200341 status = efi_firmware_capsule_authenticate(&image, &image_size);
342 if (status != EFI_SUCCESS)
343 return EFI_EXIT(status);
344
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900345 if (fit_update(image))
346 return EFI_EXIT(EFI_DEVICE_ERROR);
347
348 return EFI_EXIT(EFI_SUCCESS);
349}
350
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900351const struct efi_firmware_management_protocol efi_fmp_fit = {
Sughosh Ganu556a1262022-06-01 23:30:41 +0530352 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900353 .get_image = efi_firmware_get_image_unsupported,
354 .set_image = efi_firmware_fit_set_image,
355 .check_image = efi_firmware_check_image_unsupported,
356 .get_package_info = efi_firmware_get_package_info_unsupported,
357 .set_package_info = efi_firmware_set_package_info_unsupported,
358};
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900359#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
360
361#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
362/*
363 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
364 * method with raw data.
365 */
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900366
367/**
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900368 * efi_firmware_raw_set_image - update the firmware image
369 * @this: Protocol instance
370 * @image_index: Image index number
371 * @image: New image
372 * @image_size: Size of new image
373 * @vendor_code: Vendor-specific update policy
374 * @progress: Function to report the progress of update
375 * @abort_reason: Pointer to string of abort reason
376 *
377 * Update the firmware to new image, using dfu. The new image should
378 * be a single raw image.
379 * @vendor_code, @progress and @abort_reason are not supported.
380 *
381 * Return: status code
382 */
383static
384efi_status_t EFIAPI efi_firmware_raw_set_image(
385 struct efi_firmware_management_protocol *this,
386 u8 image_index,
387 const void *image,
388 efi_uintn_t image_size,
389 const void *vendor_code,
390 efi_status_t (*progress)(efi_uintn_t completion),
391 u16 **abort_reason)
392{
Sughosh Ganu86794052022-10-21 18:16:03 +0530393 int ret;
Sughosh Ganu88a2ef22020-12-30 19:27:10 +0530394 efi_status_t status;
Sughosh Ganu675b62e2020-12-30 19:27:05 +0530395
Heinrich Schuchardtb1193fa2022-02-03 20:13:17 +0100396 EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900397 image_size, vendor_code, progress, abort_reason);
398
399 if (!image)
400 return EFI_EXIT(EFI_INVALID_PARAMETER);
401
Vincent Stehlé8645aef2022-05-31 09:55:34 +0200402 status = efi_firmware_capsule_authenticate(&image, &image_size);
403 if (status != EFI_SUCCESS)
404 return EFI_EXIT(status);
Sughosh Ganu675b62e2020-12-30 19:27:05 +0530405
Sughosh Ganu86794052022-10-21 18:16:03 +0530406 if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
407 /*
408 * Based on the value of update bank, derive the
409 * image index value.
410 */
411 ret = fwu_get_image_index(&image_index);
412 if (ret) {
413 log_debug("Unable to get FWU image_index\n");
414 return EFI_EXIT(EFI_DEVICE_ERROR);
415 }
416 }
417
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900418 if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
419 NULL, NULL))
420 return EFI_EXIT(EFI_DEVICE_ERROR);
421
422 return EFI_EXIT(EFI_SUCCESS);
423}
424
425const struct efi_firmware_management_protocol efi_fmp_raw = {
Sughosh Ganu556a1262022-06-01 23:30:41 +0530426 .get_image_info = efi_firmware_get_image_info,
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900427 .get_image = efi_firmware_get_image_unsupported,
428 .set_image = efi_firmware_raw_set_image,
429 .check_image = efi_firmware_check_image_unsupported,
430 .get_package_info = efi_firmware_get_package_info_unsupported,
431 .set_package_info = efi_firmware_set_package_info_unsupported,
432};
433#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */