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)¤t_file.entry, 221 sizeof(current_file.entry), 222 &bytes_read); 223 if (result == 0) { 224 if (compare_uuids(¤t_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(¤t_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)¤t_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(¤t_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