From 83c3da7711a246e04f4d0a64593fc0ab46f08bad Mon Sep 17 00:00:00 2001 From: Nishant Sharma Date: Thu, 28 Apr 2022 11:52:07 +0100 Subject: [PATCH] feat(el3-spmc): add support to map S-EL0 SP memory regions Add the support to parse SP manifest to get memory regions, create xlat tables and then program it in TTBR0. SP manifest contains the info on memory map regions that are needed by the SP. These regions needs to be mapped as SP running at S-EL0 does not have privilege to do it. Signed-off-by: Sayanta Pattanayak Signed-off-by: Aditya Angadi Signed-off-by: Achin Gupta Signed-off-by: Nishant Sharma Change-Id: I0cad36e5c43f8a68c94887ff2bd798933a26be27 --- services/std_svc/spm/el3_spmc/spmc.h | 3 +- services/std_svc/spm/el3_spmc/spmc_main.c | 2 +- services/std_svc/spm/el3_spmc/spmc_setup.c | 228 +++++++++++++++++---- 3 files changed, 194 insertions(+), 39 deletions(-) diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h index e4120de07..c8515e5e0 100644 --- a/services/std_svc/spm/el3_spmc/spmc.h +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -229,7 +229,8 @@ void spmc_sp_common_ep_commit(struct secure_partition_desc *sp, entry_point_info_t *ep_info); void spmc_el0_sp_spsr_setup(entry_point_info_t *ep_info); void spmc_el0_sp_setup(struct secure_partition_desc *sp, - int32_t boot_info_reg); + int32_t boot_info_reg, + void *sp_manifest); /* * Helper function to perform a synchronous entry into a SP. diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index 44d0eccee..d661e8a47 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -1988,7 +1988,7 @@ static int find_and_prepare_sp_context(void) * context management routine. */ if (sp->runtime_el == S_EL0) { - spmc_el0_sp_setup(sp, boot_info_reg); + spmc_el0_sp_setup(sp, boot_info_reg, sp_manifest); } #endif /* SPMC_AT_EL3_SEL0_SP */ return 0; diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c index 4299ceda4..61ee0c6a3 100644 --- a/services/std_svc/spm/el3_spmc/spmc_setup.c +++ b/services/std_svc/spm/el3_spmc/spmc_setup.c @@ -37,6 +37,12 @@ static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE); * physical CPU the SP runs on. */ #define SEL0_SP_EC_INDEX 0 +#define SP_MEM_READ 0x1 +#define SP_MEM_WRITE 0x2 +#define SP_MEM_EXECUTE 0x4 +#define SP_MEM_NON_SECURE 0x8 +#define SP_MEM_READ_ONLY SP_MEM_READ +#define SP_MEM_READ_WRITE (SP_MEM_READ | SP_MEM_WRITE) /* * This function creates a initialization descriptor in the memory reserved @@ -170,75 +176,172 @@ void spmc_el0_sp_spsr_setup(entry_point_info_t *ep_info) ep_info->spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS); } -/* Setup context of an EL0 Secure Partition. */ -void spmc_el0_sp_setup(struct secure_partition_desc *sp, - int32_t boot_info_reg) +static void read_optional_string(void *manifest, int32_t offset, + char *property, char *out, size_t len) { - mmap_region_t sel1_exception_vectors = - MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START, - SPM_SHIM_EXCEPTIONS_SIZE, - MT_CODE | MT_SECURE | MT_PRIVILEGED); - cpu_context_t *ctx; + const fdt32_t *prop; + int lenp; - ctx = &sp->ec[SEL0_SP_EC_INDEX].cpu_ctx; + prop = fdt_getprop(manifest, offset, property, &lenp); + if (prop == NULL) { + out[0] = '\0'; + } else { + memcpy(out, prop, MIN(lenp, (int)len)); + } +} - sp->xlat_ctx_handle->xlat_regime = EL1_EL0_REGIME; +/******************************************************************************* + * This function will parse the Secure Partition Manifest for fetching secure + * partition specific memory region details. It will find base address, size, + * memory attributes for each memory region and then add the respective region + * into secure parition's translation context. + ******************************************************************************/ +static void populate_sp_mem_regions(struct secure_partition_desc *sp, + void *sp_manifest, + int node) +{ + uintptr_t base_address; + uint32_t mem_attr, mem_region, size; + struct mmap_region sp_mem_regions; + int32_t offset, ret; + char description[10]; + char *property; + + if (fdt_node_check_compatible(sp_manifest, node, + "arm,ffa-manifest-memory-regions") != 0) { + WARN("Incompatible memory region node in manifest\n"); + return; + } - /* This region contains the exception vectors used at S-EL1. */ - mmap_add_region_ctx(sp->xlat_ctx_handle, - &sel1_exception_vectors); + INFO("Mapping SP's memory regions\n"); - /* - * If the SP manifest specified the register to pass the address of the - * boot information, then map the memory region to pass boot - * information. - */ - if (boot_info_reg >= 0) { - mmap_region_t ffa_boot_info_region = MAP_REGION_FLAT( - (uintptr_t) ffa_boot_info_mem, - PAGE_SIZE, - MT_RO_DATA | MT_SECURE | MT_USER); - mmap_add_region_ctx(sp->xlat_ctx_handle, &ffa_boot_info_region); + for (offset = fdt_first_subnode(sp_manifest, node), mem_region = 0; + offset >= 0; + offset = fdt_next_subnode(sp_manifest, offset), mem_region++) { + read_optional_string(sp_manifest, offset, "description", + description, sizeof(description)); + + INFO("Mapping: region: %d, %s\n", mem_region, description); + + property = "base-address"; + ret = fdt_read_uint64(sp_manifest, offset, property, + &base_address); + if (ret < 0) { + WARN("Missing:%s for %s.\n", property, description); + continue; + } + + property = "pages-count"; + ret = fdt_read_uint32(sp_manifest, offset, property, &size); + if (ret < 0) { + WARN("Missing: %s for %s.\n", property, description); + continue; + } + size *= PAGE_SIZE; + + property = "attributes"; + ret = fdt_read_uint32(sp_manifest, offset, property, &mem_attr); + if (ret < 0) { + WARN("Missing: %s for %s.\n", property, description); + continue; + } + + sp_mem_regions.attr = MT_USER; + if ((mem_attr & SP_MEM_EXECUTE) == SP_MEM_EXECUTE) { + sp_mem_regions.attr |= MT_CODE; + } else if ((mem_attr & SP_MEM_READ_ONLY) == SP_MEM_READ_ONLY) { + sp_mem_regions.attr |= MT_RO_DATA; + } else if ((mem_attr & SP_MEM_READ_WRITE) == + SP_MEM_READ_WRITE) { + sp_mem_regions.attr |= MT_RW_DATA; + } + + if ((mem_attr & SP_MEM_NON_SECURE) == SP_MEM_NON_SECURE) { + sp_mem_regions.attr |= MT_NS; + } else { + sp_mem_regions.attr |= MT_SECURE; + } + + sp_mem_regions.base_pa = base_address; + sp_mem_regions.base_va = base_address; + sp_mem_regions.size = size; + sp_mem_regions.granularity = XLAT_BLOCK_SIZE(3); + mmap_add_region_ctx(sp->xlat_ctx_handle, &sp_mem_regions); } +} + +static void spmc_el0_sp_setup_mmu(struct secure_partition_desc *sp, + cpu_context_t *ctx) +{ + xlat_ctx_t *xlat_ctx; + uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; + + xlat_ctx = sp->xlat_ctx_handle; + init_xlat_tables_ctx(sp->xlat_ctx_handle); + setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table, + xlat_ctx->pa_max_address, xlat_ctx->va_max_address, + EL1_EL0_REGIME); + + write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1, + mmu_cfg_params[MMU_CFG_MAIR]); + + write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1, + mmu_cfg_params[MMU_CFG_TCR]); + + write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1, + mmu_cfg_params[MMU_CFG_TTBR0]); +} + +static void spmc_el0_sp_setup_sctlr_el1(cpu_context_t *ctx) +{ + u_register_t sctlr_el1; /* Setup SCTLR_EL1 */ - u_register_t sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1); + sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1); sctlr_el1 |= /*SCTLR_EL1_RES1 |*/ /* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */ - SCTLR_UCI_BIT | + SCTLR_UCI_BIT | /* RW regions at xlat regime EL1&0 are forced to be XN. */ - SCTLR_WXN_BIT | + SCTLR_WXN_BIT | /* Don't trap to EL1 execution of WFI or WFE at EL0. */ - SCTLR_NTWI_BIT | SCTLR_NTWE_BIT | + SCTLR_NTWI_BIT | SCTLR_NTWE_BIT | /* Don't trap to EL1 accesses to CTR_EL0 from EL0. */ - SCTLR_UCT_BIT | + SCTLR_UCT_BIT | /* Don't trap to EL1 execution of DZ ZVA at EL0. */ - SCTLR_DZE_BIT | + SCTLR_DZE_BIT | /* Enable SP Alignment check for EL0 */ - SCTLR_SA0_BIT | + SCTLR_SA0_BIT | /* Don't change PSTATE.PAN on taking an exception to EL1 */ - SCTLR_SPAN_BIT | + SCTLR_SPAN_BIT | /* Allow cacheable data and instr. accesses to normal memory. */ - SCTLR_C_BIT | SCTLR_I_BIT | + SCTLR_C_BIT | SCTLR_I_BIT | /* Enable MMU. */ - SCTLR_M_BIT - ; + SCTLR_M_BIT; sctlr_el1 &= ~( /* Explicit data accesses at EL0 are little-endian. */ - SCTLR_E0E_BIT | + SCTLR_E0E_BIT | /* * Alignment fault checking disabled when at EL1 and EL0 as * the UEFI spec permits unaligned accesses. */ - SCTLR_A_BIT | + SCTLR_A_BIT | /* Accesses to DAIF from EL0 are trapped to EL1. */ SCTLR_UMA_BIT ); write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1); +} + +static void spmc_el0_sp_setup_system_registers(struct secure_partition_desc *sp, + cpu_context_t *ctx) +{ + + spmc_el0_sp_setup_mmu(sp, ctx); + + spmc_el0_sp_setup_sctlr_el1(ctx); /* Setup other system registers. */ @@ -260,6 +363,57 @@ void spmc_el0_sp_setup(struct secure_partition_desc *sp, write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1, CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE)); } + +/* Setup context of an EL0 Secure Partition. */ +void spmc_el0_sp_setup(struct secure_partition_desc *sp, + int32_t boot_info_reg, + void *sp_manifest) +{ + mmap_region_t sel1_exception_vectors = + MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START, + SPM_SHIM_EXCEPTIONS_SIZE, + MT_CODE | MT_SECURE | MT_PRIVILEGED); + cpu_context_t *ctx; + int node; + int offset = 0; + + ctx = &sp->ec[SEL0_SP_EC_INDEX].cpu_ctx; + + sp->xlat_ctx_handle->xlat_regime = EL1_EL0_REGIME; + + /* This region contains the exception vectors used at S-EL1. */ + mmap_add_region_ctx(sp->xlat_ctx_handle, + &sel1_exception_vectors); + + /* + * If the SP manifest specified the register to pass the address of the + * boot information, then map the memory region to pass boot + * information. + */ + if (boot_info_reg >= 0) { + mmap_region_t ffa_boot_info_region = MAP_REGION_FLAT( + (uintptr_t) ffa_boot_info_mem, + PAGE_SIZE, + MT_RO_DATA | MT_SECURE | MT_USER); + mmap_add_region_ctx(sp->xlat_ctx_handle, &ffa_boot_info_region); + } + + /* + * Parse the manifest for any memory regions that the SP wants to be + * mapped in its translation regime. + */ + node = fdt_subnode_offset_namelen(sp_manifest, offset, + "memory-regions", + sizeof("memory-regions") - 1); + if (node < 0) { + WARN("Not found memory-region configuration for SP.\n"); + } else { + populate_sp_mem_regions(sp, sp_manifest, node); + } + + spmc_el0_sp_setup_system_registers(sp, ctx); + +} #endif /* SPMC_AT_EL3_SEL0_SP */ /* S-EL1 partition specific initialisation. */