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. */