a1b88dbfc286692b1d51ae5e7313c068c0a9f1e6
[platform/kernel/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 <image.h>
14 #include <signatures.h>
15
16 #include <linux/list.h>
17
18 #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  */
31 struct fmp_payload_header {
32         u32 signature;
33         u32 header_size;
34         u32 fw_version;
35         u32 lowest_supported_version;
36 };
37
38 /* Place holder; not supported */
39 static
40 efi_status_t EFIAPI efi_firmware_get_image_unsupported(
41         struct efi_firmware_management_protocol *this,
42         u8 image_index,
43         void *image,
44         efi_uintn_t *image_size)
45 {
46         EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
47
48         return EFI_EXIT(EFI_UNSUPPORTED);
49 }
50
51 /* Place holder; not supported */
52 static
53 efi_status_t EFIAPI efi_firmware_check_image_unsupported(
54         struct efi_firmware_management_protocol *this,
55         u8 image_index,
56         const void *image,
57         efi_uintn_t *image_size,
58         u32 *image_updatable)
59 {
60         EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
61                   image_updatable);
62
63         return EFI_EXIT(EFI_UNSUPPORTED);
64 }
65
66 /* Place holder; not supported */
67 static
68 efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
69         struct efi_firmware_management_protocol *this,
70         u32 *package_version,
71         u16 **package_version_name,
72         u32 *package_version_name_maxlen,
73         u64 *attributes_supported,
74         u64 *attributes_setting)
75 {
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);
79
80         return EFI_EXIT(EFI_UNSUPPORTED);
81 }
82
83 /* Place holder; not supported */
84 static
85 efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
86         struct efi_firmware_management_protocol *this,
87         const void *image,
88         efi_uintn_t *image_size,
89         const void *vendor_code,
90         u32 package_version,
91         const u16 *package_version_name)
92 {
93         EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
94                   package_version, package_version_name);
95
96         return EFI_EXIT(EFI_UNSUPPORTED);
97 }
98
99 /**
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
110  *
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.
114  *
115  * Return               status code
116  */
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)
126 {
127         struct dfu_entity *dfu;
128         size_t names_len, total_size;
129         int dfu_num, i;
130         u16 *name, *next;
131
132         dfu_init_env_entities(NULL, NULL);
133
134         names_len = 0;
135         dfu_num = 0;
136         list_for_each_entry(dfu, &dfu_list, list) {
137                 names_len += (utf8_utf16_strlen(dfu->name) + 1) * 2;
138                 dfu_num++;
139         }
140         if (!dfu_num) {
141                 log_warning("Probably dfu_alt_info not defined\n");
142                 *image_info_size = 0;
143                 dfu_free_entities();
144
145                 return EFI_SUCCESS;
146         }
147
148         total_size = sizeof(*image_info) * dfu_num + names_len;
149         /*
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.
153          */
154         if (*image_info_size < total_size) {
155                 *image_info_size = total_size;
156                 dfu_free_entities();
157
158                 return EFI_BUFFER_TOO_SMALL;
159         }
160         *image_info_size = total_size;
161
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 */
167
168         /* DFU alt number should correspond to image_index */
169         i = 0;
170         /* Name area starts just after descriptors */
171         name = (u16 *)((u8 *)image_info + sizeof(*image_info) * dfu_num);
172         next = name;
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;
177
178                 /* copy the DFU entity name */
179                 utf8_utf16_strcpy(&next, dfu->name);
180                 image_info[i].image_id_name = name;
181                 name = ++next;
182
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;
191
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;
196
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;
202
203                 i++;
204         }
205
206         dfu_free_entities();
207
208         return EFI_SUCCESS;
209 }
210
211 #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
212 /*
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
219  */
220 const efi_guid_t efi_firmware_image_type_uboot_fit =
221         EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
222
223 /**
224  * efi_firmware_fit_get_image_info - return information about the current
225  *                                   firmware image
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
234  *
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.
238  *
239  * Return               status code
240  */
241 static
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)
251 {
252         efi_status_t ret;
253
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);
258
259         if (!image_info_size)
260                 return EFI_EXIT(EFI_INVALID_PARAMETER);
261
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);
266
267         ret = efi_get_dfu_info(image_info_size, image_info,
268                                descriptor_version, descriptor_count,
269                                descriptor_size,
270                                package_version, package_version_name,
271                                &efi_firmware_image_type_uboot_fit);
272
273         return EFI_EXIT(ret);
274 }
275
276 /**
277  * efi_firmware_fit_set_image - update the firmware image
278  * @this:               Protocol instance
279  * @image_index:        Image index number
280  * @image:              New image
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
285  *
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.
289  *
290  * Return:              status code
291  */
292 static
293 efi_status_t EFIAPI efi_firmware_fit_set_image(
294         struct efi_firmware_management_protocol *this,
295         u8 image_index,
296         const void *image,
297         efi_uintn_t image_size,
298         const void *vendor_code,
299         efi_status_t (*progress)(efi_uintn_t completion),
300         u16 **abort_reason)
301 {
302         EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
303                   image_size, vendor_code, progress, abort_reason);
304
305         if (!image || image_index != 1)
306                 return EFI_EXIT(EFI_INVALID_PARAMETER);
307
308         if (fit_update(image))
309                 return EFI_EXIT(EFI_DEVICE_ERROR);
310
311         return EFI_EXIT(EFI_SUCCESS);
312 }
313
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,
321 };
322 #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
323
324 #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
325 /*
326  * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
327  * method with raw data.
328  */
329 const efi_guid_t efi_firmware_image_type_uboot_raw =
330         EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
331
332 /**
333  * efi_firmware_raw_get_image_info - return information about the current
334                                      firmware image
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
343  *
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.
347  *
348  * Return               status code
349  */
350 static
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)
360 {
361         efi_status_t ret = EFI_SUCCESS;
362
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);
367
368         if (!image_info_size)
369                 return EFI_EXIT(EFI_INVALID_PARAMETER);
370
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);
375
376         ret = efi_get_dfu_info(image_info_size, image_info,
377                                descriptor_version, descriptor_count,
378                                descriptor_size,
379                                package_version, package_version_name,
380                                &efi_firmware_image_type_uboot_raw);
381
382         return EFI_EXIT(ret);
383 }
384
385 /**
386  * efi_firmware_raw_set_image - update the firmware image
387  * @this:               Protocol instance
388  * @image_index:        Image index number
389  * @image:              New image
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
394  *
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.
398  *
399  * Return:              status code
400  */
401 static
402 efi_status_t EFIAPI efi_firmware_raw_set_image(
403         struct efi_firmware_management_protocol *this,
404         u8 image_index,
405         const void *image,
406         efi_uintn_t image_size,
407         const void *vendor_code,
408         efi_status_t (*progress)(efi_uintn_t completion),
409         u16 **abort_reason)
410 {
411         u32 fmp_hdr_signature;
412         struct fmp_payload_header *header;
413         void *capsule_payload;
414         efi_status_t status;
415         efi_uintn_t capsule_payload_size;
416
417         EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
418                   image_size, vendor_code, progress, abort_reason);
419
420         if (!image)
421                 return EFI_EXIT(EFI_INVALID_PARAMETER);
422
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,
428                                                   &capsule_payload,
429                                                   &capsule_payload_size);
430
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);
436                 }
437
438                 debug("Capsule authentication successfull\n");
439                 image = capsule_payload;
440                 image_size = capsule_payload_size;
441         } else {
442                 debug("Capsule authentication disabled. ");
443                 debug("Updating capsule without authenticating.\n");
444         }
445
446         fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
447         header = (void *)image;
448
449         if (!memcmp(&header->signature, &fmp_hdr_signature,
450                     sizeof(fmp_hdr_signature))) {
451                 /*
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.
456                  */
457                 image += header->header_size;
458                 image_size -= header->header_size;
459
460         }
461
462         if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
463                              NULL, NULL))
464                 return EFI_EXIT(EFI_DEVICE_ERROR);
465
466         return EFI_EXIT(EFI_SUCCESS);
467 }
468
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,
476 };
477 #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */