Merge pull request #1450 from MISL-EBU-System-SW/marvell-support-v6
[project/bcm63xx/atf.git] / drivers / io / io_fip.c
1 /*
2 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <bl_common.h>
9 #include <debug.h>
10 #include <errno.h>
11 #include <firmware_image_package.h>
12 #include <io_driver.h>
13 #include <io_fip.h>
14 #include <io_storage.h>
15 #include <platform.h>
16 #include <platform_def.h>
17 #include <stdint.h>
18 #include <string.h>
19 #include <utils.h>
20 #include <uuid.h>
21
22 #ifndef MAX_FIP_DEVICES
23 #define MAX_FIP_DEVICES 1
24 #endif
25
26 /* Useful for printing UUIDs when debugging.*/
27 #define PRINT_UUID2(x) \
28 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", \
29 x.time_low, x.time_mid, x.time_hi_and_version, \
30 x.clock_seq_hi_and_reserved, x.clock_seq_low, \
31 x.node[0], x.node[1], x.node[2], x.node[3], \
32 x.node[4], x.node[5]
33
34 typedef struct {
35 unsigned int file_pos;
36 fip_toc_entry_t entry;
37 } file_state_t;
38
39 /*
40 * Maintain dev_spec per FIP Device
41 * TODO - Add backend handles and file state
42 * per FIP device here once backends like io_memmap
43 * can support multiple open files
44 */
45 typedef struct {
46 uintptr_t dev_spec;
47 } fip_dev_state_t;
48
49 static const uuid_t uuid_null = { {0} };
50 /*
51 * Only one file can be open across all FIP device
52 * as backends like io_memmap don't support
53 * multiple open files. The file state and
54 * backend handle should be maintained per FIP device
55 * if the same support is available in the backend
56 */
57 static file_state_t current_file = {0};
58 static uintptr_t backend_dev_handle;
59 static uintptr_t backend_image_spec;
60
61 static fip_dev_state_t state_pool[MAX_FIP_DEVICES];
62 static io_dev_info_t dev_info_pool[MAX_FIP_DEVICES];
63
64 /* Track number of allocated fip devices */
65 static unsigned int fip_dev_count;
66
67 /* Firmware Image Package driver functions */
68 static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
69 static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
70 io_entity_t *entity);
71 static int fip_file_len(io_entity_t *entity, size_t *length);
72 static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
73 size_t *length_read);
74 static int fip_file_close(io_entity_t *entity);
75 static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
76 static int fip_dev_close(io_dev_info_t *dev_info);
77
78
79 /* Return 0 for equal uuids. */
80 static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
81 {
82 return memcmp(uuid1, uuid2, sizeof(uuid_t));
83 }
84
85
86 /* TODO: We could check version numbers or do a package checksum? */
87 static inline int is_valid_header(fip_toc_header_t *header)
88 {
89 if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
90 return 1;
91 } else {
92 return 0;
93 }
94 }
95
96
97 /* Identify the device type as a virtual driver */
98 static io_type_t device_type_fip(void)
99 {
100 return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
101 }
102
103
104 static const io_dev_connector_t fip_dev_connector = {
105 .dev_open = fip_dev_open
106 };
107
108
109 static const io_dev_funcs_t fip_dev_funcs = {
110 .type = device_type_fip,
111 .open = fip_file_open,
112 .seek = NULL,
113 .size = fip_file_len,
114 .read = fip_file_read,
115 .write = NULL,
116 .close = fip_file_close,
117 .dev_init = fip_dev_init,
118 .dev_close = fip_dev_close,
119 };
120
121 /* Locate a file state in the pool, specified by address */
122 static int find_first_fip_state(const uintptr_t dev_spec,
123 unsigned int *index_out)
124 {
125 int result = -ENOENT;
126 unsigned int index;
127
128 for (index = 0; index < (unsigned int)MAX_FIP_DEVICES; ++index) {
129 /* dev_spec is used as identifier since it's unique */
130 if (state_pool[index].dev_spec == dev_spec) {
131 result = 0;
132 *index_out = index;
133 break;
134 }
135 }
136 return result;
137 }
138
139
140 /* Allocate a device info from the pool and return a pointer to it */
141 static int allocate_dev_info(io_dev_info_t **dev_info)
142 {
143 int result = -ENOMEM;
144
145 assert(dev_info != NULL);
146
147 if (fip_dev_count < (unsigned int)MAX_FIP_DEVICES) {
148 unsigned int index = 0;
149
150 result = find_first_fip_state(0, &index);
151 assert(result == 0);
152 /* initialize dev_info */
153 dev_info_pool[index].funcs = &fip_dev_funcs;
154 dev_info_pool[index].info =
155 (uintptr_t)&state_pool[index];
156 *dev_info = &dev_info_pool[index];
157 ++fip_dev_count;
158 }
159
160 return result;
161 }
162
163 /* Release a device info to the pool */
164 static int free_dev_info(io_dev_info_t *dev_info)
165 {
166 int result;
167 unsigned int index = 0;
168 fip_dev_state_t *state;
169
170 assert(dev_info != NULL);
171
172 state = (fip_dev_state_t *)dev_info->info;
173 result = find_first_fip_state(state->dev_spec, &index);
174 if (result == 0) {
175 /* free if device info is valid */
176 zeromem(state, sizeof(fip_dev_state_t));
177 --fip_dev_count;
178 }
179
180 return result;
181 }
182
183 /*
184 * Multiple FIP devices can be opened depending on the value of
185 * MAX_FIP_DEVICES. Given that there is only one backend, only a
186 * single file can be open at a time by any FIP device.
187 */
188 static int fip_dev_open(const uintptr_t dev_spec,
189 io_dev_info_t **dev_info)
190 {
191 int result;
192 io_dev_info_t *info;
193 fip_dev_state_t *state;
194
195 assert(dev_info != NULL);
196 #if MAX_FIP_DEVICES > 1
197 assert(dev_spec != (uintptr_t)NULL);
198 #endif
199
200 result = allocate_dev_info(&info);
201 if (result != 0)
202 return -ENOMEM;
203
204 state = (fip_dev_state_t *)info->info;
205
206 state->dev_spec = dev_spec;
207
208 *dev_info = info;
209
210 return 0;
211 }
212
213
214 /* Do some basic package checks. */
215 static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
216 {
217 int result;
218 unsigned int image_id = (unsigned int)init_params;
219 uintptr_t backend_handle;
220 fip_toc_header_t header;
221 size_t bytes_read;
222
223 /* Obtain a reference to the image by querying the platform layer */
224 result = plat_get_image_source(image_id, &backend_dev_handle,
225 &backend_image_spec);
226 if (result != 0) {
227 WARN("Failed to obtain reference to image id=%u (%i)\n",
228 image_id, result);
229 result = -ENOENT;
230 goto fip_dev_init_exit;
231 }
232
233 /* Attempt to access the FIP image */
234 result = io_open(backend_dev_handle, backend_image_spec,
235 &backend_handle);
236 if (result != 0) {
237 WARN("Failed to access image id=%u (%i)\n", image_id, result);
238 result = -ENOENT;
239 goto fip_dev_init_exit;
240 }
241
242 result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
243 &bytes_read);
244 if (result == 0) {
245 if (!is_valid_header(&header)) {
246 WARN("Firmware Image Package header check failed.\n");
247 result = -ENOENT;
248 } else {
249 VERBOSE("FIP header looks OK.\n");
250 }
251 }
252
253 io_close(backend_handle);
254
255 fip_dev_init_exit:
256 return result;
257 }
258
259 /* Close a connection to the FIP device */
260 static int fip_dev_close(io_dev_info_t *dev_info)
261 {
262 /* TODO: Consider tracking open files and cleaning them up here */
263
264 /* Clear the backend. */
265 backend_dev_handle = (uintptr_t)NULL;
266 backend_image_spec = (uintptr_t)NULL;
267
268 return free_dev_info(dev_info);
269 }
270
271
272 /* Open a file for access from package. */
273 static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
274 io_entity_t *entity)
275 {
276 int result;
277 uintptr_t backend_handle;
278 const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
279 size_t bytes_read;
280 int found_file = 0;
281
282 assert(uuid_spec != NULL);
283 assert(entity != NULL);
284
285 /* Can only have one file open at a time for the moment. We need to
286 * track state like file cursor position. We know the header lives at
287 * offset zero, so this entry should never be zero for an active file.
288 * When the system supports dynamic memory allocation we can allow more
289 * than one open file at a time if needed.
290 */
291 if (current_file.entry.offset_address != 0) {
292 WARN("fip_file_open : Only one open file at a time.\n");
293 return -ENOMEM;
294 }
295
296 /* Attempt to access the FIP image */
297 result = io_open(backend_dev_handle, backend_image_spec,
298 &backend_handle);
299 if (result != 0) {
300 WARN("Failed to open Firmware Image Package (%i)\n", result);
301 result = -ENOENT;
302 goto fip_file_open_exit;
303 }
304
305 /* Seek past the FIP header into the Table of Contents */
306 result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
307 if (result != 0) {
308 WARN("fip_file_open: failed to seek\n");
309 result = -ENOENT;
310 goto fip_file_open_close;
311 }
312
313 found_file = 0;
314 do {
315 result = io_read(backend_handle,
316 (uintptr_t)&current_file.entry,
317 sizeof(current_file.entry),
318 &bytes_read);
319 if (result == 0) {
320 if (compare_uuids(&current_file.entry.uuid,
321 &uuid_spec->uuid) == 0) {
322 found_file = 1;
323 break;
324 }
325 } else {
326 WARN("Failed to read FIP (%i)\n", result);
327 goto fip_file_open_close;
328 }
329 } while (compare_uuids(&current_file.entry.uuid, &uuid_null) != 0);
330
331 if (found_file == 1) {
332 /* All fine. Update entity info with file state and return. Set
333 * the file position to 0. The 'current_file.entry' holds the
334 * base and size of the file.
335 */
336 current_file.file_pos = 0;
337 entity->info = (uintptr_t)&current_file;
338 } else {
339 /* Did not find the file in the FIP. */
340 current_file.entry.offset_address = 0;
341 result = -ENOENT;
342 }
343
344 fip_file_open_close:
345 io_close(backend_handle);
346
347 fip_file_open_exit:
348 return result;
349 }
350
351
352 /* Return the size of a file in package */
353 static int fip_file_len(io_entity_t *entity, size_t *length)
354 {
355 assert(entity != NULL);
356 assert(length != NULL);
357
358 *length = ((file_state_t *)entity->info)->entry.size;
359
360 return 0;
361 }
362
363
364 /* Read data from a file in package */
365 static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
366 size_t *length_read)
367 {
368 int result;
369 file_state_t *fp;
370 size_t file_offset;
371 size_t bytes_read;
372 uintptr_t backend_handle;
373
374 assert(entity != NULL);
375 assert(length_read != NULL);
376 assert(entity->info != (uintptr_t)NULL);
377
378 /* Open the backend, attempt to access the blob image */
379 result = io_open(backend_dev_handle, backend_image_spec,
380 &backend_handle);
381 if (result != 0) {
382 WARN("Failed to open FIP (%i)\n", result);
383 result = -ENOENT;
384 goto fip_file_read_exit;
385 }
386
387 fp = (file_state_t *)entity->info;
388
389 /* Seek to the position in the FIP where the payload lives */
390 file_offset = fp->entry.offset_address + fp->file_pos;
391 result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
392 if (result != 0) {
393 WARN("fip_file_read: failed to seek\n");
394 result = -ENOENT;
395 goto fip_file_read_close;
396 }
397
398 result = io_read(backend_handle, buffer, length, &bytes_read);
399 if (result != 0) {
400 /* We cannot read our data. Fail. */
401 WARN("Failed to read payload (%i)\n", result);
402 result = -ENOENT;
403 goto fip_file_read_close;
404 } else {
405 /* Set caller length and new file position. */
406 *length_read = bytes_read;
407 fp->file_pos += bytes_read;
408 }
409
410 /* Close the backend. */
411 fip_file_read_close:
412 io_close(backend_handle);
413
414 fip_file_read_exit:
415 return result;
416 }
417
418
419 /* Close a file in package */
420 static int fip_file_close(io_entity_t *entity)
421 {
422 /* Clear our current file pointer.
423 * If we had malloc() we would free() here.
424 */
425 if (current_file.entry.offset_address != 0) {
426 zeromem(&current_file, sizeof(current_file));
427 }
428
429 /* Clear the Entity info. */
430 entity->info = 0;
431
432 return 0;
433 }
434
435 /* Exported functions */
436
437 /* Register the Firmware Image Package driver with the IO abstraction */
438 int register_io_dev_fip(const io_dev_connector_t **dev_con)
439 {
440 int result;
441 assert(dev_con != NULL);
442
443 /*
444 * Since dev_info isn't really used in io_register_device, always
445 * use the same device info at here instead.
446 */
447 result = io_register_device(&dev_info_pool[0]);
448 if (result == 0)
449 *dev_con = &fip_dev_connector;
450
451 return result;
452 }