diff options
Diffstat (limited to 'drivers/io')
-rw-r--r-- | drivers/io/io_encrypted.c | 244 | ||||
-rw-r--r-- | drivers/io/io_fip.c | 68 | ||||
-rw-r--r-- | drivers/io/io_memmap.c | 39 | ||||
-rw-r--r-- | drivers/io/io_semihosting.c | 7 | ||||
-rw-r--r-- | drivers/io/io_storage.c | 37 |
5 files changed, 329 insertions, 66 deletions
diff --git a/drivers/io/io_encrypted.c b/drivers/io/io_encrypted.c new file mode 100644 index 000000000..744ca8356 --- /dev/null +++ b/drivers/io/io_encrypted.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2020, Linaro Limited. All rights reserved. + * Author: Sumit Garg <sumit.garg@linaro.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> + +#include <platform_def.h> + +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/auth/crypto_mod.h> +#include <drivers/io/io_driver.h> +#include <drivers/io/io_encrypted.h> +#include <drivers/io/io_storage.h> +#include <lib/utils.h> +#include <plat/common/platform.h> +#include <tools_share/firmware_encrypted.h> +#include <tools_share/uuid.h> + +static uintptr_t backend_dev_handle; +static uintptr_t backend_dev_spec; +static uintptr_t backend_handle; +static uintptr_t backend_image_spec; + +static io_dev_info_t enc_dev_info; + +/* Encrypted firmware driver functions */ +static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); +static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); +static int enc_file_len(io_entity_t *entity, size_t *length); +static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, + size_t *length_read); +static int enc_file_close(io_entity_t *entity); +static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); +static int enc_dev_close(io_dev_info_t *dev_info); + +static inline int is_valid_header(struct fw_enc_hdr *header) +{ + if (header->magic == ENC_HEADER_MAGIC) + return 1; + else + return 0; +} + +static io_type_t device_type_enc(void) +{ + return IO_TYPE_ENCRYPTED; +} + +static const io_dev_connector_t enc_dev_connector = { + .dev_open = enc_dev_open +}; + +static const io_dev_funcs_t enc_dev_funcs = { + .type = device_type_enc, + .open = enc_file_open, + .seek = NULL, + .size = enc_file_len, + .read = enc_file_read, + .write = NULL, + .close = enc_file_close, + .dev_init = enc_dev_init, + .dev_close = enc_dev_close, +}; + +static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) +{ + assert(dev_info != NULL); + + enc_dev_info.funcs = &enc_dev_funcs; + *dev_info = &enc_dev_info; + + return 0; +} + +static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) +{ + int result; + unsigned int image_id = (unsigned int)init_params; + + /* Obtain a reference to the image by querying the platform layer */ + result = plat_get_image_source(image_id, &backend_dev_handle, + &backend_dev_spec); + if (result != 0) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, result); + return -ENOENT; + } + + return result; +} + +static int enc_dev_close(io_dev_info_t *dev_info) +{ + backend_dev_handle = (uintptr_t)NULL; + backend_dev_spec = (uintptr_t)NULL; + + return 0; +} + +static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity) +{ + int result; + + assert(spec != 0); + assert(entity != NULL); + + backend_image_spec = spec; + + result = io_open(backend_dev_handle, backend_image_spec, + &backend_handle); + if (result != 0) { + WARN("Failed to open backend device (%i)\n", result); + result = -ENOENT; + } + + return result; +} + +static int enc_file_len(io_entity_t *entity, size_t *length) +{ + int result; + + assert(entity != NULL); + assert(length != NULL); + + result = io_size(backend_handle, length); + if (result != 0) { + WARN("Failed to read blob length (%i)\n", result); + return -ENOENT; + } + + /* + * Encryption header is attached at the beginning of the encrypted file + * and is not considered a part of the payload. + */ + if (*length < sizeof(struct fw_enc_hdr)) + return -EIO; + + *length -= sizeof(struct fw_enc_hdr); + + return result; +} + +static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, + size_t *length_read) +{ + int result; + struct fw_enc_hdr header; + enum fw_enc_status_t fw_enc_status; + size_t bytes_read; + uint8_t key[ENC_MAX_KEY_SIZE]; + size_t key_len = sizeof(key); + unsigned int key_flags = 0; + const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)backend_image_spec; + + assert(entity != NULL); + assert(length_read != NULL); + + result = io_read(backend_handle, (uintptr_t)&header, sizeof(header), + &bytes_read); + if (result != 0) { + WARN("Failed to read encryption header (%i)\n", result); + return -ENOENT; + } + + if (!is_valid_header(&header)) { + WARN("Encryption header check failed.\n"); + return -ENOENT; + } + + VERBOSE("Encryption header looks OK.\n"); + fw_enc_status = header.flags & FW_ENC_STATUS_FLAG_MASK; + + if ((header.iv_len > ENC_MAX_IV_SIZE) || + (header.tag_len > ENC_MAX_TAG_SIZE)) { + WARN("Incorrect IV or tag length\n"); + return -ENOENT; + } + + result = io_read(backend_handle, buffer, length, &bytes_read); + if (result != 0) { + WARN("Failed to read encrypted payload (%i)\n", result); + return -ENOENT; + } + + *length_read = bytes_read; + + result = plat_get_enc_key_info(fw_enc_status, key, &key_len, &key_flags, + (uint8_t *)&uuid_spec->uuid, + sizeof(uuid_t)); + if (result != 0) { + WARN("Failed to obtain encryption key (%i)\n", result); + return -ENOENT; + } + + result = crypto_mod_auth_decrypt(header.dec_algo, + (void *)buffer, *length_read, key, + key_len, key_flags, header.iv, + header.iv_len, header.tag, + header.tag_len); + memset(key, 0, key_len); + + if (result != 0) { + ERROR("File decryption failed (%i)\n", result); + return -ENOENT; + } + + return result; +} + +static int enc_file_close(io_entity_t *entity) +{ + io_close(backend_handle); + + backend_image_spec = (uintptr_t)NULL; + entity->info = 0; + + return 0; +} + +/* Exported functions */ + +/* Register the Encrypted Firmware driver with the IO abstraction */ +int register_io_dev_enc(const io_dev_connector_t **dev_con) +{ + int result; + + assert(dev_con != NULL); + + result = io_register_device(&enc_dev_info); + if (result == 0) + *dev_con = &enc_dev_connector; + + return result; +} diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c index 5d49fffaa..6e152959f 100644 --- a/drivers/io/io_fip.c +++ b/drivers/io/io_fip.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -36,7 +36,7 @@ typedef struct { unsigned int file_pos; fip_toc_entry_t entry; -} file_state_t; +} fip_file_state_t; /* * Maintain dev_spec per FIP Device @@ -46,9 +46,9 @@ typedef struct { */ typedef struct { uintptr_t dev_spec; + uint16_t plat_toc_flag; } fip_dev_state_t; -static const uuid_t uuid_null; /* * Only one file can be open across all FIP device * as backends like io_memmap don't support @@ -56,7 +56,7 @@ static const uuid_t uuid_null; * backend handle should be maintained per FIP device * if the same support is available in the backend */ -static file_state_t current_file = {0}; +static fip_file_state_t current_fip_file = {0}; static uintptr_t backend_dev_handle; static uintptr_t backend_image_spec; @@ -220,6 +220,11 @@ static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) uintptr_t backend_handle; fip_toc_header_t header; size_t bytes_read; + fip_dev_state_t *state; + + assert(dev_info != NULL); + + state = (fip_dev_state_t *)dev_info->info; /* Obtain a reference to the image by querying the platform layer */ result = plat_get_image_source(image_id, &backend_dev_handle, @@ -248,6 +253,11 @@ static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) result = -ENOENT; } else { VERBOSE("FIP header looks OK.\n"); + /* + * Store 16-bit Platform ToC flags field which occupies + * bits [32-47] in fip header. + */ + state->plat_toc_flag = (header.flags >> 32) & 0xffff; } } @@ -277,6 +287,7 @@ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, int result; uintptr_t backend_handle; const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec; + static const uuid_t uuid_null = { {0} }; /* Double braces for clang */ size_t bytes_read; int found_file = 0; @@ -289,9 +300,9 @@ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, * When the system supports dynamic memory allocation we can allow more * than one open file at a time if needed. */ - if (current_file.entry.offset_address != 0) { + if (current_fip_file.entry.offset_address != 0U) { WARN("fip_file_open : Only one open file at a time.\n"); - return -ENOMEM; + return -ENFILE; } /* Attempt to access the FIP image */ @@ -315,31 +326,32 @@ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, found_file = 0; do { result = io_read(backend_handle, - (uintptr_t)¤t_file.entry, - sizeof(current_file.entry), + (uintptr_t)¤t_fip_file.entry, + sizeof(current_fip_file.entry), &bytes_read); if (result == 0) { - if (compare_uuids(¤t_file.entry.uuid, + if (compare_uuids(¤t_fip_file.entry.uuid, &uuid_spec->uuid) == 0) { found_file = 1; - break; } } else { WARN("Failed to read FIP (%i)\n", result); goto fip_file_open_close; } - } while (compare_uuids(¤t_file.entry.uuid, &uuid_null) != 0); + } while ((found_file == 0) && + (compare_uuids(¤t_fip_file.entry.uuid, + &uuid_null) != 0)); if (found_file == 1) { /* All fine. Update entity info with file state and return. Set - * the file position to 0. The 'current_file.entry' holds the - * base and size of the file. + * the file position to 0. The 'current_fip_file.entry' holds + * the base and size of the file. */ - current_file.file_pos = 0; - entity->info = (uintptr_t)¤t_file; + current_fip_file.file_pos = 0; + entity->info = (uintptr_t)¤t_fip_file; } else { /* Did not find the file in the FIP. */ - current_file.entry.offset_address = 0; + current_fip_file.entry.offset_address = 0; result = -ENOENT; } @@ -357,7 +369,7 @@ static int fip_file_len(io_entity_t *entity, size_t *length) assert(entity != NULL); assert(length != NULL); - *length = ((file_state_t *)entity->info)->entry.size; + *length = ((fip_file_state_t *)entity->info)->entry.size; return 0; } @@ -368,7 +380,7 @@ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { int result; - file_state_t *fp; + fip_file_state_t *fp; size_t file_offset; size_t bytes_read; uintptr_t backend_handle; @@ -386,7 +398,7 @@ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, goto fip_file_read_exit; } - fp = (file_state_t *)entity->info; + fp = (fip_file_state_t *)entity->info; /* Seek to the position in the FIP where the payload lives */ file_offset = fp->entry.offset_address + fp->file_pos; @@ -425,8 +437,8 @@ static int fip_file_close(io_entity_t *entity) /* Clear our current file pointer. * If we had malloc() we would free() here. */ - if (current_file.entry.offset_address != 0) { - zeromem(¤t_file, sizeof(current_file)); + if (current_fip_file.entry.offset_address != 0U) { + zeromem(¤t_fip_file, sizeof(current_fip_file)); } /* Clear the Entity info. */ @@ -453,3 +465,17 @@ int register_io_dev_fip(const io_dev_connector_t **dev_con) return result; } + +/* Function to retrieve plat_toc_flags, previously saved in FIP dev */ +int fip_dev_get_plat_toc_flag(io_dev_info_t *dev_info, uint16_t *plat_toc_flag) +{ + fip_dev_state_t *state; + + assert(dev_info != NULL); + + state = (fip_dev_state_t *)dev_info->info; + + *plat_toc_flag = state->plat_toc_flag; + + return 0; +} diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c index eed50cc08..eb69163b7 100644 --- a/drivers/io/io_memmap.c +++ b/drivers/io/io_memmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -27,9 +27,9 @@ typedef struct { uintptr_t base; unsigned long long file_pos; unsigned long long size; -} file_state_t; +} memmap_file_state_t; -static file_state_t current_file = {0}; +static memmap_file_state_t current_memmap_file = {0}; /* Identify the device type as memmap */ static io_type_t device_type_memmap(void) @@ -71,7 +71,7 @@ static const io_dev_funcs_t memmap_dev_funcs = { /* No state associated with this device so structure can be const */ -static const io_dev_info_t memmap_dev_info = { +static io_dev_info_t memmap_dev_info = { .funcs = &memmap_dev_funcs, .info = (uintptr_t)NULL }; @@ -82,8 +82,7 @@ static int memmap_dev_open(const uintptr_t dev_spec __unused, io_dev_info_t **dev_info) { assert(dev_info != NULL); - *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */ - + *dev_info = &memmap_dev_info; return 0; } @@ -109,16 +108,16 @@ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, * spec at a time. When we have dynamic memory we can malloc and set * entity->info. */ - if (current_file.in_use == 0) { + if (current_memmap_file.in_use == 0) { assert(block_spec != NULL); assert(entity != NULL); - current_file.in_use = 1; - current_file.base = block_spec->offset; + current_memmap_file.in_use = 1; + current_memmap_file.base = block_spec->offset; /* File cursor offset for seek and incremental reads etc. */ - current_file.file_pos = 0; - current_file.size = block_spec->length; - entity->info = (uintptr_t)¤t_file; + current_memmap_file.file_pos = 0; + current_memmap_file.size = block_spec->length; + entity->info = (uintptr_t)¤t_memmap_file; result = 0; } else { WARN("A Memmap device is already active. Close first.\n"); @@ -133,13 +132,13 @@ static int memmap_block_seek(io_entity_t *entity, int mode, signed long long offset) { int result = -ENOENT; - file_state_t *fp; + memmap_file_state_t *fp; /* We only support IO_SEEK_SET for the moment. */ if (mode == IO_SEEK_SET) { assert(entity != NULL); - fp = (file_state_t *) entity->info; + fp = (memmap_file_state_t *) entity->info; /* Assert that new file position is valid */ assert((offset >= 0) && @@ -160,7 +159,7 @@ static int memmap_block_len(io_entity_t *entity, size_t *length) assert(entity != NULL); assert(length != NULL); - *length = (size_t)((file_state_t *)entity->info)->size; + *length = (size_t)((memmap_file_state_t *)entity->info)->size; return 0; } @@ -170,13 +169,13 @@ static int memmap_block_len(io_entity_t *entity, size_t *length) static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { - file_state_t *fp; + memmap_file_state_t *fp; unsigned long long pos_after; assert(entity != NULL); assert(length_read != NULL); - fp = (file_state_t *) entity->info; + fp = (memmap_file_state_t *) entity->info; /* Assert that file position is valid for this read operation */ pos_after = fp->file_pos + length; @@ -198,13 +197,13 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written) { - file_state_t *fp; + memmap_file_state_t *fp; unsigned long long pos_after; assert(entity != NULL); assert(length_written != NULL); - fp = (file_state_t *) entity->info; + fp = (memmap_file_state_t *) entity->info; /* Assert that file position is valid for this write operation */ pos_after = fp->file_pos + length; @@ -230,7 +229,7 @@ static int memmap_block_close(io_entity_t *entity) entity->info = 0; /* This would be a mem free() if we had malloc.*/ - zeromem((void *)¤t_file, sizeof(current_file)); + zeromem((void *)¤t_memmap_file, sizeof(current_memmap_file)); return 0; } diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c index 4ceddc6cc..1c2f84d54 100644 --- a/drivers/io/io_semihosting.c +++ b/drivers/io/io_semihosting.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -51,8 +51,7 @@ static const io_dev_funcs_t sh_dev_funcs = { }; -/* No state associated with this device so structure can be const */ -static const io_dev_info_t sh_dev_info = { +static io_dev_info_t sh_dev_info = { .funcs = &sh_dev_funcs, .info = (uintptr_t)NULL }; @@ -63,7 +62,7 @@ static int sh_dev_open(const uintptr_t dev_spec __unused, io_dev_info_t **dev_info) { assert(dev_info != NULL); - *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ + *dev_info = &sh_dev_info; return 0; } diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c index b8c1d6479..053426891 100644 --- a/drivers/io/io_storage.c +++ b/drivers/io/io_storage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -32,36 +32,34 @@ static unsigned int dev_count; #if ENABLE_ASSERTIONS /* Return a boolean value indicating whether a device connector is valid */ -static int is_valid_dev_connector(const io_dev_connector_t *dev_con) +static bool is_valid_dev_connector(const io_dev_connector_t *dev_con) { - int result = (dev_con != NULL) && (dev_con->dev_open != NULL); - return result; + return (dev_con != NULL) && (dev_con->dev_open != NULL); } - /* Return a boolean value indicating whether a device handle is valid */ -static int is_valid_dev(const uintptr_t dev_handle) +static bool is_valid_dev(const uintptr_t dev_handle) { const io_dev_info_t *dev = (io_dev_info_t *)dev_handle; - int result = (dev != NULL) && (dev->funcs != NULL) && + + return (dev != NULL) && (dev->funcs != NULL) && (dev->funcs->type != NULL) && (dev->funcs->type() < IO_TYPE_MAX); - return result; } /* Return a boolean value indicating whether an IO entity is valid */ -static int is_valid_entity(const uintptr_t handle) +static bool is_valid_entity(const uintptr_t handle) { const io_entity_t *entity = (io_entity_t *)handle; - int result = (entity != NULL) && + + return (entity != NULL) && (is_valid_dev((uintptr_t)entity->dev_handle)); - return result; } /* Return a boolean value indicating whether a seek mode is valid */ -static int is_valid_seek_mode(io_seek_mode_t mode) +static bool is_valid_seek_mode(io_seek_mode_t mode) { return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX)); } @@ -71,15 +69,14 @@ static int is_valid_seek_mode(io_seek_mode_t mode) /* Open a connection to a specific device */ -static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, +static int io_storage_dev_open(const io_dev_connector_t *dev_con, + const uintptr_t dev_spec, io_dev_info_t **dev_info) { - int result; assert(dev_info != NULL); assert(is_valid_dev_connector(dev_con)); - result = dev_con->dev_open(dev_spec, dev_info); - return result; + return dev_con->dev_open(dev_spec, dev_info); } @@ -116,7 +113,8 @@ static int allocate_entity(io_entity_t **entity) unsigned int index = 0; result = find_first_entity(NULL, &index); assert(result == 0); - *entity = entity_map[index] = &entity_pool[index]; + *entity = &entity_pool[index]; + entity_map[index] = &entity_pool[index]; ++entity_count; } @@ -163,11 +161,8 @@ int io_register_device(const io_dev_info_t *dev_info) int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, uintptr_t *handle) { - int result; assert(handle != NULL); - - result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); - return result; + return io_storage_dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); } |