blob: 5d2ecde2f152efeffeda79f2c822f2703bcc32d6 [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>
13#include <image.h>
Sughosh Ganu675b62e2020-12-30 19:27:05 +053014#include <signatures.h>
15
AKASHI Takahirof27c2012020-11-30 18:12:12 +090016#include <linux/list.h>
17
Sughosh Ganu675b62e2020-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
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +090038/* Place holder; not supported */
39static
40efi_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 */
52static
53efi_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 */
67static
68efi_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 */
84static
85efi_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}
AKASHI Takahirof27c2012020-11-30 18:12:12 +090098
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 */
117static 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_info[i].attributes_setting =
189 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
190 image_info[i].lowest_supported_image_version = 0;
191 image_info[i].last_attempt_version = 0;
192 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
193 image_info[i].hardware_instance = 1;
194 image_info[i].dependencies = NULL;
195
196 i++;
197 }
198
199 dfu_free_entities();
200
201 return EFI_SUCCESS;
202}
203
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900204#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
205/*
206 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
207 * method with existing FIT image format, and handles
208 * - multiple regions of firmware via DFU
209 * but doesn't support
210 * - versioning of firmware image
211 * - package information
212 */
213const efi_guid_t efi_firmware_image_type_uboot_fit =
214 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
215
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900216/**
217 * efi_firmware_fit_get_image_info - return information about the current
218 * firmware image
219 * @this: Protocol instance
220 * @image_info_size: Size of @image_info
221 * @image_info: Image information
222 * @descriptor_version: Pointer to version number
223 * @descriptor_count: Pointer to number of descriptors
224 * @descriptor_size: Pointer to descriptor size
225 * package_version: Package version
226 * package_version_name: Package version's name
227 *
228 * Return information bout the current firmware image in @image_info.
229 * @image_info will consist of a number of descriptors.
230 * Each descriptor will be created based on "dfu_alt_info" variable.
231 *
232 * Return status code
233 */
234static
235efi_status_t EFIAPI efi_firmware_fit_get_image_info(
236 struct efi_firmware_management_protocol *this,
237 efi_uintn_t *image_info_size,
238 struct efi_firmware_image_descriptor *image_info,
239 u32 *descriptor_version,
240 u8 *descriptor_count,
241 efi_uintn_t *descriptor_size,
242 u32 *package_version,
243 u16 **package_version_name)
244{
245 efi_status_t ret;
246
247 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
248 image_info_size, image_info,
249 descriptor_version, descriptor_count, descriptor_size,
250 package_version, package_version_name);
251
252 if (!image_info_size)
253 return EFI_EXIT(EFI_INVALID_PARAMETER);
254
255 if (*image_info_size &&
256 (!image_info || !descriptor_version || !descriptor_count ||
257 !descriptor_size || !package_version || !package_version_name))
258 return EFI_EXIT(EFI_INVALID_PARAMETER);
259
260 ret = efi_get_dfu_info(image_info_size, image_info,
261 descriptor_version, descriptor_count,
262 descriptor_size,
263 package_version, package_version_name,
264 &efi_firmware_image_type_uboot_fit);
265
266 return EFI_EXIT(ret);
267}
268
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900269/**
270 * efi_firmware_fit_set_image - update the firmware image
271 * @this: Protocol instance
272 * @image_index: Image index number
273 * @image: New image
274 * @image_size: Size of new image
275 * @vendor_code: Vendor-specific update policy
276 * @progress: Function to report the progress of update
277 * @abort_reason: Pointer to string of abort reason
278 *
279 * Update the firmware to new image, using dfu. The new image should
280 * have FIT image format commonly used in U-Boot.
281 * @vendor_code, @progress and @abort_reason are not supported.
282 *
283 * Return: status code
284 */
285static
286efi_status_t EFIAPI efi_firmware_fit_set_image(
287 struct efi_firmware_management_protocol *this,
288 u8 image_index,
289 const void *image,
290 efi_uintn_t image_size,
291 const void *vendor_code,
292 efi_status_t (*progress)(efi_uintn_t completion),
293 u16 **abort_reason)
294{
295 EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
296 image_size, vendor_code, progress, abort_reason);
297
298 if (!image || image_index != 1)
299 return EFI_EXIT(EFI_INVALID_PARAMETER);
300
301 if (fit_update(image))
302 return EFI_EXIT(EFI_DEVICE_ERROR);
303
304 return EFI_EXIT(EFI_SUCCESS);
305}
306
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900307const struct efi_firmware_management_protocol efi_fmp_fit = {
308 .get_image_info = efi_firmware_fit_get_image_info,
309 .get_image = efi_firmware_get_image_unsupported,
310 .set_image = efi_firmware_fit_set_image,
311 .check_image = efi_firmware_check_image_unsupported,
312 .get_package_info = efi_firmware_get_package_info_unsupported,
313 .set_package_info = efi_firmware_set_package_info_unsupported,
314};
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900315#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
316
317#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
318/*
319 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
320 * method with raw data.
321 */
322const efi_guid_t efi_firmware_image_type_uboot_raw =
323 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
324
325/**
326 * efi_firmware_raw_get_image_info - return information about the current
327 firmware image
328 * @this: Protocol instance
329 * @image_info_size: Size of @image_info
330 * @image_info: Image information
331 * @descriptor_version: Pointer to version number
332 * @descriptor_count: Pointer to number of descriptors
333 * @descriptor_size: Pointer to descriptor size
334 * package_version: Package version
335 * package_version_name: Package version's name
336 *
337 * Return information bout the current firmware image in @image_info.
338 * @image_info will consist of a number of descriptors.
339 * Each descriptor will be created based on "dfu_alt_info" variable.
340 *
341 * Return status code
342 */
343static
344efi_status_t EFIAPI efi_firmware_raw_get_image_info(
345 struct efi_firmware_management_protocol *this,
346 efi_uintn_t *image_info_size,
347 struct efi_firmware_image_descriptor *image_info,
348 u32 *descriptor_version,
349 u8 *descriptor_count,
350 efi_uintn_t *descriptor_size,
351 u32 *package_version,
352 u16 **package_version_name)
353{
354 efi_status_t ret = EFI_SUCCESS;
355
356 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
357 image_info_size, image_info,
358 descriptor_version, descriptor_count, descriptor_size,
359 package_version, package_version_name);
360
361 if (!image_info_size)
362 return EFI_EXIT(EFI_INVALID_PARAMETER);
363
364 if (*image_info_size &&
365 (!image_info || !descriptor_version || !descriptor_count ||
366 !descriptor_size || !package_version || !package_version_name))
367 return EFI_EXIT(EFI_INVALID_PARAMETER);
368
369 ret = efi_get_dfu_info(image_info_size, image_info,
370 descriptor_version, descriptor_count,
371 descriptor_size,
372 package_version, package_version_name,
373 &efi_firmware_image_type_uboot_raw);
374
375 return EFI_EXIT(ret);
376}
377
378/**
379 * efi_firmware_raw_set_image - update the firmware image
380 * @this: Protocol instance
381 * @image_index: Image index number
382 * @image: New image
383 * @image_size: Size of new image
384 * @vendor_code: Vendor-specific update policy
385 * @progress: Function to report the progress of update
386 * @abort_reason: Pointer to string of abort reason
387 *
388 * Update the firmware to new image, using dfu. The new image should
389 * be a single raw image.
390 * @vendor_code, @progress and @abort_reason are not supported.
391 *
392 * Return: status code
393 */
394static
395efi_status_t EFIAPI efi_firmware_raw_set_image(
396 struct efi_firmware_management_protocol *this,
397 u8 image_index,
398 const void *image,
399 efi_uintn_t image_size,
400 const void *vendor_code,
401 efi_status_t (*progress)(efi_uintn_t completion),
402 u16 **abort_reason)
403{
Sughosh Ganu675b62e2020-12-30 19:27:05 +0530404 u32 fmp_hdr_signature;
405 struct fmp_payload_header *header;
406
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900407 EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
408 image_size, vendor_code, progress, abort_reason);
409
410 if (!image)
411 return EFI_EXIT(EFI_INVALID_PARAMETER);
412
Sughosh Ganu675b62e2020-12-30 19:27:05 +0530413 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
414 header = (void *)image;
415
416 if (!memcmp(&header->signature, &fmp_hdr_signature,
417 sizeof(fmp_hdr_signature))) {
418 /*
419 * When building the capsule with the scripts in
420 * edk2, a FMP header is inserted above the capsule
421 * payload. Compensate for this header to get the
422 * actual payload that is to be updated.
423 */
424 image += header->header_size;
425 image_size -= header->header_size;
426
427 }
428
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900429 if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
430 NULL, NULL))
431 return EFI_EXIT(EFI_DEVICE_ERROR);
432
433 return EFI_EXIT(EFI_SUCCESS);
434}
435
436const struct efi_firmware_management_protocol efi_fmp_raw = {
437 .get_image_info = efi_firmware_raw_get_image_info,
438 .get_image = efi_firmware_get_image_unsupported,
439 .set_image = efi_firmware_raw_set_image,
440 .check_image = efi_firmware_check_image_unsupported,
441 .get_package_info = efi_firmware_get_package_info_unsupported,
442 .set_package_info = efi_firmware_set_package_info_unsupported,
443};
444#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */