blob: 72c560dbc2235e0f514b5e56077e27321597673d [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>
14#include <linux/list.h>
15
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +090016/* Place holder; not supported */
17static
18efi_status_t EFIAPI efi_firmware_get_image_unsupported(
19 struct efi_firmware_management_protocol *this,
20 u8 image_index,
21 void *image,
22 efi_uintn_t *image_size)
23{
24 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
25
26 return EFI_EXIT(EFI_UNSUPPORTED);
27}
28
29/* Place holder; not supported */
30static
31efi_status_t EFIAPI efi_firmware_check_image_unsupported(
32 struct efi_firmware_management_protocol *this,
33 u8 image_index,
34 const void *image,
35 efi_uintn_t *image_size,
36 u32 *image_updatable)
37{
38 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
39 image_updatable);
40
41 return EFI_EXIT(EFI_UNSUPPORTED);
42}
43
44/* Place holder; not supported */
45static
46efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
47 struct efi_firmware_management_protocol *this,
48 u32 *package_version,
49 u16 **package_version_name,
50 u32 *package_version_name_maxlen,
51 u64 *attributes_supported,
52 u64 *attributes_setting)
53{
54 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
55 package_version_name, package_version_name_maxlen,
56 attributes_supported, attributes_setting);
57
58 return EFI_EXIT(EFI_UNSUPPORTED);
59}
60
61/* Place holder; not supported */
62static
63efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
64 struct efi_firmware_management_protocol *this,
65 const void *image,
66 efi_uintn_t *image_size,
67 const void *vendor_code,
68 u32 package_version,
69 const u16 *package_version_name)
70{
71 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
72 package_version, package_version_name);
73
74 return EFI_EXIT(EFI_UNSUPPORTED);
75}
AKASHI Takahirof27c2012020-11-30 18:12:12 +090076
77/**
78 * efi_get_dfu_info - return information about the current firmware image
79 * @this: Protocol instance
80 * @image_info_size: Size of @image_info
81 * @image_info: Image information
82 * @descriptor_version: Pointer to version number
83 * @descriptor_count: Pointer to number of descriptors
84 * @descriptor_size: Pointer to descriptor size
85 * package_version: Package version
86 * package_version_name: Package version's name
87 * image_type: Image type GUID
88 *
89 * Return information bout the current firmware image in @image_info.
90 * @image_info will consist of a number of descriptors.
91 * Each descriptor will be created based on "dfu_alt_info" variable.
92 *
93 * Return status code
94 */
95static efi_status_t efi_get_dfu_info(
96 efi_uintn_t *image_info_size,
97 struct efi_firmware_image_descriptor *image_info,
98 u32 *descriptor_version,
99 u8 *descriptor_count,
100 efi_uintn_t *descriptor_size,
101 u32 *package_version,
102 u16 **package_version_name,
103 const efi_guid_t *image_type)
104{
105 struct dfu_entity *dfu;
106 size_t names_len, total_size;
107 int dfu_num, i;
108 u16 *name, *next;
109
110 dfu_init_env_entities(NULL, NULL);
111
112 names_len = 0;
113 dfu_num = 0;
114 list_for_each_entry(dfu, &dfu_list, list) {
115 names_len += (utf8_utf16_strlen(dfu->name) + 1) * 2;
116 dfu_num++;
117 }
118 if (!dfu_num) {
119 log_warning("Probably dfu_alt_info not defined\n");
120 *image_info_size = 0;
121 dfu_free_entities();
122
123 return EFI_SUCCESS;
124 }
125
126 total_size = sizeof(*image_info) * dfu_num + names_len;
127 /*
128 * we will assume that sizeof(*image_info) * dfu_name
129 * is, at least, a multiple of 2. So the start address for
130 * image_id_name would be aligned with 2 bytes.
131 */
132 if (*image_info_size < total_size) {
133 *image_info_size = total_size;
134 dfu_free_entities();
135
136 return EFI_BUFFER_TOO_SMALL;
137 }
138 *image_info_size = total_size;
139
140 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
141 *descriptor_count = dfu_num;
142 *descriptor_size = sizeof(*image_info);
143 *package_version = 0xffffffff; /* not supported */
144 *package_version_name = NULL; /* not supported */
145
146 /* DFU alt number should correspond to image_index */
147 i = 0;
148 /* Name area starts just after descriptors */
149 name = (u16 *)((u8 *)image_info + sizeof(*image_info) * dfu_num);
150 next = name;
151 list_for_each_entry(dfu, &dfu_list, list) {
152 image_info[i].image_index = dfu->alt + 1;
153 image_info[i].image_type_id = *image_type;
154 image_info[i].image_id = dfu->alt;
155
156 /* copy the DFU entity name */
157 utf8_utf16_strcpy(&next, dfu->name);
158 image_info[i].image_id_name = name;
159 name = ++next;
160
161 image_info[i].version = 0; /* not supported */
162 image_info[i].version_name = NULL; /* not supported */
163 image_info[i].size = 0;
164 image_info[i].attributes_supported =
165 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
166 image_info[i].attributes_setting =
167 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
168 image_info[i].lowest_supported_image_version = 0;
169 image_info[i].last_attempt_version = 0;
170 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
171 image_info[i].hardware_instance = 1;
172 image_info[i].dependencies = NULL;
173
174 i++;
175 }
176
177 dfu_free_entities();
178
179 return EFI_SUCCESS;
180}
181
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900182#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
183/*
184 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
185 * method with existing FIT image format, and handles
186 * - multiple regions of firmware via DFU
187 * but doesn't support
188 * - versioning of firmware image
189 * - package information
190 */
191const efi_guid_t efi_firmware_image_type_uboot_fit =
192 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
193
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900194/**
195 * efi_firmware_fit_get_image_info - return information about the current
196 * firmware image
197 * @this: Protocol instance
198 * @image_info_size: Size of @image_info
199 * @image_info: Image information
200 * @descriptor_version: Pointer to version number
201 * @descriptor_count: Pointer to number of descriptors
202 * @descriptor_size: Pointer to descriptor size
203 * package_version: Package version
204 * package_version_name: Package version's name
205 *
206 * Return information bout the current firmware image in @image_info.
207 * @image_info will consist of a number of descriptors.
208 * Each descriptor will be created based on "dfu_alt_info" variable.
209 *
210 * Return status code
211 */
212static
213efi_status_t EFIAPI efi_firmware_fit_get_image_info(
214 struct efi_firmware_management_protocol *this,
215 efi_uintn_t *image_info_size,
216 struct efi_firmware_image_descriptor *image_info,
217 u32 *descriptor_version,
218 u8 *descriptor_count,
219 efi_uintn_t *descriptor_size,
220 u32 *package_version,
221 u16 **package_version_name)
222{
223 efi_status_t ret;
224
225 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
226 image_info_size, image_info,
227 descriptor_version, descriptor_count, descriptor_size,
228 package_version, package_version_name);
229
230 if (!image_info_size)
231 return EFI_EXIT(EFI_INVALID_PARAMETER);
232
233 if (*image_info_size &&
234 (!image_info || !descriptor_version || !descriptor_count ||
235 !descriptor_size || !package_version || !package_version_name))
236 return EFI_EXIT(EFI_INVALID_PARAMETER);
237
238 ret = efi_get_dfu_info(image_info_size, image_info,
239 descriptor_version, descriptor_count,
240 descriptor_size,
241 package_version, package_version_name,
242 &efi_firmware_image_type_uboot_fit);
243
244 return EFI_EXIT(ret);
245}
246
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900247/**
248 * efi_firmware_fit_set_image - update the firmware image
249 * @this: Protocol instance
250 * @image_index: Image index number
251 * @image: New image
252 * @image_size: Size of new image
253 * @vendor_code: Vendor-specific update policy
254 * @progress: Function to report the progress of update
255 * @abort_reason: Pointer to string of abort reason
256 *
257 * Update the firmware to new image, using dfu. The new image should
258 * have FIT image format commonly used in U-Boot.
259 * @vendor_code, @progress and @abort_reason are not supported.
260 *
261 * Return: status code
262 */
263static
264efi_status_t EFIAPI efi_firmware_fit_set_image(
265 struct efi_firmware_management_protocol *this,
266 u8 image_index,
267 const void *image,
268 efi_uintn_t image_size,
269 const void *vendor_code,
270 efi_status_t (*progress)(efi_uintn_t completion),
271 u16 **abort_reason)
272{
273 EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
274 image_size, vendor_code, progress, abort_reason);
275
276 if (!image || image_index != 1)
277 return EFI_EXIT(EFI_INVALID_PARAMETER);
278
279 if (fit_update(image))
280 return EFI_EXIT(EFI_DEVICE_ERROR);
281
282 return EFI_EXIT(EFI_SUCCESS);
283}
284
AKASHI Takahirof27c2012020-11-30 18:12:12 +0900285const struct efi_firmware_management_protocol efi_fmp_fit = {
286 .get_image_info = efi_firmware_fit_get_image_info,
287 .get_image = efi_firmware_get_image_unsupported,
288 .set_image = efi_firmware_fit_set_image,
289 .check_image = efi_firmware_check_image_unsupported,
290 .get_package_info = efi_firmware_get_package_info_unsupported,
291 .set_package_info = efi_firmware_set_package_info_unsupported,
292};
AKASHI Takahirobb7e71d2020-11-17 09:28:00 +0900293#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
294
295#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
296/*
297 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
298 * method with raw data.
299 */
300const efi_guid_t efi_firmware_image_type_uboot_raw =
301 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
302
303/**
304 * efi_firmware_raw_get_image_info - return information about the current
305 firmware image
306 * @this: Protocol instance
307 * @image_info_size: Size of @image_info
308 * @image_info: Image information
309 * @descriptor_version: Pointer to version number
310 * @descriptor_count: Pointer to number of descriptors
311 * @descriptor_size: Pointer to descriptor size
312 * package_version: Package version
313 * package_version_name: Package version's name
314 *
315 * Return information bout the current firmware image in @image_info.
316 * @image_info will consist of a number of descriptors.
317 * Each descriptor will be created based on "dfu_alt_info" variable.
318 *
319 * Return status code
320 */
321static
322efi_status_t EFIAPI efi_firmware_raw_get_image_info(
323 struct efi_firmware_management_protocol *this,
324 efi_uintn_t *image_info_size,
325 struct efi_firmware_image_descriptor *image_info,
326 u32 *descriptor_version,
327 u8 *descriptor_count,
328 efi_uintn_t *descriptor_size,
329 u32 *package_version,
330 u16 **package_version_name)
331{
332 efi_status_t ret = EFI_SUCCESS;
333
334 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
335 image_info_size, image_info,
336 descriptor_version, descriptor_count, descriptor_size,
337 package_version, package_version_name);
338
339 if (!image_info_size)
340 return EFI_EXIT(EFI_INVALID_PARAMETER);
341
342 if (*image_info_size &&
343 (!image_info || !descriptor_version || !descriptor_count ||
344 !descriptor_size || !package_version || !package_version_name))
345 return EFI_EXIT(EFI_INVALID_PARAMETER);
346
347 ret = efi_get_dfu_info(image_info_size, image_info,
348 descriptor_version, descriptor_count,
349 descriptor_size,
350 package_version, package_version_name,
351 &efi_firmware_image_type_uboot_raw);
352
353 return EFI_EXIT(ret);
354}
355
356/**
357 * efi_firmware_raw_set_image - update the firmware image
358 * @this: Protocol instance
359 * @image_index: Image index number
360 * @image: New image
361 * @image_size: Size of new image
362 * @vendor_code: Vendor-specific update policy
363 * @progress: Function to report the progress of update
364 * @abort_reason: Pointer to string of abort reason
365 *
366 * Update the firmware to new image, using dfu. The new image should
367 * be a single raw image.
368 * @vendor_code, @progress and @abort_reason are not supported.
369 *
370 * Return: status code
371 */
372static
373efi_status_t EFIAPI efi_firmware_raw_set_image(
374 struct efi_firmware_management_protocol *this,
375 u8 image_index,
376 const void *image,
377 efi_uintn_t image_size,
378 const void *vendor_code,
379 efi_status_t (*progress)(efi_uintn_t completion),
380 u16 **abort_reason)
381{
382 EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
383 image_size, vendor_code, progress, abort_reason);
384
385 if (!image)
386 return EFI_EXIT(EFI_INVALID_PARAMETER);
387
388 if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
389 NULL, NULL))
390 return EFI_EXIT(EFI_DEVICE_ERROR);
391
392 return EFI_EXIT(EFI_SUCCESS);
393}
394
395const struct efi_firmware_management_protocol efi_fmp_raw = {
396 .get_image_info = efi_firmware_raw_get_image_info,
397 .get_image = efi_firmware_get_image_unsupported,
398 .set_image = efi_firmware_raw_set_image,
399 .check_image = efi_firmware_check_image_unsupported,
400 .get_package_info = efi_firmware_get_package_info_unsupported,
401 .set_package_info = efi_firmware_set_package_info_unsupported,
402};
403#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */