]> Git Repo - J-u-boot.git/blob - lib/efi_loader/efi_firmware.c
FWU: Add support for the FWU Multi Bank Update feature
[J-u-boot.git] / lib / efi_loader / efi_firmware.c
1 // 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 <fwu.h>
14 #include <image.h>
15 #include <signatures.h>
16
17 #include <linux/list.h>
18
19 #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  */
32 struct fmp_payload_header {
33         u32 signature;
34         u32 header_size;
35         u32 fw_version;
36         u32 lowest_supported_version;
37 };
38
39 __weak void set_dfu_alt_info(char *interface, char *devstr)
40 {
41         env_set("dfu_alt_info", update_info.dfu_string);
42 }
43
44 /* Place holder; not supported */
45 static
46 efi_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 */
58 static
59 efi_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 */
73 static
74 efi_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 */
90 static
91 efi_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 }
104
105 /**
106  * efi_fill_image_desc_array - populate image descriptor array
107  * @image_info_size:            Size of @image_info
108  * @image_info:                 Image information
109  * @descriptor_version:         Pointer to version number
110  * @descriptor_count:           Image count
111  * @descriptor_size:            Pointer to descriptor size
112  * @package_version:            Package version
113  * @package_version_name:       Package version's name
114  *
115  * Return information about the current firmware image in @image_info.
116  * @image_info will consist of a number of descriptors.
117  * Each descriptor will be created based on efi_fw_image array.
118  *
119  * Return               status code
120  */
121 static efi_status_t efi_fill_image_desc_array(
122         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,
128         u16 **package_version_name)
129 {
130         size_t total_size;
131         struct efi_fw_image *fw_array;
132         int i;
133
134         total_size = sizeof(*image_info) * num_image_type_guids;
135
136         if (*image_info_size < total_size) {
137                 *image_info_size = total_size;
138
139                 return EFI_BUFFER_TOO_SMALL;
140         }
141         *image_info_size = total_size;
142
143         fw_array = update_info.images;
144         *descriptor_count = num_image_type_guids;
145         *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
146         *descriptor_size = sizeof(*image_info);
147         *package_version = 0xffffffff; /* not supported */
148         *package_version_name = NULL; /* not supported */
149
150         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;
154
155                 image_info[i].image_id_name = fw_array[i].fw_name;
156
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 =
161                         IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
162                         IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
163                 image_info[i].attributes_setting =
164                                 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
165
166                 /* Check if the capsule authentication is enabled */
167                 if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
168                         image_info[0].attributes_setting |=
169                                 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
170
171                 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;
176         }
177
178         return EFI_SUCCESS;
179 }
180
181 /**
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  */
191 static
192 efi_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
245 /**
246  * efi_firmware_get_image_info - return information about the current
247  *                                   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
254  * @package_version:            Package version
255  * @package_version_name:       Package version's name
256  *
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  */
263 static
264 efi_status_t EFIAPI efi_firmware_get_image_info(
265         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
289         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);
293
294         return EFI_EXIT(ret);
295 }
296
297 #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
307 /**
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  */
323 static
324 efi_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 {
333         efi_status_t status;
334
335         EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
336                   image_size, vendor_code, progress, abort_reason);
337
338         if (!image || image_index != 1)
339                 return EFI_EXIT(EFI_INVALID_PARAMETER);
340
341         status = efi_firmware_capsule_authenticate(&image, &image_size);
342         if (status != EFI_SUCCESS)
343                 return EFI_EXIT(status);
344
345         if (fit_update(image))
346                 return EFI_EXIT(EFI_DEVICE_ERROR);
347
348         return EFI_EXIT(EFI_SUCCESS);
349 }
350
351 const struct efi_firmware_management_protocol efi_fmp_fit = {
352         .get_image_info = efi_firmware_get_image_info,
353         .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 };
359 #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  */
366
367 /**
368  * 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  */
383 static
384 efi_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 {
393         int ret;
394         efi_status_t status;
395
396         EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
397                   image_size, vendor_code, progress, abort_reason);
398
399         if (!image)
400                 return EFI_EXIT(EFI_INVALID_PARAMETER);
401
402         status = efi_firmware_capsule_authenticate(&image, &image_size);
403         if (status != EFI_SUCCESS)
404                 return EFI_EXIT(status);
405
406         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
418         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
425 const struct efi_firmware_management_protocol efi_fmp_raw = {
426         .get_image_info = efi_firmware_get_image_info,
427         .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 */
This page took 0.051288 seconds and 4 git commands to generate.