/******************************************************************************* * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits * before passing control back to the Secure Monitor. Entry in S-El1 is done * after initialising minimal architectural state that guarantees safe * execution. ******************************************************************************/ static void opteed_cpu_on_finish_handler(uint64_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; entry_point_info_t optee_on_entrypoint; assert(optee_vectors); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF); opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, (uint64_t)&optee_vectors->cpu_on_entry, 0, 0, 0, optee_ctx); /* Initialise this cpu's secure context */ cm_init_my_context(&optee_on_entrypoint); /* Enter OPTEE */ rc = opteed_synchronous_sp_entry(optee_ctx); /* * Read the response from OPTEE. A non-zero return means that * something went wrong while communicating with OPTEE. */ if (rc != 0) panic(); /* Update its context to reflect the state OPTEE is in */ set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); }
/******************************************************************************* * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type * (aarch32/aarch64) if not already known and initialises the context for entry * into OPTEE for its initialization. ******************************************************************************/ int32_t opteed_setup(void) { entry_point_info_t *optee_ep_info; uint64_t mpidr = read_mpidr(); uint32_t linear_id; linear_id = platform_get_core_pos(mpidr); /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. TODO: Add support to * conditionally include the SPD service */ optee_ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (!optee_ep_info) { WARN("No OPTEE provided by BL2 boot loader, Booting device" " without OPTEE initialization. SMC`s destined for OPTEE" " will return SMC_UNK\n"); return 1; } /* * If there's no valid entry point for SP, we return a non-zero value * signalling failure initializing the service. We bail out without * registering any handlers */ if (!optee_ep_info->pc) return 1; /* * We could inspect the SP image and determine it's execution * state i.e whether AArch32 or AArch64. Assuming it's AArch32 * for the time being. */ opteed_rw = OPTEE_AARCH32; opteed_init_optee_ep_state(optee_ep_info, opteed_rw, optee_ep_info->pc, &opteed_sp_context[linear_id]); /* * All OPTEED initialization done. Now register our init function with * BL31 for deferred invocation */ bl31_register_bl32_init(&opteed_init); return 0; }
/******************************************************************************* * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type * (aarch32/aarch64) if not already known and initialises the context for entry * into OPTEE for its initialization. ******************************************************************************/ int32_t opteed_setup(void) { entry_point_info_t *ep_info; struct optee_header *header; uint64_t mpidr = read_mpidr(); uint32_t linear_id; uintptr_t init_load_addr; size_t init_size; size_t init_mem_usage; uintptr_t payload_addr; uintptr_t mem_limit; uintptr_t paged_part; uintptr_t paged_size; linear_id = platform_get_core_pos(mpidr); /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. TODO: Add support to * conditionally include the SPD service */ ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (!ep_info) { WARN("No OPTEE provided by BL2 boot loader.\n"); goto err; } header = (struct optee_header *)ep_info->pc; if (header->magic != OPTEE_MAGIC || header->version != OPTEE_VERSION) { WARN("Invalid OPTEE header.\n"); goto err; } if (header->arch == OPTEE_ARCH_ARM32) opteed_rw = OPTEE_AARCH32; else if (header->arch == OPTEE_ARCH_ARM64) opteed_rw = OPTEE_AARCH64; else { WARN("Invalid OPTEE architecture (%d)\n", header->arch); goto err; } init_load_addr = ((uint64_t)header->init_load_addr_hi << 32) | header->init_load_addr_lo; init_size = header->init_size; init_mem_usage = header->init_mem_usage; payload_addr = (uintptr_t)(header + 1); paged_size = header->paged_size; /* * Move OPTEE binary to the required location in memory. * * There's two ways OPTEE can be running in memory: * 1. A memory large enough to keep the entire OPTEE binary * (DRAM currently) * 2. A part of OPTEE in a smaller (and more secure) memory * (SRAM currently). This is achieved with demand paging * of read-only data/code against a backing store in some * larger memory (DRAM currently). * * In either case dictates init_load_addr in the OPTEE * header the address where what's after the header * (payload) should be residing when started. init_size in * the header tells how much of the payload that need to be * copied. init_mem_usage tells how much runtime memory in * total is needed by OPTEE. * * In alternative 2 there's additional data after * init_size, this is the rest of OPTEE which is demand * paged into memory. A pointer to that data is supplied * to OPTEE when initializing. * * Alternative 1 only uses DRAM when executing OPTEE while * alternative 2 uses both SRAM and DRAM to execute. * * All data written which is later read by OPTEE must be flushed * out to memory since OPTEE starts with MMU turned off and caches * disabled. */ if (is_mem_free(BL32_SRAM_BASE, BL32_SRAM_LIMIT - BL32_SRAM_BASE, init_load_addr, init_mem_usage)) { /* Running in SRAM, paging some code against DRAM */ memcpy((void *)init_load_addr, (void *)payload_addr, init_size); flush_dcache_range(init_load_addr, init_size); paged_part = payload_addr + init_size; mem_limit = BL32_SRAM_LIMIT; } else if (is_mem_free(BL32_DRAM_BASE, BL32_DRAM_LIMIT - BL32_DRAM_BASE, init_load_addr, init_mem_usage)) { /* * Running in DRAM. * * The paged part normally empty, but if it isn't, * move it to the end of DRAM before moving the * init part in place. */ paged_part = BL32_DRAM_LIMIT - paged_size; if (paged_size) { if (!is_mem_free(BL32_DRAM_BASE, BL32_DRAM_LIMIT - BL32_DRAM_BASE, init_load_addr, init_mem_usage + paged_size)) { WARN("Failed to reserve memory 0x%lx - 0x%lx\n", init_load_addr, init_load_addr + init_mem_usage + paged_size); goto err; } memcpy((void *)paged_part, (void *)(payload_addr + init_size), paged_size); flush_dcache_range(paged_part, paged_size); } memmove((void *)init_load_addr, (void *)payload_addr, init_size); flush_dcache_range(init_load_addr, init_size); mem_limit = BL32_DRAM_LIMIT; } else { WARN("Failed to reserve memory 0x%lx - 0x%lx\n", init_load_addr, init_load_addr + init_mem_usage); goto err; } opteed_init_optee_ep_state(ep_info, opteed_rw, init_load_addr, paged_part, mem_limit, &opteed_sp_context[linear_id]); /* * All OPTEED initialization done. Now register our init function with * BL31 for deferred invocation */ bl31_register_bl32_init(&opteed_init); return 0; err: WARN("Booting device without OPTEE initialization.\n"); WARN("SMC`s destined for OPTEE will return SMC_UNK\n"); return 1; }