blob: abb351180a214e61240aed0f793961af6a935fd9 [file] [log] [blame]
Harry Liebel561cd332014-02-14 14:42:48 +00001/*
Douglas Raillarda8954fc2017-01-26 15:54:44 +00002 * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
Harry Liebel561cd332014-02-14 14:42:48 +00003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Harry Liebel561cd332014-02-14 14:42:48 +00005 */
6
Harry Liebel561cd332014-02-14 14:42:48 +00007#include <assert.h>
Dan Handleyed6ff952014-05-14 17:44:19 +01008#include <bl_common.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +01009#include <debug.h>
10#include <errno.h>
Dan Handley714a0d22014-04-09 13:13:04 +010011#include <firmware_image_package.h>
Dan Handley714a0d22014-04-09 13:13:04 +010012#include <io_driver.h>
13#include <io_fip.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010014#include <io_storage.h>
15#include <platform.h>
Dan Handleyed6ff952014-05-14 17:44:19 +010016#include <platform_def.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010017#include <stdint.h>
18#include <string.h>
Douglas Raillarda8954fc2017-01-26 15:54:44 +000019#include <utils.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010020#include <uuid.h>
Harry Liebel561cd332014-02-14 14:42:48 +000021
22/* Useful for printing UUIDs when debugging.*/
23#define PRINT_UUID2(x) \
24 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", \
25 x.time_low, x.time_mid, x.time_hi_and_version, \
26 x.clock_seq_hi_and_reserved, x.clock_seq_low, \
27 x.node[0], x.node[1], x.node[2], x.node[3], \
28 x.node[4], x.node[5]
29
30typedef struct {
Harry Liebel561cd332014-02-14 14:42:48 +000031 /* Put file_pos above the struct to allow {0} on static init.
32 * It is a workaround for a known bug in GCC
33 * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
34 */
35 unsigned int file_pos;
Dan Handleye2712bc2014-04-10 15:37:22 +010036 fip_toc_entry_t entry;
37} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000038
Harry Liebel561cd332014-02-14 14:42:48 +000039static const uuid_t uuid_null = {0};
Dan Handleye2712bc2014-04-10 15:37:22 +010040static file_state_t current_file = {0};
Dan Handleya4cb68e2014-04-23 13:47:06 +010041static uintptr_t backend_dev_handle;
42static uintptr_t backend_image_spec;
Harry Liebel561cd332014-02-14 14:42:48 +000043
44
45/* Firmware Image Package driver functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010046static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
47static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010048 io_entity_t *entity);
49static int fip_file_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010050static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
Harry Liebel561cd332014-02-14 14:42:48 +000051 size_t *length_read);
Dan Handleye2712bc2014-04-10 15:37:22 +010052static int fip_file_close(io_entity_t *entity);
Dan Handleya4cb68e2014-04-23 13:47:06 +010053static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
Dan Handleye2712bc2014-04-10 15:37:22 +010054static int fip_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000055
Harry Liebel561cd332014-02-14 14:42:48 +000056
57/* Return 0 for equal uuids. */
58static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
59{
60 return memcmp(uuid1, uuid2, sizeof(uuid_t));
61}
62
63
64/* TODO: We could check version numbers or do a package checksum? */
Dan Handleye2712bc2014-04-10 15:37:22 +010065static inline int is_valid_header(fip_toc_header_t *header)
Harry Liebel561cd332014-02-14 14:42:48 +000066{
67 if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
68 return 1;
69 } else {
70 return 0;
71 }
72}
73
74
Harry Liebel561cd332014-02-14 14:42:48 +000075/* Identify the device type as a virtual driver */
Dan Handleye2712bc2014-04-10 15:37:22 +010076io_type_t device_type_fip(void)
Harry Liebel561cd332014-02-14 14:42:48 +000077{
78 return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
79}
80
81
Dan Handleya4cb68e2014-04-23 13:47:06 +010082static const io_dev_connector_t fip_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000083 .dev_open = fip_dev_open
84};
85
86
Dan Handleya4cb68e2014-04-23 13:47:06 +010087static const io_dev_funcs_t fip_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000088 .type = device_type_fip,
89 .open = fip_file_open,
90 .seek = NULL,
91 .size = fip_file_len,
92 .read = fip_file_read,
93 .write = NULL,
94 .close = fip_file_close,
95 .dev_init = fip_dev_init,
96 .dev_close = fip_dev_close,
97};
98
99
Dan Handleya4cb68e2014-04-23 13:47:06 +0100100/* No state associated with this device so structure can be const */
101static const io_dev_info_t fip_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +0000102 .funcs = &fip_dev_funcs,
103 .info = (uintptr_t)NULL
104};
105
106
107/* Open a connection to the FIP device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -0800108static int fip_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +0100109 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +0000110{
111 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100112 *dev_info = (io_dev_info_t *)&fip_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +0000113
Juan Castillo6e762062015-11-02 10:47:01 +0000114 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000115}
116
117
118/* Do some basic package checks. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100119static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
Harry Liebel561cd332014-02-14 14:42:48 +0000120{
Juan Castillo6e762062015-11-02 10:47:01 +0000121 int result;
Juan Castillo3a66aca2015-04-13 17:36:19 +0100122 unsigned int image_id = (unsigned int)init_params;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100123 uintptr_t backend_handle;
Dan Handleye2712bc2014-04-10 15:37:22 +0100124 fip_toc_header_t header;
Harry Liebel561cd332014-02-14 14:42:48 +0000125 size_t bytes_read;
126
127 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100128 result = plat_get_image_source(image_id, &backend_dev_handle,
Harry Liebel561cd332014-02-14 14:42:48 +0000129 &backend_image_spec);
Juan Castillo6e762062015-11-02 10:47:01 +0000130 if (result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100131 WARN("Failed to obtain reference to image id=%u (%i)\n",
132 image_id, result);
Juan Castillo6e762062015-11-02 10:47:01 +0000133 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000134 goto fip_dev_init_exit;
135 }
136
137 /* Attempt to access the FIP image */
138 result = io_open(backend_dev_handle, backend_image_spec,
139 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000140 if (result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100141 WARN("Failed to access image id=%u (%i)\n", image_id, result);
Juan Castillo6e762062015-11-02 10:47:01 +0000142 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000143 goto fip_dev_init_exit;
144 }
145
Dan Handleya4cb68e2014-04-23 13:47:06 +0100146 result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
147 &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000148 if (result == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000149 if (!is_valid_header(&header)) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000150 WARN("Firmware Image Package header check failed.\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000151 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000152 } else {
Dan Handley91b624e2014-07-29 17:14:00 +0100153 VERBOSE("FIP header looks OK.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000154 }
155 }
156
157 io_close(backend_handle);
158
159 fip_dev_init_exit:
160 return result;
161}
162
163/* Close a connection to the FIP device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100164static int fip_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +0000165{
166 /* TODO: Consider tracking open files and cleaning them up here */
167
168 /* Clear the backend. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100169 backend_dev_handle = (uintptr_t)NULL;
170 backend_image_spec = (uintptr_t)NULL;
Harry Liebel561cd332014-02-14 14:42:48 +0000171
Juan Castillo6e762062015-11-02 10:47:01 +0000172 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000173}
174
175
176/* Open a file for access from package. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100177static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100178 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000179{
Juan Castillo6e762062015-11-02 10:47:01 +0000180 int result;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100181 uintptr_t backend_handle;
Juan Castillo3a66aca2015-04-13 17:36:19 +0100182 const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000183 size_t bytes_read;
184 int found_file = 0;
185
Juan Castillo3a66aca2015-04-13 17:36:19 +0100186 assert(uuid_spec != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000187 assert(entity != NULL);
188
189 /* Can only have one file open at a time for the moment. We need to
190 * track state like file cursor position. We know the header lives at
191 * offset zero, so this entry should never be zero for an active file.
192 * When the system supports dynamic memory allocation we can allow more
193 * than one open file at a time if needed.
194 */
195 if (current_file.entry.offset_address != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000196 WARN("fip_file_open : Only one open file at a time.\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000197 return -ENOMEM;
Harry Liebel561cd332014-02-14 14:42:48 +0000198 }
199
200 /* Attempt to access the FIP image */
201 result = io_open(backend_dev_handle, backend_image_spec,
202 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000203 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000204 WARN("Failed to open Firmware Image Package (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000205 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000206 goto fip_file_open_exit;
207 }
208
209 /* Seek past the FIP header into the Table of Contents */
Dan Handleye2712bc2014-04-10 15:37:22 +0100210 result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
Juan Castillo6e762062015-11-02 10:47:01 +0000211 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000212 WARN("fip_file_open: failed to seek\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000213 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000214 goto fip_file_open_close;
215 }
216
Harry Liebel561cd332014-02-14 14:42:48 +0000217 found_file = 0;
218 do {
Dan Handleya4cb68e2014-04-23 13:47:06 +0100219 result = io_read(backend_handle,
220 (uintptr_t)&current_file.entry,
Harry Liebel561cd332014-02-14 14:42:48 +0000221 sizeof(current_file.entry),
222 &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000223 if (result == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000224 if (compare_uuids(&current_file.entry.uuid,
Juan Castillo3a66aca2015-04-13 17:36:19 +0100225 &uuid_spec->uuid) == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000226 found_file = 1;
227 break;
228 }
229 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000230 WARN("Failed to read FIP (%i)\n", result);
Harry Liebel561cd332014-02-14 14:42:48 +0000231 goto fip_file_open_close;
232 }
233 } while (compare_uuids(&current_file.entry.uuid, &uuid_null) != 0);
234
235 if (found_file == 1) {
236 /* All fine. Update entity info with file state and return. Set
237 * the file position to 0. The 'current_file.entry' holds the
238 * base and size of the file.
239 */
240 current_file.file_pos = 0;
241 entity->info = (uintptr_t)&current_file;
242 } else {
243 /* Did not find the file in the FIP. */
Jeenu Viswambharandd3dc322014-02-20 11:51:00 +0000244 current_file.entry.offset_address = 0;
Juan Castillo6e762062015-11-02 10:47:01 +0000245 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000246 }
247
248 fip_file_open_close:
249 io_close(backend_handle);
250
251 fip_file_open_exit:
252 return result;
253}
254
255
256/* Return the size of a file in package */
Dan Handleye2712bc2014-04-10 15:37:22 +0100257static int fip_file_len(io_entity_t *entity, size_t *length)
Harry Liebel561cd332014-02-14 14:42:48 +0000258{
259 assert(entity != NULL);
260 assert(length != NULL);
261
Dan Handleye2712bc2014-04-10 15:37:22 +0100262 *length = ((file_state_t *)entity->info)->entry.size;
Harry Liebel561cd332014-02-14 14:42:48 +0000263
Juan Castillo6e762062015-11-02 10:47:01 +0000264 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000265}
266
267
268/* Read data from a file in package */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100269static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
Harry Liebel561cd332014-02-14 14:42:48 +0000270 size_t *length_read)
271{
Juan Castillo6e762062015-11-02 10:47:01 +0000272 int result;
Dan Handleye2712bc2014-04-10 15:37:22 +0100273 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000274 size_t file_offset;
275 size_t bytes_read;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100276 uintptr_t backend_handle;
Harry Liebel561cd332014-02-14 14:42:48 +0000277
278 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100279 assert(buffer != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000280 assert(length_read != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100281 assert(entity->info != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000282
283 /* Open the backend, attempt to access the blob image */
284 result = io_open(backend_dev_handle, backend_image_spec,
285 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000286 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000287 WARN("Failed to open FIP (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000288 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000289 goto fip_file_read_exit;
290 }
291
Dan Handleye2712bc2014-04-10 15:37:22 +0100292 fp = (file_state_t *)entity->info;
Harry Liebel561cd332014-02-14 14:42:48 +0000293
294 /* Seek to the position in the FIP where the payload lives */
295 file_offset = fp->entry.offset_address + fp->file_pos;
296 result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
Juan Castillo6e762062015-11-02 10:47:01 +0000297 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000298 WARN("fip_file_read: failed to seek\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000299 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000300 goto fip_file_read_close;
301 }
302
303 result = io_read(backend_handle, buffer, length, &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000304 if (result != 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000305 /* We cannot read our data. Fail. */
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000306 WARN("Failed to read payload (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000307 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000308 goto fip_file_read_close;
309 } else {
310 /* Set caller length and new file position. */
311 *length_read = bytes_read;
312 fp->file_pos += bytes_read;
313 }
314
315/* Close the backend. */
316 fip_file_read_close:
317 io_close(backend_handle);
318
319 fip_file_read_exit:
320 return result;
321}
322
323
324/* Close a file in package */
Dan Handleye2712bc2014-04-10 15:37:22 +0100325static int fip_file_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000326{
327 /* Clear our current file pointer.
328 * If we had malloc() we would free() here.
329 */
330 if (current_file.entry.offset_address != 0) {
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000331 zeromem(&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000332 }
333
334 /* Clear the Entity info. */
335 entity->info = 0;
336
Juan Castillo6e762062015-11-02 10:47:01 +0000337 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000338}
339
340/* Exported functions */
341
342/* Register the Firmware Image Package driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100343int register_io_dev_fip(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000344{
Juan Castillo6e762062015-11-02 10:47:01 +0000345 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000346 assert(dev_con != NULL);
347
348 result = io_register_device(&fip_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000349 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000350 *dev_con = &fip_dev_connector;
351
352 return result;
353}