diff --git a/include/services/sprt_svc.h b/include/services/sprt_svc.h index ccc4eb3..b6b51dd 100644 --- a/include/services/sprt_svc.h +++ b/include/services/sprt_svc.h @@ -53,6 +53,15 @@ #define SPRT_MEMORY_PERM_ATTR_GET_AARCH64 SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_GET) #define SPRT_MEMORY_PERM_ATTR_SET_AARCH64 SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_SET) +/* Defines used by SPRT_MEMORY_PERM_ATTR_{GET,SET}_AARCH64 */ + +#define SPRT_MEMORY_PERM_ATTR_RO U(0) +#define SPRT_MEMORY_PERM_ATTR_RW U(1) +#define SPRT_MEMORY_PERM_ATTR_RO_EXEC U(2) +/* U(3) is reserved */ +#define SPRT_MEMORY_PERM_ATTR_MASK U(3) +#define SPRT_MEMORY_PERM_ATTR_SHIFT 3 + /* SPRT error codes. */ #define SPRT_SUCCESS 0 diff --git a/services/std_svc/spm/sp_xlat.c b/services/std_svc/spm/sp_xlat.c index 443b0b9..bbe392d 100644 --- a/services/std_svc/spm/sp_xlat.c +++ b/services/std_svc/spm/sp_xlat.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -25,9 +24,6 @@ * Instantiation of translation table context ******************************************************************************/ -/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */ -static spinlock_t mem_attr_smc_lock; - /* Place translation tables by default along with the ones used by BL31. */ #ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME #define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table" @@ -314,123 +310,3 @@ init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle); } - -/******************************************************************************* - * Functions to manipulate memory regions - ******************************************************************************/ - -/* - * Attributes are encoded using a different format in the SMC interface than in - * the Trusted Firmware, where the mmap_attr_t enum type is used. This function - * converts an attributes value from the SMC format to the mmap_attr_t format by - * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER. - * The other fields are left as 0 because they are ignored by the function - * xlat_change_mem_attributes_ctx(). - */ -static unsigned int smc_attr_to_mmap_attr(unsigned int attributes) -{ - unsigned int tf_attr = 0U; - - unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) - >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; - - if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) { - tf_attr |= MT_RW | MT_USER; - } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) { - tf_attr |= MT_RO | MT_USER; - } else { - /* Other values are reserved. */ - assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS); - /* The only requirement is that there's no access from EL0 */ - tf_attr |= MT_RO | MT_PRIVILEGED; - } - - if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) { - tf_attr |= MT_EXECUTE; - } else { - tf_attr |= MT_EXECUTE_NEVER; - } - - return tf_attr; -} - -/* - * This function converts attributes from the Trusted Firmware format into the - * SMC interface format. - */ -static unsigned int smc_mmap_to_smc_attr(unsigned int attr) -{ - unsigned int smc_attr = 0U; - - unsigned int data_access; - - if ((attr & MT_USER) == 0) { - /* No access from EL0. */ - data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS; - } else { - if ((attr & MT_RW) != 0) { - assert(MT_TYPE(attr) != MT_DEVICE); - data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW; - } else { - data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO; - } - } - - smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) - << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; - - if ((attr & MT_EXECUTE_NEVER) != 0U) { - smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC; - } - - return smc_attr; -} - -int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, - uintptr_t base_va) -{ - uint32_t attributes; - - spin_lock(&mem_attr_smc_lock); - - int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, - base_va, &attributes); - - spin_unlock(&mem_attr_smc_lock); - - /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */ - assert((rc == 0) || (rc == -EINVAL)); - - if (rc == 0) { - return (int32_t) smc_mmap_to_smc_attr(attributes); - } else { - return SPM_INVALID_PARAMETER; - } -} - -int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, - u_register_t page_address, - u_register_t pages_count, - u_register_t smc_attributes) -{ - uintptr_t base_va = (uintptr_t) page_address; - size_t size = (size_t) (pages_count * PAGE_SIZE); - uint32_t attributes = (uint32_t) smc_attributes; - - INFO(" Start address : 0x%lx\n", base_va); - INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size); - INFO(" Attributes : 0x%x\n", attributes); - - spin_lock(&mem_attr_smc_lock); - - int ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, - base_va, size, - smc_attr_to_mmap_attr(attributes)); - - spin_unlock(&mem_attr_smc_lock); - - /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */ - assert((ret == 0) || (ret == -EINVAL)); - - return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER; -} diff --git a/services/std_svc/spm/spm_main.c b/services/std_svc/spm/spm_main.c index 5d3cc1a..d80775f 100644 --- a/services/std_svc/spm/spm_main.c +++ b/services/std_svc/spm/spm_main.c @@ -375,8 +375,6 @@ ns = is_caller_non_secure(flags); if (ns == SMC_FROM_SECURE) { - unsigned int linear_id = plat_my_core_pos(); - sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id); /* Handle SMCs from Secure world. */ @@ -390,27 +388,6 @@ case SPM_VERSION_AARCH32: SMC_RET1(handle, SPM_VERSION_COMPILED); - case SP_MEMORY_ATTRIBUTES_GET_AARCH64: - INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n"); - - if (sp_ctx->state != SP_STATE_RESET) { - WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n"); - SMC_RET1(handle, SPM_NOT_SUPPORTED); - } - SMC_RET1(handle, - spm_memory_attributes_get_smc_handler( - sp_ctx, x1)); - - case SP_MEMORY_ATTRIBUTES_SET_AARCH64: - INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n"); - - if (sp_ctx->state != SP_STATE_RESET) { - WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n"); - SMC_RET1(handle, SPM_NOT_SUPPORTED); - } - SMC_RET1(handle, - spm_memory_attributes_set_smc_handler( - sp_ctx, x1, x2, x3)); default: break; } @@ -422,11 +399,6 @@ switch (smc_fid) { - case SP_MEMORY_ATTRIBUTES_GET_AARCH64: - case SP_MEMORY_ATTRIBUTES_SET_AARCH64: - /* SMC interfaces reserved for secure callers. */ - SMC_RET1(handle, SPM_NOT_SUPPORTED); - default: break; } diff --git a/services/std_svc/spm/spm_private.h b/services/std_svc/spm/spm_private.h index 5414e83..c1aad93 100644 --- a/services/std_svc/spm/spm_private.h +++ b/services/std_svc/spm/spm_private.h @@ -55,9 +55,12 @@ uint64_t c_rt_ctx; cpu_context_t cpu_ctx; - xlat_ctx_t *xlat_ctx_handle; struct sp_res_desc rd; + /* Translation tables context */ + xlat_ctx_t *xlat_ctx_handle; + spinlock_t xlat_ctx_lock; + sp_state_t state; spinlock_t state_lock; @@ -95,13 +98,6 @@ xlat_ctx_t *spm_sp_xlat_context_alloc(void); void sp_map_memory_regions(sp_context_t *sp_ctx); -int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, - uintptr_t base_va); -int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, - u_register_t page_address, - u_register_t pages_count, - u_register_t smc_attributes); - /* Functions to handle Secure Partition contexts */ void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx); sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id); diff --git a/services/std_svc/spm/sprt.c b/services/std_svc/spm/sprt.c index 5330025..034dced 100644 --- a/services/std_svc/spm/sprt.c +++ b/services/std_svc/spm/sprt.c @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -16,6 +19,138 @@ #include "spm_private.h" /******************************************************************************* + * Functions to manipulate memory regions + ******************************************************************************/ + +/* + * Attributes are encoded using a different format in the SMC interface than in + * the Trusted Firmware, where the mmap_attr_t enum type is used. This function + * converts an attributes value from the SMC format to the mmap_attr_t format by + * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER. + * The other fields are left as 0 because they are ignored by the function + * xlat_change_mem_attributes_ctx(). + */ +static unsigned int smc_attr_to_mmap_attr(unsigned int attributes) +{ + unsigned int perm = attributes & SPRT_MEMORY_PERM_ATTR_MASK; + + if (perm == SPRT_MEMORY_PERM_ATTR_RW) { + return MT_RW | MT_EXECUTE_NEVER | MT_USER; + } else if (perm == SPRT_MEMORY_PERM_ATTR_RO) { + return MT_RO | MT_EXECUTE_NEVER | MT_USER; + } else if (perm == SPRT_MEMORY_PERM_ATTR_RO_EXEC) { + return MT_RO | MT_USER; + } else { + return UINT_MAX; + } +} + +/* + * This function converts attributes from the Trusted Firmware format into the + * SMC interface format. + */ +static unsigned int mmap_attr_to_smc_attr(unsigned int attr) +{ + unsigned int perm; + + /* No access from EL0. */ + if ((attr & MT_USER) == 0U) + return UINT_MAX; + + if ((attr & MT_RW) != 0) { + assert(MT_TYPE(attr) != MT_DEVICE); + perm = SPRT_MEMORY_PERM_ATTR_RW; + } else { + if ((attr & MT_EXECUTE_NEVER) != 0U) { + perm = SPRT_MEMORY_PERM_ATTR_RO; + } else { + perm = SPRT_MEMORY_PERM_ATTR_RO_EXEC; + } + } + + return perm << SPRT_MEMORY_PERM_ATTR_SHIFT; +} + +static int32_t sprt_memory_perm_attr_get(sp_context_t *sp_ctx, uintptr_t base_va) +{ + uint32_t attributes; + + spin_lock(&(sp_ctx->xlat_ctx_lock)); + + int ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, + base_va, &attributes); + + spin_unlock(&(sp_ctx->xlat_ctx_lock)); + + /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */ + assert((ret == 0) || (ret == -EINVAL)); + + if (ret != 0) + return SPRT_INVALID_PARAMETER; + + unsigned int perm = mmap_attr_to_smc_attr(attributes); + + if (perm == UINT_MAX) + return SPRT_INVALID_PARAMETER; + + return SPRT_SUCCESS | perm; +} + +static int32_t sprt_memory_perm_attr_set(sp_context_t *sp_ctx, + u_register_t page_address, u_register_t pages_count, + u_register_t smc_attributes) +{ + int ret; + uintptr_t base_va = (uintptr_t) page_address; + size_t size = pages_count * PAGE_SIZE; + + VERBOSE(" Start address : 0x%lx\n", base_va); + VERBOSE(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size); + VERBOSE(" Attributes : 0x%lx\n", smc_attributes); + + uint32_t mmap_attr = smc_attr_to_mmap_attr(smc_attributes); + + if (mmap_attr == UINT_MAX) { + WARN("%s: Invalid memory attributes: 0x%lx\n", __func__, + smc_attributes); + return SPRT_INVALID_PARAMETER; + } + + /* + * Perform some checks before actually trying to change the memory + * attributes. + */ + + spin_lock(&(sp_ctx->xlat_ctx_lock)); + + uint32_t attributes; + + ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, + base_va, &attributes); + + if (ret != 0) { + spin_unlock(&(sp_ctx->xlat_ctx_lock)); + return SPRT_INVALID_PARAMETER; + } + + if ((attributes & MT_USER) == 0U) { + /* Prohibit changing attributes of S-EL1 regions */ + spin_unlock(&(sp_ctx->xlat_ctx_lock)); + return SPRT_INVALID_PARAMETER; + } + + ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, + base_va, size, mmap_attr); + + spin_unlock(&(sp_ctx->xlat_ctx_lock)); + + /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */ + assert((ret == 0) || (ret == -EINVAL)); + + return (ret == 0) ? SPRT_SUCCESS : SPRT_INVALID_PARAMETER; +} + +/******************************************************************************* * This function handles all SMCs in the range reserved for SPRT. ******************************************************************************/ uint64_t sprt_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, @@ -53,6 +188,24 @@ case SPRT_YIELD_AARCH64: spm_sp_synchronous_exit(SPRT_YIELD_AARCH64); + case SPRT_MEMORY_PERM_ATTR_GET_AARCH64: + { + /* Get context of the SP in use by this CPU. */ + unsigned int linear_id = plat_my_core_pos(); + sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id); + + SMC_RET1(handle, sprt_memory_perm_attr_get(sp_ctx, x1)); + } + + case SPRT_MEMORY_PERM_ATTR_SET_AARCH64: + { + /* Get context of the SP in use by this CPU. */ + unsigned int linear_id = plat_my_core_pos(); + sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id); + + SMC_RET1(handle, sprt_memory_perm_attr_set(sp_ctx, x1, x2, x3)); + } + default: break; }