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)¤t_file.entry, 317 sizeof(current_file.entry), 318 &bytes_read); 319 if (result == 0) { 320 if (compare_uuids(¤t_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(¤t_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)¤t_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(¤t_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 } 453