diff options
author | davidcunado-arm <david.cunado@arm.com> | 2017-10-04 16:23:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-04 16:23:59 +0100 |
commit | c64d1345a8227ec9c9d8f8fa6a6c3e5e487b82f0 (patch) | |
tree | 2604ec7cfc96c5ea1ea9456bd958b45a15d44e75 /lib | |
parent | cb2cfae365eedb94619f8f88f98aee8f866d9a14 (diff) | |
parent | b09ba056c4203a3fcca78675aa3de257023b7d70 (diff) | |
download | platform_external_arm-trusted-firmware-c64d1345a8227ec9c9d8f8fa6a6c3e5e487b82f0.tar.gz platform_external_arm-trusted-firmware-c64d1345a8227ec9c9d8f8fa6a6c3e5e487b82f0.tar.bz2 platform_external_arm-trusted-firmware-c64d1345a8227ec9c9d8f8fa6a6c3e5e487b82f0.zip |
Merge pull request #1109 from robertovargas-arm/mem_protect
Mem protect
Diffstat (limited to 'lib')
-rw-r--r-- | lib/psci/psci_lib.mk | 1 | ||||
-rw-r--r-- | lib/psci/psci_main.c | 9 | ||||
-rw-r--r-- | lib/psci/psci_mem_protect.c | 38 | ||||
-rw-r--r-- | lib/psci/psci_private.h | 4 | ||||
-rw-r--r-- | lib/psci/psci_setup.c | 5 | ||||
-rw-r--r-- | lib/utils/mem_region.c | 78 |
6 files changed, 135 insertions, 0 deletions
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk index 29080dbb0..1d4aac4a3 100644 --- a/lib/psci/psci_lib.mk +++ b/lib/psci/psci_lib.mk @@ -17,6 +17,7 @@ PSCI_LIB_SOURCES := lib/el3_runtime/cpu_data_array.c \ lib/psci/psci_main.c \ lib/psci/psci_setup.c \ lib/psci/psci_system_off.c \ + lib/psci/psci_mem_protect.c \ lib/psci/${ARCH}/psci_helpers.S ifeq (${ARCH}, aarch64) diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c index 257479aa9..a5d707e01 100644 --- a/lib/psci/psci_main.c +++ b/lib/psci/psci_main.c @@ -408,6 +408,11 @@ u_register_t psci_smc_handler(uint32_t smc_fid, case PSCI_STAT_COUNT_AARCH32: return psci_stat_count(x1, x2); #endif + case PSCI_MEM_PROTECT: + return psci_mem_protect(x1); + + case PSCI_MEM_CHK_RANGE_AARCH32: + return psci_mem_chk_range(x1, x2); default: break; @@ -445,6 +450,10 @@ u_register_t psci_smc_handler(uint32_t smc_fid, return psci_stat_count(x1, x2); #endif + case PSCI_MEM_CHK_RANGE_AARCH64: + return psci_mem_chk_range(x1, x2); + + default: break; } diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c new file mode 100644 index 000000000..fca84e905 --- /dev/null +++ b/lib/psci/psci_mem_protect.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <limits.h> +#include <utils.h> +#include "psci_private.h" + +int psci_mem_protect(unsigned int enable) +{ + int val; + + assert(psci_plat_pm_ops->read_mem_protect); + assert(psci_plat_pm_ops->write_mem_protect); + + if (psci_plat_pm_ops->read_mem_protect(&val) < 0) + return PSCI_E_NOT_SUPPORTED; + if (psci_plat_pm_ops->write_mem_protect(enable) < 0) + return PSCI_E_NOT_SUPPORTED; + + return val != 0; +} + +int psci_mem_chk_range(uintptr_t base, u_register_t length) +{ + int ret; + + assert(psci_plat_pm_ops->mem_protect_chk); + + if (length == 0 || check_uptr_overflow(base, length-1)) + return PSCI_E_DENIED; + + ret = psci_plat_pm_ops->mem_protect_chk(base, length); + return (ret < 0) ? PSCI_E_DENIED : PSCI_E_SUCCESS; +} diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h index da6a20fa4..facfacb03 100644 --- a/lib/psci/psci_private.h +++ b/lib/psci/psci_private.h @@ -269,4 +269,8 @@ u_register_t psci_stat_residency(u_register_t target_cpu, u_register_t psci_stat_count(u_register_t target_cpu, unsigned int power_state); +/* Private exported functions from psci_mem_protect.c */ +int psci_mem_protect(unsigned int enable); +int psci_mem_chk_range(uintptr_t base, u_register_t length); + #endif /* __PSCI_PRIVATE_H__ */ diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c index f70e34da4..5ef49acbe 100644 --- a/lib/psci/psci_setup.c +++ b/lib/psci/psci_setup.c @@ -243,6 +243,11 @@ int psci_setup(const psci_lib_args_t *lib_args) psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET); if (psci_plat_pm_ops->get_node_hw_state) psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64); + if (psci_plat_pm_ops->read_mem_protect && + psci_plat_pm_ops->write_mem_protect) + psci_caps |= define_psci_cap(PSCI_MEM_PROTECT); + if (psci_plat_pm_ops->mem_protect_chk) + psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64); #if ENABLE_PSCI_STAT psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64); diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c new file mode 100644 index 000000000..31c6231fa --- /dev/null +++ b/lib/utils/mem_region.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <utils.h> + +/* + * All the regions defined in mem_region_t must have the following properties + * + * - Any contiguous regions must be merged into a single entry. + * - The number of bytes of each region must be greater than zero. + * - The calculation of the highest address within the region (base + nbytes-1) + * doesn't produce an overflow. + * + * These conditions must be fulfilled by the caller and they aren't checked + * at runtime. + */ + +/* + * zero_normalmem all the regions defined in tbl. + * It assumes that MMU is enabled and the memory is Normal memory. + * tbl must be a valid pointer to a memory mem_region_t array, + * nregions is the size of the array. + */ +void clear_mem_regions(mem_region_t *tbl, size_t nregions) +{ + size_t i; + + assert(tbl); + assert(nregions > 0); + + for (i = 0; i < nregions; i++) { + assert(tbl->nbytes > 0); + assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); + zero_normalmem((void *) (tbl->base), tbl->nbytes); + tbl++; + } +} + +/* + * This function checks that a region (addr + nbytes-1) of memory is totally + * covered by one of the regions defined in tbl. + * tbl must be a valid pointer to a memory mem_region_t array, nregions + * is the size of the array and the region described by addr and nbytes must + * not generate an overflow. + * Returns: + * -1 means that the region is not covered by any of the regions + * described in tbl. + * 0 the region (addr + nbytes-1) is covered by one of the regions described + * in tbl + */ +int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions, + uintptr_t addr, size_t nbytes) +{ + uintptr_t region_start, region_end, start, end; + size_t i; + + assert(tbl); + assert(nbytes > 0); + assert(!check_uptr_overflow(addr, nbytes-1)); + + region_start = addr; + region_end = addr + (nbytes - 1); + for (i = 0; i < nregions; i++) { + assert(tbl->nbytes > 0); + assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); + start = tbl->base; + end = start + (tbl->nbytes - 1); + if (region_start >= start && region_end <= end) + return 0; + tbl++; + } + + return -1; +} |