Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (c) 2014-2017, 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 /* 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 
     30 typedef struct {
     31 	/* 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;
     36 	fip_toc_entry_t entry;
     37 } file_state_t;
     38 
     39 static const uuid_t uuid_null = {0};
     40 static file_state_t current_file = {0};
     41 static uintptr_t backend_dev_handle;
     42 static uintptr_t backend_image_spec;
     43 
     44 
     45 /* Firmware Image Package driver functions */
     46 static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
     47 static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
     48 			  io_entity_t *entity);
     49 static int fip_file_len(io_entity_t *entity, size_t *length);
     50 static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
     51 			  size_t *length_read);
     52 static int fip_file_close(io_entity_t *entity);
     53 static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
     54 static int fip_dev_close(io_dev_info_t *dev_info);
     55 
     56 
     57 /* Return 0 for equal uuids. */
     58 static 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? */
     65 static inline int is_valid_header(fip_toc_header_t *header)
     66 {
     67 	if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
     68 		return 1;
     69 	} else {
     70 		return 0;
     71 	}
     72 }
     73 
     74 
     75 /* Identify the device type as a virtual driver */
     76 io_type_t device_type_fip(void)
     77 {
     78 	return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
     79 }
     80 
     81 
     82 static const io_dev_connector_t fip_dev_connector = {
     83 	.dev_open = fip_dev_open
     84 };
     85 
     86 
     87 static const io_dev_funcs_t fip_dev_funcs = {
     88 	.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 
    100 /* No state associated with this device so structure can be const */
    101 static const io_dev_info_t fip_dev_info = {
    102 	.funcs = &fip_dev_funcs,
    103 	.info = (uintptr_t)NULL
    104 };
    105 
    106 
    107 /* Open a connection to the FIP device */
    108 static int fip_dev_open(const uintptr_t dev_spec __unused,
    109 			 io_dev_info_t **dev_info)
    110 {
    111 	assert(dev_info != NULL);
    112 	*dev_info = (io_dev_info_t *)&fip_dev_info; /* cast away const */
    113 
    114 	return 0;
    115 }
    116 
    117 
    118 /* Do some basic package checks. */
    119 static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
    120 {
    121 	int result;
    122 	unsigned int image_id = (unsigned int)init_params;
    123 	uintptr_t backend_handle;
    124 	fip_toc_header_t header;
    125 	size_t bytes_read;
    126 
    127 	/* Obtain a reference to the image by querying the platform layer */
    128 	result = plat_get_image_source(image_id, &backend_dev_handle,
    129 				       &backend_image_spec);
    130 	if (result != 0) {
    131 		WARN("Failed to obtain reference to image id=%u (%i)\n",
    132 			image_id, result);
    133 		result = -ENOENT;
    134 		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);
    140 	if (result != 0) {
    141 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
    142 		result = -ENOENT;
    143 		goto fip_dev_init_exit;
    144 	}
    145 
    146 	result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
    147 			&bytes_read);
    148 	if (result == 0) {
    149 		if (!is_valid_header(&header)) {
    150 			WARN("Firmware Image Package header check failed.\n");
    151 			result = -ENOENT;
    152 		} else {
    153 			VERBOSE("FIP header looks OK.\n");
    154 		}
    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 */
    164 static int fip_dev_close(io_dev_info_t *dev_info)
    165 {
    166 	/* TODO: Consider tracking open files and cleaning them up here */
    167 
    168 	/* Clear the backend. */
    169 	backend_dev_handle = (uintptr_t)NULL;
    170 	backend_image_spec = (uintptr_t)NULL;
    171 
    172 	return 0;
    173 }
    174 
    175 
    176 /* Open a file for access from package. */
    177 static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
    178 			 io_entity_t *entity)
    179 {
    180 	int result;
    181 	uintptr_t backend_handle;
    182 	const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
    183 	size_t bytes_read;
    184 	int found_file = 0;
    185 
    186 	assert(uuid_spec != NULL);
    187 	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) {
    196 		WARN("fip_file_open : Only one open file at a time.\n");
    197 		return -ENOMEM;
    198 	}
    199 
    200 	/* Attempt to access the FIP image */
    201 	result = io_open(backend_dev_handle, backend_image_spec,
    202 			 &backend_handle);
    203 	if (result != 0) {
    204 		WARN("Failed to open Firmware Image Package (%i)\n", result);
    205 		result = -ENOENT;
    206 		goto fip_file_open_exit;
    207 	}
    208 
    209 	/* Seek past the FIP header into the Table of Contents */
    210 	result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
    211 	if (result != 0) {
    212 		WARN("fip_file_open: failed to seek\n");
    213 		result = -ENOENT;
    214 		goto fip_file_open_close;
    215 	}
    216 
    217 	found_file = 0;
    218 	do {
    219 		result = io_read(backend_handle,
    220 				 (uintptr_t)&current_file.entry,
    221 				 sizeof(current_file.entry),
    222 				 &bytes_read);
    223 		if (result == 0) {
    224 			if (compare_uuids(&current_file.entry.uuid,
    225 					  &uuid_spec->uuid) == 0) {
    226 				found_file = 1;
    227 				break;
    228 			}
    229 		} else {
    230 			WARN("Failed to read FIP (%i)\n", result);
    231 			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. */
    244 		current_file.entry.offset_address = 0;
    245 		result = -ENOENT;
    246 	}
    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 */
    257 static int fip_file_len(io_entity_t *entity, size_t *length)
    258 {
    259 	assert(entity != NULL);
    260 	assert(length != NULL);
    261 
    262 	*length =  ((file_state_t *)entity->info)->entry.size;
    263 
    264 	return 0;
    265 }
    266 
    267 
    268 /* Read data from a file in package */
    269 static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
    270 			  size_t *length_read)
    271 {
    272 	int result;
    273 	file_state_t *fp;
    274 	size_t file_offset;
    275 	size_t bytes_read;
    276 	uintptr_t backend_handle;
    277 
    278 	assert(entity != NULL);
    279 	assert(buffer != (uintptr_t)NULL);
    280 	assert(length_read != NULL);
    281 	assert(entity->info != (uintptr_t)NULL);
    282 
    283 	/* Open the backend, attempt to access the blob image */
    284 	result = io_open(backend_dev_handle, backend_image_spec,
    285 			 &backend_handle);
    286 	if (result != 0) {
    287 		WARN("Failed to open FIP (%i)\n", result);
    288 		result = -ENOENT;
    289 		goto fip_file_read_exit;
    290 	}
    291 
    292 	fp = (file_state_t *)entity->info;
    293 
    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);
    297 	if (result != 0) {
    298 		WARN("fip_file_read: failed to seek\n");
    299 		result = -ENOENT;
    300 		goto fip_file_read_close;
    301 	}
    302 
    303 	result = io_read(backend_handle, buffer, length, &bytes_read);
    304 	if (result != 0) {
    305 		/* We cannot read our data. Fail. */
    306 		WARN("Failed to read payload (%i)\n", result);
    307 		result = -ENOENT;
    308 		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 */
    325 static int fip_file_close(io_entity_t *entity)
    326 {
    327 	/* Clear our current file pointer.
    328 	 * If we had malloc() we would free() here.
    329 	 */
    330 	if (current_file.entry.offset_address != 0) {
    331 		zeromem(&current_file, sizeof(current_file));
    332 	}
    333 
    334 	/* Clear the Entity info. */
    335 	entity->info = 0;
    336 
    337 	return 0;
    338 }
    339 
    340 /* Exported functions */
    341 
    342 /* Register the Firmware Image Package driver with the IO abstraction */
    343 int register_io_dev_fip(const io_dev_connector_t **dev_con)
    344 {
    345 	int result;
    346 	assert(dev_con != NULL);
    347 
    348 	result = io_register_device(&fip_dev_info);
    349 	if (result == 0)
    350 		*dev_con = &fip_dev_connector;
    351 
    352 	return result;
    353 }
    354