blob: 15d33ba59112d1766f617dbde0bba7f1aa5cd4f9 [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
16/*
17 * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
18 * method with existing FIT image format, and handles
19 * - multiple regions of firmware via DFU
20 * but doesn't support
21 * - versioning of firmware image
22 * - package information
23 */
24const efi_guid_t efi_firmware_image_type_uboot_fit =
25 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
26
27/**
28 * efi_get_dfu_info - return information about the current firmware image
29 * @this: Protocol instance
30 * @image_info_size: Size of @image_info
31 * @image_info: Image information
32 * @descriptor_version: Pointer to version number
33 * @descriptor_count: Pointer to number of descriptors
34 * @descriptor_size: Pointer to descriptor size
35 * package_version: Package version
36 * package_version_name: Package version's name
37 * image_type: Image type GUID
38 *
39 * Return information bout the current firmware image in @image_info.
40 * @image_info will consist of a number of descriptors.
41 * Each descriptor will be created based on "dfu_alt_info" variable.
42 *
43 * Return status code
44 */
45static efi_status_t efi_get_dfu_info(
46 efi_uintn_t *image_info_size,
47 struct efi_firmware_image_descriptor *image_info,
48 u32 *descriptor_version,
49 u8 *descriptor_count,
50 efi_uintn_t *descriptor_size,
51 u32 *package_version,
52 u16 **package_version_name,
53 const efi_guid_t *image_type)
54{
55 struct dfu_entity *dfu;
56 size_t names_len, total_size;
57 int dfu_num, i;
58 u16 *name, *next;
59
60 dfu_init_env_entities(NULL, NULL);
61
62 names_len = 0;
63 dfu_num = 0;
64 list_for_each_entry(dfu, &dfu_list, list) {
65 names_len += (utf8_utf16_strlen(dfu->name) + 1) * 2;
66 dfu_num++;
67 }
68 if (!dfu_num) {
69 log_warning("Probably dfu_alt_info not defined\n");
70 *image_info_size = 0;
71 dfu_free_entities();
72
73 return EFI_SUCCESS;
74 }
75
76 total_size = sizeof(*image_info) * dfu_num + names_len;
77 /*
78 * we will assume that sizeof(*image_info) * dfu_name
79 * is, at least, a multiple of 2. So the start address for
80 * image_id_name would be aligned with 2 bytes.
81 */
82 if (*image_info_size < total_size) {
83 *image_info_size = total_size;
84 dfu_free_entities();
85
86 return EFI_BUFFER_TOO_SMALL;
87 }
88 *image_info_size = total_size;
89
90 *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
91 *descriptor_count = dfu_num;
92 *descriptor_size = sizeof(*image_info);
93 *package_version = 0xffffffff; /* not supported */
94 *package_version_name = NULL; /* not supported */
95
96 /* DFU alt number should correspond to image_index */
97 i = 0;
98 /* Name area starts just after descriptors */
99 name = (u16 *)((u8 *)image_info + sizeof(*image_info) * dfu_num);
100 next = name;
101 list_for_each_entry(dfu, &dfu_list, list) {
102 image_info[i].image_index = dfu->alt + 1;
103 image_info[i].image_type_id = *image_type;
104 image_info[i].image_id = dfu->alt;
105
106 /* copy the DFU entity name */
107 utf8_utf16_strcpy(&next, dfu->name);
108 image_info[i].image_id_name = name;
109 name = ++next;
110
111 image_info[i].version = 0; /* not supported */
112 image_info[i].version_name = NULL; /* not supported */
113 image_info[i].size = 0;
114 image_info[i].attributes_supported =
115 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
116 image_info[i].attributes_setting =
117 IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
118 image_info[i].lowest_supported_image_version = 0;
119 image_info[i].last_attempt_version = 0;
120 image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
121 image_info[i].hardware_instance = 1;
122 image_info[i].dependencies = NULL;
123
124 i++;
125 }
126
127 dfu_free_entities();
128
129 return EFI_SUCCESS;
130}
131
132/**
133 * efi_firmware_fit_get_image_info - return information about the current
134 * firmware image
135 * @this: Protocol instance
136 * @image_info_size: Size of @image_info
137 * @image_info: Image information
138 * @descriptor_version: Pointer to version number
139 * @descriptor_count: Pointer to number of descriptors
140 * @descriptor_size: Pointer to descriptor size
141 * package_version: Package version
142 * package_version_name: Package version's name
143 *
144 * Return information bout the current firmware image in @image_info.
145 * @image_info will consist of a number of descriptors.
146 * Each descriptor will be created based on "dfu_alt_info" variable.
147 *
148 * Return status code
149 */
150static
151efi_status_t EFIAPI efi_firmware_fit_get_image_info(
152 struct efi_firmware_management_protocol *this,
153 efi_uintn_t *image_info_size,
154 struct efi_firmware_image_descriptor *image_info,
155 u32 *descriptor_version,
156 u8 *descriptor_count,
157 efi_uintn_t *descriptor_size,
158 u32 *package_version,
159 u16 **package_version_name)
160{
161 efi_status_t ret;
162
163 EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
164 image_info_size, image_info,
165 descriptor_version, descriptor_count, descriptor_size,
166 package_version, package_version_name);
167
168 if (!image_info_size)
169 return EFI_EXIT(EFI_INVALID_PARAMETER);
170
171 if (*image_info_size &&
172 (!image_info || !descriptor_version || !descriptor_count ||
173 !descriptor_size || !package_version || !package_version_name))
174 return EFI_EXIT(EFI_INVALID_PARAMETER);
175
176 ret = efi_get_dfu_info(image_info_size, image_info,
177 descriptor_version, descriptor_count,
178 descriptor_size,
179 package_version, package_version_name,
180 &efi_firmware_image_type_uboot_fit);
181
182 return EFI_EXIT(ret);
183}
184
185/* Place holder; not supported */
186static
187efi_status_t EFIAPI efi_firmware_get_image_unsupported(
188 struct efi_firmware_management_protocol *this,
189 u8 image_index,
190 void *image,
191 efi_uintn_t *image_size)
192{
193 EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
194
195 return EFI_EXIT(EFI_UNSUPPORTED);
196}
197
198/**
199 * efi_firmware_fit_set_image - update the firmware image
200 * @this: Protocol instance
201 * @image_index: Image index number
202 * @image: New image
203 * @image_size: Size of new image
204 * @vendor_code: Vendor-specific update policy
205 * @progress: Function to report the progress of update
206 * @abort_reason: Pointer to string of abort reason
207 *
208 * Update the firmware to new image, using dfu. The new image should
209 * have FIT image format commonly used in U-Boot.
210 * @vendor_code, @progress and @abort_reason are not supported.
211 *
212 * Return: status code
213 */
214static
215efi_status_t EFIAPI efi_firmware_fit_set_image(
216 struct efi_firmware_management_protocol *this,
217 u8 image_index,
218 const void *image,
219 efi_uintn_t image_size,
220 const void *vendor_code,
221 efi_status_t (*progress)(efi_uintn_t completion),
222 u16 **abort_reason)
223{
224 EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
225 image_size, vendor_code, progress, abort_reason);
226
227 if (!image || image_index != 1)
228 return EFI_EXIT(EFI_INVALID_PARAMETER);
229
230 if (fit_update(image))
231 return EFI_EXIT(EFI_DEVICE_ERROR);
232
233 return EFI_EXIT(EFI_SUCCESS);
234}
235
236/* Place holder; not supported */
237static
238efi_status_t EFIAPI efi_firmware_check_image_unsupported(
239 struct efi_firmware_management_protocol *this,
240 u8 image_index,
241 const void *image,
242 efi_uintn_t *image_size,
243 u32 *image_updatable)
244{
245 EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
246 image_updatable);
247
248 return EFI_EXIT(EFI_UNSUPPORTED);
249}
250
251/* Place holder; not supported */
252static
253efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
254 struct efi_firmware_management_protocol *this,
255 u32 *package_version,
256 u16 **package_version_name,
257 u32 *package_version_name_maxlen,
258 u64 *attributes_supported,
259 u64 *attributes_setting)
260{
261 EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
262 package_version_name, package_version_name_maxlen,
263 attributes_supported, attributes_setting);
264
265 return EFI_EXIT(EFI_UNSUPPORTED);
266}
267
268/* Place holder; not supported */
269static
270efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
271 struct efi_firmware_management_protocol *this,
272 const void *image,
273 efi_uintn_t *image_size,
274 const void *vendor_code,
275 u32 package_version,
276 const u16 *package_version_name)
277{
278 EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
279 package_version, package_version_name);
280
281 return EFI_EXIT(EFI_UNSUPPORTED);
282}
283
284const struct efi_firmware_management_protocol efi_fmp_fit = {
285 .get_image_info = efi_firmware_fit_get_image_info,
286 .get_image = efi_firmware_get_image_unsupported,
287 .set_image = efi_firmware_fit_set_image,
288 .check_image = efi_firmware_check_image_unsupported,
289 .get_package_info = efi_firmware_get_package_info_unsupported,
290 .set_package_info = efi_firmware_set_package_info_unsupported,
291};