blob: a23940d81f9e700cfb7567af02bdcff1d0c9b36c [file] [log] [blame]
Harry Liebel561cd332014-02-14 14:42:48 +00001/*
Antonio Nino Diaz5f73afb2018-02-14 11:41:26 +00002 * Copyright (c) 2014-2018, 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 unsigned int file_pos;
Dan Handleye2712bc2014-04-10 15:37:22 +010032 fip_toc_entry_t entry;
33} file_state_t;
Harry Liebel561cd332014-02-14 14:42:48 +000034
Harry Liebel561cd332014-02-14 14:42:48 +000035static const uuid_t uuid_null = {0};
Dan Handleye2712bc2014-04-10 15:37:22 +010036static file_state_t current_file = {0};
Dan Handleya4cb68e2014-04-23 13:47:06 +010037static uintptr_t backend_dev_handle;
38static uintptr_t backend_image_spec;
Harry Liebel561cd332014-02-14 14:42:48 +000039
40
41/* Firmware Image Package driver functions */
Dan Handleya4cb68e2014-04-23 13:47:06 +010042static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
43static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +010044 io_entity_t *entity);
45static int fip_file_len(io_entity_t *entity, size_t *length);
Dan Handleya4cb68e2014-04-23 13:47:06 +010046static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
Harry Liebel561cd332014-02-14 14:42:48 +000047 size_t *length_read);
Dan Handleye2712bc2014-04-10 15:37:22 +010048static int fip_file_close(io_entity_t *entity);
Dan Handleya4cb68e2014-04-23 13:47:06 +010049static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
Dan Handleye2712bc2014-04-10 15:37:22 +010050static int fip_dev_close(io_dev_info_t *dev_info);
Harry Liebel561cd332014-02-14 14:42:48 +000051
Harry Liebel561cd332014-02-14 14:42:48 +000052
53/* Return 0 for equal uuids. */
54static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
55{
56 return memcmp(uuid1, uuid2, sizeof(uuid_t));
57}
58
59
60/* TODO: We could check version numbers or do a package checksum? */
Dan Handleye2712bc2014-04-10 15:37:22 +010061static inline int is_valid_header(fip_toc_header_t *header)
Harry Liebel561cd332014-02-14 14:42:48 +000062{
63 if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
64 return 1;
65 } else {
66 return 0;
67 }
68}
69
70
Harry Liebel561cd332014-02-14 14:42:48 +000071/* Identify the device type as a virtual driver */
Dan Handleye2712bc2014-04-10 15:37:22 +010072io_type_t device_type_fip(void)
Harry Liebel561cd332014-02-14 14:42:48 +000073{
74 return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
75}
76
77
Dan Handleya4cb68e2014-04-23 13:47:06 +010078static const io_dev_connector_t fip_dev_connector = {
Harry Liebel561cd332014-02-14 14:42:48 +000079 .dev_open = fip_dev_open
80};
81
82
Dan Handleya4cb68e2014-04-23 13:47:06 +010083static const io_dev_funcs_t fip_dev_funcs = {
Harry Liebel561cd332014-02-14 14:42:48 +000084 .type = device_type_fip,
85 .open = fip_file_open,
86 .seek = NULL,
87 .size = fip_file_len,
88 .read = fip_file_read,
89 .write = NULL,
90 .close = fip_file_close,
91 .dev_init = fip_dev_init,
92 .dev_close = fip_dev_close,
93};
94
95
Dan Handleya4cb68e2014-04-23 13:47:06 +010096/* No state associated with this device so structure can be const */
97static const io_dev_info_t fip_dev_info = {
Harry Liebel561cd332014-02-14 14:42:48 +000098 .funcs = &fip_dev_funcs,
99 .info = (uintptr_t)NULL
100};
101
102
103/* Open a connection to the FIP device */
Soren Brinkmann46dd1702016-01-14 10:11:05 -0800104static int fip_dev_open(const uintptr_t dev_spec __unused,
Dan Handleye2712bc2014-04-10 15:37:22 +0100105 io_dev_info_t **dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +0000106{
107 assert(dev_info != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100108 *dev_info = (io_dev_info_t *)&fip_dev_info; /* cast away const */
Harry Liebel561cd332014-02-14 14:42:48 +0000109
Juan Castillo6e762062015-11-02 10:47:01 +0000110 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000111}
112
113
114/* Do some basic package checks. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100115static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
Harry Liebel561cd332014-02-14 14:42:48 +0000116{
Juan Castillo6e762062015-11-02 10:47:01 +0000117 int result;
Juan Castillo3a66aca2015-04-13 17:36:19 +0100118 unsigned int image_id = (unsigned int)init_params;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100119 uintptr_t backend_handle;
Dan Handleye2712bc2014-04-10 15:37:22 +0100120 fip_toc_header_t header;
Harry Liebel561cd332014-02-14 14:42:48 +0000121 size_t bytes_read;
122
123 /* Obtain a reference to the image by querying the platform layer */
Juan Castillo3a66aca2015-04-13 17:36:19 +0100124 result = plat_get_image_source(image_id, &backend_dev_handle,
Harry Liebel561cd332014-02-14 14:42:48 +0000125 &backend_image_spec);
Juan Castillo6e762062015-11-02 10:47:01 +0000126 if (result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100127 WARN("Failed to obtain reference to image id=%u (%i)\n",
128 image_id, result);
Juan Castillo6e762062015-11-02 10:47:01 +0000129 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000130 goto fip_dev_init_exit;
131 }
132
133 /* Attempt to access the FIP image */
134 result = io_open(backend_dev_handle, backend_image_spec,
135 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000136 if (result != 0) {
Juan Castillo3a66aca2015-04-13 17:36:19 +0100137 WARN("Failed to access image id=%u (%i)\n", image_id, result);
Juan Castillo6e762062015-11-02 10:47:01 +0000138 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000139 goto fip_dev_init_exit;
140 }
141
Dan Handleya4cb68e2014-04-23 13:47:06 +0100142 result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
143 &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000144 if (result == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000145 if (!is_valid_header(&header)) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000146 WARN("Firmware Image Package header check failed.\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000147 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000148 } else {
Dan Handley91b624e2014-07-29 17:14:00 +0100149 VERBOSE("FIP header looks OK.\n");
Harry Liebel561cd332014-02-14 14:42:48 +0000150 }
151 }
152
153 io_close(backend_handle);
154
155 fip_dev_init_exit:
156 return result;
157}
158
159/* Close a connection to the FIP device */
Dan Handleye2712bc2014-04-10 15:37:22 +0100160static int fip_dev_close(io_dev_info_t *dev_info)
Harry Liebel561cd332014-02-14 14:42:48 +0000161{
162 /* TODO: Consider tracking open files and cleaning them up here */
163
164 /* Clear the backend. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100165 backend_dev_handle = (uintptr_t)NULL;
166 backend_image_spec = (uintptr_t)NULL;
Harry Liebel561cd332014-02-14 14:42:48 +0000167
Juan Castillo6e762062015-11-02 10:47:01 +0000168 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000169}
170
171
172/* Open a file for access from package. */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100173static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
Dan Handleye2712bc2014-04-10 15:37:22 +0100174 io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000175{
Juan Castillo6e762062015-11-02 10:47:01 +0000176 int result;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100177 uintptr_t backend_handle;
Juan Castillo3a66aca2015-04-13 17:36:19 +0100178 const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
Harry Liebel561cd332014-02-14 14:42:48 +0000179 size_t bytes_read;
180 int found_file = 0;
181
Juan Castillo3a66aca2015-04-13 17:36:19 +0100182 assert(uuid_spec != NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000183 assert(entity != NULL);
184
185 /* Can only have one file open at a time for the moment. We need to
186 * track state like file cursor position. We know the header lives at
187 * offset zero, so this entry should never be zero for an active file.
188 * When the system supports dynamic memory allocation we can allow more
189 * than one open file at a time if needed.
190 */
191 if (current_file.entry.offset_address != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000192 WARN("fip_file_open : Only one open file at a time.\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000193 return -ENOMEM;
Harry Liebel561cd332014-02-14 14:42:48 +0000194 }
195
196 /* Attempt to access the FIP image */
197 result = io_open(backend_dev_handle, backend_image_spec,
198 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000199 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000200 WARN("Failed to open Firmware Image Package (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000201 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000202 goto fip_file_open_exit;
203 }
204
205 /* Seek past the FIP header into the Table of Contents */
Dan Handleye2712bc2014-04-10 15:37:22 +0100206 result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
Juan Castillo6e762062015-11-02 10:47:01 +0000207 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000208 WARN("fip_file_open: failed to seek\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000209 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000210 goto fip_file_open_close;
211 }
212
Harry Liebel561cd332014-02-14 14:42:48 +0000213 found_file = 0;
214 do {
Dan Handleya4cb68e2014-04-23 13:47:06 +0100215 result = io_read(backend_handle,
216 (uintptr_t)&current_file.entry,
Harry Liebel561cd332014-02-14 14:42:48 +0000217 sizeof(current_file.entry),
218 &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000219 if (result == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000220 if (compare_uuids(&current_file.entry.uuid,
Juan Castillo3a66aca2015-04-13 17:36:19 +0100221 &uuid_spec->uuid) == 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000222 found_file = 1;
223 break;
224 }
225 } else {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000226 WARN("Failed to read FIP (%i)\n", result);
Harry Liebel561cd332014-02-14 14:42:48 +0000227 goto fip_file_open_close;
228 }
229 } while (compare_uuids(&current_file.entry.uuid, &uuid_null) != 0);
230
231 if (found_file == 1) {
232 /* All fine. Update entity info with file state and return. Set
233 * the file position to 0. The 'current_file.entry' holds the
234 * base and size of the file.
235 */
236 current_file.file_pos = 0;
237 entity->info = (uintptr_t)&current_file;
238 } else {
239 /* Did not find the file in the FIP. */
Jeenu Viswambharandd3dc322014-02-20 11:51:00 +0000240 current_file.entry.offset_address = 0;
Juan Castillo6e762062015-11-02 10:47:01 +0000241 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000242 }
243
244 fip_file_open_close:
245 io_close(backend_handle);
246
247 fip_file_open_exit:
248 return result;
249}
250
251
252/* Return the size of a file in package */
Dan Handleye2712bc2014-04-10 15:37:22 +0100253static int fip_file_len(io_entity_t *entity, size_t *length)
Harry Liebel561cd332014-02-14 14:42:48 +0000254{
255 assert(entity != NULL);
256 assert(length != NULL);
257
Dan Handleye2712bc2014-04-10 15:37:22 +0100258 *length = ((file_state_t *)entity->info)->entry.size;
Harry Liebel561cd332014-02-14 14:42:48 +0000259
Juan Castillo6e762062015-11-02 10:47:01 +0000260 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000261}
262
263
264/* Read data from a file in package */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100265static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
Harry Liebel561cd332014-02-14 14:42:48 +0000266 size_t *length_read)
267{
Juan Castillo6e762062015-11-02 10:47:01 +0000268 int result;
Dan Handleye2712bc2014-04-10 15:37:22 +0100269 file_state_t *fp;
Harry Liebel561cd332014-02-14 14:42:48 +0000270 size_t file_offset;
271 size_t bytes_read;
Dan Handleya4cb68e2014-04-23 13:47:06 +0100272 uintptr_t backend_handle;
Harry Liebel561cd332014-02-14 14:42:48 +0000273
274 assert(entity != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100275 assert(buffer != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000276 assert(length_read != NULL);
Dan Handleya4cb68e2014-04-23 13:47:06 +0100277 assert(entity->info != (uintptr_t)NULL);
Harry Liebel561cd332014-02-14 14:42:48 +0000278
279 /* Open the backend, attempt to access the blob image */
280 result = io_open(backend_dev_handle, backend_image_spec,
281 &backend_handle);
Juan Castillo6e762062015-11-02 10:47:01 +0000282 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000283 WARN("Failed to open FIP (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000284 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000285 goto fip_file_read_exit;
286 }
287
Dan Handleye2712bc2014-04-10 15:37:22 +0100288 fp = (file_state_t *)entity->info;
Harry Liebel561cd332014-02-14 14:42:48 +0000289
290 /* Seek to the position in the FIP where the payload lives */
291 file_offset = fp->entry.offset_address + fp->file_pos;
292 result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
Juan Castillo6e762062015-11-02 10:47:01 +0000293 if (result != 0) {
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000294 WARN("fip_file_read: failed to seek\n");
Juan Castillo6e762062015-11-02 10:47:01 +0000295 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000296 goto fip_file_read_close;
297 }
298
299 result = io_read(backend_handle, buffer, length, &bytes_read);
Juan Castillo6e762062015-11-02 10:47:01 +0000300 if (result != 0) {
Harry Liebel561cd332014-02-14 14:42:48 +0000301 /* We cannot read our data. Fail. */
Jeenu Viswambharan08c28d52014-02-20 12:03:31 +0000302 WARN("Failed to read payload (%i)\n", result);
Juan Castillo6e762062015-11-02 10:47:01 +0000303 result = -ENOENT;
Harry Liebel561cd332014-02-14 14:42:48 +0000304 goto fip_file_read_close;
305 } else {
306 /* Set caller length and new file position. */
307 *length_read = bytes_read;
308 fp->file_pos += bytes_read;
309 }
310
311/* Close the backend. */
312 fip_file_read_close:
313 io_close(backend_handle);
314
315 fip_file_read_exit:
316 return result;
317}
318
319
320/* Close a file in package */
Dan Handleye2712bc2014-04-10 15:37:22 +0100321static int fip_file_close(io_entity_t *entity)
Harry Liebel561cd332014-02-14 14:42:48 +0000322{
323 /* Clear our current file pointer.
324 * If we had malloc() we would free() here.
325 */
326 if (current_file.entry.offset_address != 0) {
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000327 zeromem(&current_file, sizeof(current_file));
Harry Liebel561cd332014-02-14 14:42:48 +0000328 }
329
330 /* Clear the Entity info. */
331 entity->info = 0;
332
Juan Castillo6e762062015-11-02 10:47:01 +0000333 return 0;
Harry Liebel561cd332014-02-14 14:42:48 +0000334}
335
336/* Exported functions */
337
338/* Register the Firmware Image Package driver with the IO abstraction */
Dan Handleya4cb68e2014-04-23 13:47:06 +0100339int register_io_dev_fip(const io_dev_connector_t **dev_con)
Harry Liebel561cd332014-02-14 14:42:48 +0000340{
Juan Castillo6e762062015-11-02 10:47:01 +0000341 int result;
Harry Liebel561cd332014-02-14 14:42:48 +0000342 assert(dev_con != NULL);
343
344 result = io_register_device(&fip_dev_info);
Juan Castillo6e762062015-11-02 10:47:01 +0000345 if (result == 0)
Harry Liebel561cd332014-02-14 14:42:48 +0000346 *dev_con = &fip_dev_connector;
347
348 return result;
349}