diff options
Diffstat (limited to 'lib/fconf')
-rw-r--r-- | lib/fconf/fconf.c | 78 | ||||
-rw-r--r-- | lib/fconf/fconf.mk | 19 | ||||
-rw-r--r-- | lib/fconf/fconf_amu_getter.c | 142 | ||||
-rw-r--r-- | lib/fconf/fconf_cot_getter.c | 499 | ||||
-rw-r--r-- | lib/fconf/fconf_dyn_cfg_getter.c | 157 | ||||
-rw-r--r-- | lib/fconf/fconf_mpmm_getter.c | 80 | ||||
-rw-r--r-- | lib/fconf/fconf_tbbr_getter.c | 84 |
7 files changed, 1059 insertions, 0 deletions
diff --git a/lib/fconf/fconf.c b/lib/fconf/fconf.c new file mode 100644 index 0000000..136e056 --- /dev/null +++ b/lib/fconf/fconf.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2022, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <lib/fconf/fconf.h> +#include <lib/fconf/fconf_dyn_cfg_getter.h> +#include <libfdt.h> +#include <plat/common/platform.h> +#include <platform_def.h> + +int fconf_load_config(unsigned int image_id) +{ + int err; + const struct dyn_cfg_dtb_info_t *config_info; + + assert((image_id == FW_CONFIG_ID) || (image_id == TB_FW_CONFIG_ID)); + + image_info_t config_image_info = { + .h.type = (uint8_t)PARAM_IMAGE_BINARY, + .h.version = (uint8_t)VERSION_2, + .h.size = (uint16_t)sizeof(image_info_t), + .h.attr = 0 + }; + + config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, image_id); + assert(config_info != NULL); + + config_image_info.image_base = config_info->config_addr; + config_image_info.image_max_size = config_info->config_max_size; + + VERBOSE("FCONF: Loading config with image ID: %u\n", image_id); + err = load_auth_image(image_id, &config_image_info); + if (err != 0) { + VERBOSE("Failed to load config %u\n", image_id); + return err; + } + + INFO("FCONF: Config file with image ID:%u loaded at address = 0x%lx\n", + image_id, config_image_info.image_base); + + return 0; +} + +void fconf_populate(const char *config_type, uintptr_t config) +{ + assert(config != 0UL); + + /* Check if the pointer to DTB is correct */ + if (fdt_check_header((void *)config) != 0) { + ERROR("FCONF: Invalid DTB file passed for %s\n", config_type); + panic(); + } + + INFO("FCONF: Reading %s firmware configuration file from: 0x%lx\n", config_type, config); + + /* Go through all registered populate functions */ + IMPORT_SYM(struct fconf_populator *, __FCONF_POPULATOR_START__, start); + IMPORT_SYM(struct fconf_populator *, __FCONF_POPULATOR_END__, end); + const struct fconf_populator *populator; + + for (populator = start; populator != end; populator++) { + assert((populator->info != NULL) && (populator->populate != NULL)); + + if (strcmp(populator->config_type, config_type) == 0) { + INFO("FCONF: Reading firmware configuration information for: %s\n", populator->info); + if (populator->populate(config) != 0) { + /* TODO: handle property miss */ + panic(); + } + } + } +} diff --git a/lib/fconf/fconf.mk b/lib/fconf/fconf.mk new file mode 100644 index 0000000..ff781aa --- /dev/null +++ b/lib/fconf/fconf.mk @@ -0,0 +1,19 @@ +# +# Copyright (c) 2019-2021, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include common/fdt_wrappers.mk + +FCONF_SOURCES := lib/fconf/fconf.c +FCONF_SOURCES += ${FDT_WRAPPERS_SOURCES} + +FCONF_DYN_SOURCES := lib/fconf/fconf_dyn_cfg_getter.c +FCONF_DYN_SOURCES += ${FDT_WRAPPERS_SOURCES} + +FCONF_AMU_SOURCES := lib/fconf/fconf_amu_getter.c +FCONF_AMU_SOURCES += ${FDT_WRAPPERS_SOURCES} + +FCONF_MPMM_SOURCES := lib/fconf/fconf_mpmm_getter.c +FCONF_MPMM_SOURCES += ${FDT_WRAPPERS_SOURCES} diff --git a/lib/fconf/fconf_amu_getter.c b/lib/fconf/fconf_amu_getter.c new file mode 100644 index 0000000..eff309c --- /dev/null +++ b/lib/fconf/fconf_amu_getter.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stddef.h> +#include <stdint.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <lib/fconf/fconf.h> +#include <lib/fconf/fconf_amu_getter.h> +#include <libfdt.h> + +#include <plat/common/platform.h> + +struct fconf_amu_config fconf_amu_config; +static struct amu_topology fconf_amu_topology_; + +/* + * Populate the core-specific AMU structure with information retrieved from a + * device tree. + * + * Returns `0` on success, or a negative integer representing an error code. + */ +static int fconf_populate_amu_cpu_amu(const void *fdt, int parent, + struct amu_core *amu) +{ + int ret = 0; + int node = 0; + + fdt_for_each_subnode(node, fdt, parent) { + const char *name; + const char *value; + int len; + + uintptr_t idx = 0U; + + name = fdt_get_name(fdt, node, &len); + if (strncmp(name, "counter@", 8) != 0) { + continue; + } + + ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL); + if (ret < 0) { + break; + } + + value = fdt_getprop(fdt, node, "enable-at-el3", &len); + if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) { + break; + } + + if (len != -FDT_ERR_NOTFOUND) { + amu->enable |= (1 << idx); + } + } + + if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { + return node; + } + + return ret; +} + +/* + * Within a `cpu` node, attempt to dereference the `amu` property, and populate + * the AMU information for the core. + * + * Returns `0` on success, or a negative integer representing an error code. + */ +static int fconf_populate_amu_cpu(const void *fdt, int node, uintptr_t mpidr) +{ + int ret; + int idx; + + uint32_t amu_phandle; + struct amu_core *amu; + + ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle); + if (ret < 0) { + if (ret == -FDT_ERR_NOTFOUND) { + ret = 0; + } + + return ret; + } + + node = fdt_node_offset_by_phandle(fdt, amu_phandle); + if (node < 0) { + return node; + } + + idx = plat_core_pos_by_mpidr(mpidr); + if (idx < 0) { + return -FDT_ERR_BADVALUE; + } + + amu = &fconf_amu_topology_.cores[idx]; + + return fconf_populate_amu_cpu_amu(fdt, node, amu); +} + +/* + * Populates the global `amu_topology` structure based on what's described by + * the hardware configuration device tree blob. + * + * The device tree is expected to provide an `amu` property for each `cpu` node, + * like so: + * + * cpu@0 { + * amu = <&cpu0_amu>; + * }; + * + * amus { + * cpu0_amu: amu-0 { + * counters { + * #address-cells = <2>; + * #size-cells = <0>; + * + * counter@x,y { + * reg = <x y>; // Group x, counter y + * }; + * }; + * }; + * }; + */ +static int fconf_populate_amu(uintptr_t config) +{ + int ret = fdtw_for_each_cpu( + (const void *)config, fconf_populate_amu_cpu); + if (ret == 0) { + fconf_amu_config.topology = &fconf_amu_topology_; + } else { + ERROR("FCONF: failed to parse AMU information: %d\n", ret); + } + + return ret; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, fconf_populate_amu); diff --git a/lib/fconf/fconf_cot_getter.c b/lib/fconf/fconf_cot_getter.c new file mode 100644 index 0000000..1033018 --- /dev/null +++ b/lib/fconf/fconf_cot_getter.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2020-2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stddef.h> + +#include <mbedtls/version.h> + +#include <common/fdt_wrappers.h> +#include <common/tbbr/cot_def.h> +#include <drivers/auth/auth_mod.h> +#include <lib/fconf/fconf.h> +#include <lib/object_pool.h> +#include <libfdt.h> + +#include <tools_share/tbbr_oid.h> + +/* static structures used during authentication process */ +static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_SIG, 0); +static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_SIG_ALG, 0); +static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_RAW_DATA, 0); + +/* pointers to an array of CoT descriptors */ +static const auth_img_desc_t *cot_desc[MAX_NUMBER_IDS]; +/* array of CoT descriptors */ +static auth_img_desc_t auth_img_descs[MAX_NUMBER_IDS]; + +/* array of authentication methods structures */ +static auth_method_desc_t auth_methods[MAX_NUMBER_IDS * AUTH_METHOD_NUM]; +static OBJECT_POOL_ARRAY(auth_methods_pool, auth_methods); + +/* array of authentication params structures */ +static auth_param_desc_t auth_params[MAX_NUMBER_IDS * COT_MAX_VERIFIED_PARAMS]; +static OBJECT_POOL_ARRAY(auth_params_pool, auth_params); + +/* array of authentication param type structures */ +static auth_param_type_desc_t auth_param_type_descs[MAX_NUMBER_IDS]; +static OBJECT_POOL_ARRAY(auth_param_type_descs_pool, auth_param_type_descs); + +/* + * array of OIDs + * Object IDs are used to search hash, pk, counter values in certificate. + * As per binding we have below 2 combinations: + * 1. Certificates are validated using nv-cntr and pk + * 2. Raw images are authenticated using hash + * Hence in worst case, there are maximum 2 OIDs per image/certificate + */ +static unsigned char oids[(MAX_NUMBER_IDS * 2)][MAX_OID_NAME_LEN]; +static OBJECT_POOL_ARRAY(oid_pool, oids); + +/* An array of auth buffer which holds hashes and pk + * ToDo: Size decided with the current number of images and + * certificates which are available in CoT. Size of these buffers bound to + * increase in the future on the addition of images/certificates. + */ +static unsigned char hash_auth_bufs[20][HASH_DER_LEN]; +static OBJECT_POOL_ARRAY(hash_auth_buf_pool, hash_auth_bufs); +static unsigned char pk_auth_bufs[12][PK_DER_LEN]; +static OBJECT_POOL_ARRAY(pk_auth_buf_pool, pk_auth_bufs); + +/******************************************************************************* + * update_parent_auth_data() - Update authentication data structure + * @auth_desc[in]: Pointer to the auth image descriptor + * @type_desc[in]: Pointer to authentication parameter + * @auth_buf_size[in]: Buffer size to hold pk or hash + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int update_parent_auth_data(const auth_img_desc_t *auth_desc, + auth_param_type_desc_t *type_desc, + unsigned int auth_buf_size) +{ + unsigned int i; + auth_param_desc_t *auth_data = &auth_desc->authenticated_data[0]; + unsigned char *auth_buf; + + for (i = 0U; i < COT_MAX_VERIFIED_PARAMS; i++) { + if (auth_data[i].type_desc == type_desc) { + return 0; + } + if (auth_data[i].type_desc == NULL) { + break; + } + } + + if (auth_buf_size == HASH_DER_LEN) { + auth_buf = pool_alloc(&hash_auth_buf_pool); + } else if (auth_buf_size == PK_DER_LEN) { + auth_buf = pool_alloc(&pk_auth_buf_pool); + } else { + return -1; + } + + if (i < COT_MAX_VERIFIED_PARAMS) { + auth_data[i].type_desc = type_desc; + auth_data[i].data.ptr = auth_buf; + auth_data[i].data.len = auth_buf_size; + } else { + ERROR("Out of authentication data array\n"); + return -1; + } + + return 0; +} + +/******************************************************************************* + * get_auth_param_type_desc() - Get pointer of authentication parameter + * @img_id[in]: Image Id + * @type_desc[out]: Pointer to authentication parameter + * @buf_size[out]: Buffer size which hold hash/pk + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int get_auth_param_type_desc(unsigned int img_id, + auth_param_type_desc_t **type_desc, + unsigned int *buf_size) +{ + auth_method_desc_t *img_auth_method = NULL; + img_type_t type = auth_img_descs[img_id].img_type; + + if (type == IMG_CERT) { + img_auth_method = + &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_SIG]; + *type_desc = img_auth_method->param.sig.pk; + *buf_size = PK_DER_LEN; + } else if (type == IMG_RAW) { + img_auth_method = + &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_HASH]; + *type_desc = img_auth_method->param.hash.hash; + *buf_size = HASH_DER_LEN; + } else { + return -1; + } + + return 0; +} + +/******************************************************************************* + * set_auth_method() - Update global auth image descriptors with authentication + * method data + * @auth_method_type[in]: Type of authentication method + * @oid[in]: Object Idetifier for pk/hash search + * @auth_method[in]: Pointer to authentication method to set + ******************************************************************************/ +static void set_auth_method(auth_method_type_t auth_method_type, char *oid, + auth_method_desc_t *auth_method) +{ + auth_param_type_t auth_param_type = AUTH_PARAM_NONE; + auth_param_type_desc_t *auth_param_type_desc; + + assert(auth_method != NULL); + + auth_param_type_desc = pool_alloc(&auth_param_type_descs_pool); + auth_method->type = auth_method_type; + + if (auth_method_type == AUTH_METHOD_SIG) { + auth_param_type = AUTH_PARAM_PUB_KEY; + auth_method->param.sig.sig = &sig; + auth_method->param.sig.alg = &sig_alg; + auth_method->param.sig.data = &raw_data; + auth_method->param.sig.pk = auth_param_type_desc; + } else if (auth_method_type == AUTH_METHOD_HASH) { + auth_param_type = AUTH_PARAM_HASH; + auth_method->param.hash.data = &raw_data; + auth_method->param.hash.hash = auth_param_type_desc; + } else if (auth_method_type == AUTH_METHOD_NV_CTR) { + auth_param_type = AUTH_PARAM_NV_CTR; + auth_method->param.nv_ctr.cert_nv_ctr = auth_param_type_desc; + auth_method->param.nv_ctr.plat_nv_ctr = auth_param_type_desc; + } + + auth_param_type_desc->type = auth_param_type; + auth_param_type_desc->cookie = (void *)oid; +} + +/******************************************************************************* + * get_oid() - get object identifier from device tree + * @dtb[in]: Pointer to the device tree blob in memory + * @node[in]: Offset of the node + * @prop[in]: Property to read from the given node + * @oid[out]: Object Indentifier of key/hash/nv-counter in certificate + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int get_oid(const void *dtb, int node, const char *prop, char **oid) +{ + uint32_t phandle; + int rc; + + rc = fdt_read_uint32(dtb, node, prop, &phandle); + if (rc < 0) { + return rc; + } + + node = fdt_node_offset_by_phandle(dtb, phandle); + if (node < 0) { + return node; + } + + *oid = pool_alloc(&oid_pool); + rc = fdtw_read_string(dtb, node, "oid", *oid, MAX_OID_NAME_LEN); + + return rc; +} + +/******************************************************************************* + * populate_and_set_auth_methods() - Populate auth method parameters from + * device tree and set authentication method + * structure. + * @dtb[in]: Pointer to the device tree blob in memory + * @node[in]: Offset of the node + * @img_id[in]: Image identifier + * @type[in]: Type of image + * @root_certificate[in]:Root certificate (authenticated by ROTPK) + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int populate_and_set_auth_methods(const void *dtb, int node, + unsigned int img_id, img_type_t type, + bool root_certificate) +{ + auth_method_type_t auth_method_type = AUTH_METHOD_NONE; + int rc; + char *oid = NULL; + + auth_method_desc_t *auth_method = pool_alloc_n(&auth_methods_pool, + AUTH_METHOD_NUM); + + /* + * This is as per binding document where certificates are + * verified by signature and images are verified by hash. + */ + if (type == IMG_CERT) { + if (root_certificate) { + oid = NULL; + } else { + rc = get_oid(dtb, node, "signing-key", &oid); + if (rc < 0) { + ERROR("FCONF: Can't read %s property\n", + "signing-key"); + return rc; + } + } + auth_method_type = AUTH_METHOD_SIG; + } else if (type == IMG_RAW) { + rc = get_oid(dtb, node, "hash", &oid); + if (rc < 0) { + ERROR("FCONF: Can't read %s property\n", + "hash"); + return rc; + } + auth_method_type = AUTH_METHOD_HASH; + } else { + return -1; + } + + set_auth_method(auth_method_type, oid, + &auth_method[auth_method_type]); + + /* Retrieve the optional property */ + rc = get_oid(dtb, node, "antirollback-counter", &oid); + if (rc == 0) { + auth_method_type = AUTH_METHOD_NV_CTR; + set_auth_method(auth_method_type, oid, + &auth_method[auth_method_type]); + } + + auth_img_descs[img_id].img_auth_methods = &auth_method[0]; + + return 0; +} + +/******************************************************************************* + * get_parent_img_id() - Get parent image id for given child node + * @dtb[in]: Pointer to the device tree blob in memory + * @node[in]: Offset of the child node + * @parent_img_id[out]: Image id of parent + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int get_parent_img_id(const void *dtb, int node, + unsigned int *parent_img_id) +{ + uint32_t phandle; + int err; + + err = fdt_read_uint32(dtb, node, "parent", &phandle); + if (err < 0) { + ERROR("FCONF: Could not read %s property in node\n", + "parent"); + return err; + } + + node = fdt_node_offset_by_phandle(dtb, phandle); + if (node < 0) { + ERROR("FCONF: Failed to locate node using its phandle\n"); + return node; + } + + err = fdt_read_uint32(dtb, node, "image-id", parent_img_id); + if (err < 0) { + ERROR("FCONF: Could not read %s property in node\n", + "image-id"); + } + + return err; +} + +/******************************************************************************* + * set_desc_data() - Update data in descriptor's structure + * @dtb[in]: Pointer to the device tree blob in memory + * @node[in]: Offset of the node + * @type[in]: Type of image (RAW/CERT) + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int set_desc_data(const void *dtb, int node, img_type_t type) +{ + int rc; + bool root_certificate = false; + unsigned int img_id, parent_img_id; + + rc = fdt_read_uint32(dtb, node, "image-id", &img_id); + if (rc < 0) { + ERROR("FCONF: Can't find property %s in node\n", + "image-id"); + return rc; + } + + if (fdt_getprop(dtb, node, "root-certificate", + NULL) != NULL) { + root_certificate = true; + } + + if (!root_certificate) { + rc = get_parent_img_id(dtb, node, &parent_img_id); + if (rc < 0) { + return rc; + } + auth_img_descs[img_id].parent = &auth_img_descs[parent_img_id]; + } + + auth_img_descs[img_id].img_id = img_id; + auth_img_descs[img_id].img_type = type; + + rc = populate_and_set_auth_methods(dtb, node, img_id, type, + root_certificate); + if (rc < 0) { + return rc; + } + + if (type == IMG_CERT) { + auth_param_desc_t *auth_param = + pool_alloc_n(&auth_params_pool, + COT_MAX_VERIFIED_PARAMS); + auth_img_descs[img_id].authenticated_data = &auth_param[0]; + } + + cot_desc[img_id] = &auth_img_descs[img_id]; + + return rc; +} + +/******************************************************************************* + * populate_manifest_descs() - Populate CoT descriptors and update global + * certificate structures + * @dtb[in]: Pointer to the device tree blob in memory + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int populate_manifest_descs(const void *dtb) +{ + int node, child; + int rc; + + /* + * Assert the node offset points to "arm, cert-descs" + * compatible property + */ + const char *compatible_str = "arm, cert-descs"; + + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find %s compatible in node\n", + compatible_str); + return node; + } + + fdt_for_each_subnode(child, dtb, node) { + rc = set_desc_data(dtb, child, IMG_CERT); + if (rc < 0) { + return rc; + } + } + + return 0; +} + +/******************************************************************************* + * populate_image_descs() - Populate CoT descriptors and update global + * image descriptor structures. + * @dtb[in]: Pointer to the device tree blob in memory + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int populate_image_descs(const void *dtb) +{ + int node, child; + int rc; + + /* + * Assert the node offset points to "arm, img-descs" + * compatible property + */ + const char *compatible_str = "arm, img-descs"; + + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find %s compatible in node\n", + compatible_str); + return node; + } + + fdt_for_each_subnode(child, dtb, node) { + rc = set_desc_data(dtb, child, IMG_RAW); + if (rc < 0) { + return rc; + } + } + + return 0; +} + +/******************************************************************************* + * fconf_populate_cot_descs() - Populate CoT descriptors and update global + * structures + * @config[in]: Pointer to the device tree blob in memory + * + * Return 0 on success or an error value otherwise. + ******************************************************************************/ +static int fconf_populate_cot_descs(uintptr_t config) +{ + auth_param_type_desc_t *type_desc = NULL; + unsigned int auth_buf_size = 0U; + int rc; + + /* As libfdt uses void *, we can't avoid this cast */ + const void *dtb = (void *)config; + + /* populate manifest descs information */ + rc = populate_manifest_descs(dtb); + if (rc < 0) { + ERROR("FCONF: population of %s descs failed %d\n", + "manifest", rc); + return rc; + } + + /* populate image descs information */ + rc = populate_image_descs(dtb); + if (rc < 0) { + ERROR("FCONF: population of %s descs failed %d\n", + "images", rc); + return rc; + } + + /* update parent's authentication data */ + for (unsigned int i = 0U; i < MAX_NUMBER_IDS; i++) { + if (auth_img_descs[i].parent != NULL) { + rc = get_auth_param_type_desc(i, + &type_desc, + &auth_buf_size); + if (rc < 0) { + ERROR("FCONF: failed to get auth data %d\n", + rc); + return rc; + } + + rc = update_parent_auth_data(auth_img_descs[i].parent, + type_desc, + auth_buf_size); + if (rc < 0) { + ERROR("FCONF: auth data update failed %d\n", + rc); + return rc; + } + } + } + + return rc; +} + +FCONF_REGISTER_POPULATOR(TB_FW, cot_desc, fconf_populate_cot_descs); +REGISTER_COT(cot_desc); diff --git a/lib/fconf/fconf_dyn_cfg_getter.c b/lib/fconf/fconf_dyn_cfg_getter.c new file mode 100644 index 0000000..58956d6 --- /dev/null +++ b/lib/fconf/fconf_dyn_cfg_getter.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019-2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <lib/fconf/fconf_dyn_cfg_getter.h> +#include <lib/object_pool.h> +#include <libfdt.h> + +#include <platform_def.h> + +/* We currently use FW, TB_FW, SOC_FW, TOS_FW, NT_FW and HW configs */ +#define MAX_DTB_INFO U(6) +/* + * Compile time assert if FW_CONFIG_ID is 0 which is more + * unlikely as 0 is a valid image ID for FIP as per the current + * code but still to avoid code breakage in case of unlikely + * event when image IDs get changed. + */ +CASSERT(FW_CONFIG_ID != U(0), assert_invalid_fw_config_id); + +static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO]; +static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos); + +/* + * This function is used to alloc memory for config information from + * global pool and set the configuration information. + */ +void set_config_info(uintptr_t config_addr, uintptr_t secondary_config_addr, + uint32_t config_max_size, + unsigned int config_id) +{ + struct dyn_cfg_dtb_info_t *dtb_info; + + dtb_info = pool_alloc(&dtb_info_pool); + dtb_info->config_addr = config_addr; + dtb_info->secondary_config_addr = secondary_config_addr; + dtb_info->config_max_size = config_max_size; + dtb_info->config_id = config_id; +} + +/* Get index of the config_id image */ +unsigned int dyn_cfg_dtb_info_get_index(unsigned int config_id) +{ + unsigned int index; + + /* Positions index to the proper config-id */ + for (index = 0U; index < MAX_DTB_INFO; index++) { + if (dtb_infos[index].config_id == config_id) { + return index; + } + } + + return FCONF_INVALID_IDX; +} + +struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id) +{ + /* Positions index to the proper config-id */ + unsigned int index = dyn_cfg_dtb_info_get_index(config_id); + + if (index < MAX_DTB_INFO) { + return &dtb_infos[index]; + } + + WARN("FCONF: Invalid config id %u\n", config_id); + + return NULL; +} + +int fconf_populate_dtb_registry(uintptr_t config) +{ + int rc; + int node, child; + + /* As libfdt use void *, we can't avoid this cast */ + const void *dtb = (void *)config; + + /* + * In case of BL1, fw_config dtb information is already + * populated in global dtb_infos array by 'set_config_info' + * function, Below check is present to avoid re-population of + * fw_config information. + * + * Other BLs, satisfy below check and populate fw_config information + * in global dtb_infos array. + */ + if (dtb_infos[0].config_id == 0U) { + uint32_t config_max_size = fdt_totalsize(dtb); + set_config_info(config, ~0UL, config_max_size, FW_CONFIG_ID); + } + + /* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */ + const char *compatible_str = "fconf,dyn_cfg-dtb_registry"; + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str); + return node; + } + + fdt_for_each_subnode(child, dtb, node) { + uint32_t config_max_size, config_id; + uintptr_t config_addr; + uintptr_t secondary_config_addr = ~0UL; + uint64_t val64; + + /* Read configuration dtb information */ + rc = fdt_read_uint64(dtb, child, "load-address", &val64); + if (rc < 0) { + ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); + return rc; + } + config_addr = (uintptr_t)val64; + + rc = fdt_read_uint32(dtb, child, "max-size", &config_max_size); + if (rc < 0) { + ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); + return rc; + } + + rc = fdt_read_uint32(dtb, child, "id", &config_id); + if (rc < 0) { + ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); + return rc; + } + + VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n"); + VERBOSE("\tload-address = %lx\n", config_addr); + VERBOSE("\tmax-size = 0x%x\n", config_max_size); + VERBOSE("\tconfig-id = %u\n", config_id); + + rc = fdt_read_uint64(dtb, child, "secondary-load-address", + &val64); + if (rc == 0) { + secondary_config_addr = (uintptr_t)val64; + VERBOSE("\tsecondary-load-address = %lx\n", + secondary_config_addr); + } + + set_config_info(config_addr, secondary_config_addr, + config_max_size, config_id); + } + + if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { + ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node); + return child; + } + + return 0; +} + +FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry); diff --git a/lib/fconf/fconf_mpmm_getter.c b/lib/fconf/fconf_mpmm_getter.c new file mode 100644 index 0000000..02a566d --- /dev/null +++ b/lib/fconf/fconf_mpmm_getter.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stddef.h> +#include <stdint.h> + +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <lib/fconf/fconf.h> +#include <lib/fconf/fconf_mpmm_getter.h> +#include <libfdt.h> + +#include <plat/common/platform.h> + +struct fconf_mpmm_config fconf_mpmm_config; +static struct mpmm_topology fconf_mpmm_topology; + +/* + * Within a `cpu` node, determine support for MPMM via the `supports-mpmm` + * property. + * + * Returns `0` on success, or a negative integer representing an error code. + */ +static int fconf_populate_mpmm_cpu(const void *fdt, int off, uintptr_t mpidr) +{ + int ret, len; + + int core_pos; + struct mpmm_core *core; + + core_pos = plat_core_pos_by_mpidr(mpidr); + if (core_pos < 0) { + return -FDT_ERR_BADVALUE; + } + + core = &fconf_mpmm_topology.cores[core_pos]; + + fdt_getprop(fdt, off, "supports-mpmm", &len); + if (len >= 0) { + core->supported = true; + ret = 0; + } else { + core->supported = false; + ret = len; + } + + return ret; +} + +/* + * Populates the global `fconf_mpmm_config` structure based on what's described + * by the hardware configuration device tree blob. + * + * The device tree is expected to provide a `supports-mpmm` property for each + * `cpu` node, like so: + * + * cpu@0 { + * supports-mpmm; + * }; + * + * This property indicates whether the core implements MPMM, as we cannot detect + * support for it dynamically. + */ +static int fconf_populate_mpmm(uintptr_t config) +{ + int ret = fdtw_for_each_cpu( + (const void *)config, fconf_populate_mpmm_cpu); + if (ret == 0) { + fconf_mpmm_config.topology = &fconf_mpmm_topology; + } else { + ERROR("FCONF: failed to configure MPMM: %d\n", ret); + } + + return ret; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, mpmm, fconf_populate_mpmm); diff --git a/lib/fconf/fconf_tbbr_getter.c b/lib/fconf/fconf_tbbr_getter.c new file mode 100644 index 0000000..c3b4b7e --- /dev/null +++ b/lib/fconf/fconf_tbbr_getter.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019-2022, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <assert.h> + +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/fdt_wrappers.h> +#include <lib/fconf/fconf_tbbr_getter.h> +#include <libfdt.h> + +struct tbbr_dyn_config_t tbbr_dyn_config; + +int fconf_populate_tbbr_dyn_config(uintptr_t config) +{ + int err; + int node; + uint64_t val64; + uint32_t val32; + + /* As libfdt use void *, we can't avoid this cast */ + const void *dtb = (void *)config; + + /* Assert the node offset point to "arm,tb_fw" compatible property */ + const char *compatible_str = "arm,tb_fw"; + node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); + if (node < 0) { + ERROR("FCONF: Can't find `%s` compatible in dtb\n", + compatible_str); + return node; + } + + /* Locate the disable_auth cell and read the value */ + err = fdt_read_uint32(dtb, node, "disable_auth", + &tbbr_dyn_config.disable_auth); + if (err < 0) { + WARN("FCONF: Read %s failed for `%s`\n", + "cell", "disable_auth"); + return err; + } + + /* Check if the value is boolean */ + if ((tbbr_dyn_config.disable_auth != 0U) && + (tbbr_dyn_config.disable_auth != 1U)) { + WARN("Invalid value for `%s` cell %u\n", + "disable_auth", tbbr_dyn_config.disable_auth); + return -1; + } + +#if defined(DYN_DISABLE_AUTH) + if (tbbr_dyn_config.disable_auth == 1) + dyn_disable_auth(); +#endif + + /* Retrieve the Mbed TLS heap details from the DTB */ + err = fdt_read_uint64(dtb, node, "mbedtls_heap_addr", &val64); + if (err < 0) { + ERROR("FCONF: Read %s failed for `%s`\n", + "cell", "mbedtls_heap_addr"); + return err; + } + tbbr_dyn_config.mbedtls_heap_addr = (void *)(uintptr_t)val64; + + err = fdt_read_uint32(dtb, node, "mbedtls_heap_size", &val32); + if (err < 0) { + ERROR("FCONF: Read %s failed for `%s`\n", + "cell", "mbedtls_heap_size"); + return err; + } + tbbr_dyn_config.mbedtls_heap_size = val32; + + VERBOSE("%s%s%s %u\n", "FCONF: `tbbr.", "disable_auth", + "` cell found with value =", tbbr_dyn_config.disable_auth); + VERBOSE("%s%s%s %p\n", "FCONF: `tbbr.", "mbedtls_heap_addr", + "` cell found with value =", tbbr_dyn_config.mbedtls_heap_addr); + VERBOSE("%s%s%s %zu\n", "FCONF: `tbbr.", "mbedtls_heap_size", + "` cell found with value =", tbbr_dyn_config.mbedtls_heap_size); + + return 0; +} + +FCONF_REGISTER_POPULATOR(TB_FW, tbbr, fconf_populate_tbbr_dyn_config); |