aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/io
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/io')
-rw-r--r--drivers/io/io_encrypted.c244
-rw-r--r--drivers/io/io_fip.c68
-rw-r--r--drivers/io/io_memmap.c39
-rw-r--r--drivers/io/io_semihosting.c7
-rw-r--r--drivers/io/io_storage.c37
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)&current_file.entry,
- sizeof(current_file.entry),
+ (uintptr_t)&current_fip_file.entry,
+ sizeof(current_fip_file.entry),
&bytes_read);
if (result == 0) {
- if (compare_uuids(&current_file.entry.uuid,
+ if (compare_uuids(&current_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(&current_file.entry.uuid, &uuid_null) != 0);
+ } while ((found_file == 0) &&
+ (compare_uuids(&current_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)&current_file;
+ current_fip_file.file_pos = 0;
+ entity->info = (uintptr_t)&current_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(&current_file, sizeof(current_file));
+ if (current_fip_file.entry.offset_address != 0U) {
+ zeromem(&current_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)&current_file;
+ current_memmap_file.file_pos = 0;
+ current_memmap_file.size = block_spec->length;
+ entity->info = (uintptr_t)&current_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 *)&current_file, sizeof(current_file));
+ zeromem((void *)&current_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);
}