Home | History | Annotate | Download | only in tspd
      1 /*
      2  * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <assert.h>
      9 #include <bl_common.h>
     10 #include <context_mgmt.h>
     11 #include <debug.h>
     12 #include <string.h>
     13 #include <tsp.h>
     14 #include <utils.h>
     15 #include "tspd_private.h"
     16 
     17 /*******************************************************************************
     18  * Given a secure payload entrypoint info pointer, entry point PC, register
     19  * width, cpu id & pointer to a context data structure, this function will
     20  * initialize tsp context and entry point info for the secure payload
     21  ******************************************************************************/
     22 void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point,
     23 				uint32_t rw,
     24 				uint64_t pc,
     25 				tsp_context_t *tsp_ctx)
     26 {
     27 	uint32_t ep_attr;
     28 
     29 	/* Passing a NULL context is a critical programming error */
     30 	assert(tsp_ctx);
     31 	assert(tsp_entry_point);
     32 	assert(pc);
     33 
     34 	/*
     35 	 * We support AArch64 TSP for now.
     36 	 * TODO: Add support for AArch32 TSP
     37 	 */
     38 	assert(rw == TSP_AARCH64);
     39 
     40 	/* Associate this context with the cpu specified */
     41 	tsp_ctx->mpidr = read_mpidr_el1();
     42 	tsp_ctx->state = 0;
     43 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
     44 	clr_yield_smc_active_flag(tsp_ctx->state);
     45 
     46 	cm_set_context(&tsp_ctx->cpu_ctx, SECURE);
     47 
     48 	/* initialise an entrypoint to set up the CPU context */
     49 	ep_attr = SECURE | EP_ST_ENABLE;
     50 	if (read_sctlr_el3() & SCTLR_EE_BIT)
     51 		ep_attr |= EP_EE_BIG;
     52 	SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr);
     53 
     54 	tsp_entry_point->pc = pc;
     55 	tsp_entry_point->spsr = SPSR_64(MODE_EL1,
     56 					MODE_SP_ELX,
     57 					DISABLE_ALL_EXCEPTIONS);
     58 	zeromem(&tsp_entry_point->args, sizeof(tsp_entry_point->args));
     59 }
     60 
     61 /*******************************************************************************
     62  * This function takes an SP context pointer and:
     63  * 1. Applies the S-EL1 system register context from tsp_ctx->cpu_ctx.
     64  * 2. Saves the current C runtime state (callee saved registers) on the stack
     65  *    frame and saves a reference to this state.
     66  * 3. Calls el3_exit() so that the EL3 system and general purpose registers
     67  *    from the tsp_ctx->cpu_ctx are used to enter the secure payload image.
     68  ******************************************************************************/
     69 uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx)
     70 {
     71 	uint64_t rc;
     72 
     73 	assert(tsp_ctx != NULL);
     74 	assert(tsp_ctx->c_rt_ctx == 0);
     75 
     76 	/* Apply the Secure EL1 system register context and switch to it */
     77 	assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
     78 	cm_el1_sysregs_context_restore(SECURE);
     79 	cm_set_next_eret_context(SECURE);
     80 
     81 	rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx);
     82 #if DEBUG
     83 	tsp_ctx->c_rt_ctx = 0;
     84 #endif
     85 
     86 	return rc;
     87 }
     88 
     89 
     90 /*******************************************************************************
     91  * This function takes an SP context pointer and:
     92  * 1. Saves the S-EL1 system register context tp tsp_ctx->cpu_ctx.
     93  * 2. Restores the current C runtime state (callee saved registers) from the
     94  *    stack frame using the reference to this state saved in tspd_enter_sp().
     95  * 3. It does not need to save any general purpose or EL3 system register state
     96  *    as the generic smc entry routine should have saved those.
     97  ******************************************************************************/
     98 void tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret)
     99 {
    100 	assert(tsp_ctx != NULL);
    101 	/* Save the Secure EL1 system register context */
    102 	assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
    103 	cm_el1_sysregs_context_save(SECURE);
    104 
    105 	assert(tsp_ctx->c_rt_ctx != 0);
    106 	tspd_exit_sp(tsp_ctx->c_rt_ctx, ret);
    107 
    108 	/* Should never reach here */
    109 	assert(0);
    110 }
    111 
    112 /*******************************************************************************
    113  * This function takes an SP context pointer and abort any preempted SMC
    114  * request.
    115  * Return 1 if there was a preempted SMC request, 0 otherwise.
    116  ******************************************************************************/
    117 int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx)
    118 {
    119 	if (!get_yield_smc_active_flag(tsp_ctx->state))
    120 		return 0;
    121 
    122 	/* Abort any preempted SMC request */
    123 	clr_yield_smc_active_flag(tsp_ctx->state);
    124 
    125 	/*
    126 	 * Arrange for an entry into the test secure payload. It will
    127 	 * be returned via TSP_ABORT_DONE case in tspd_smc_handler.
    128 	 */
    129 	cm_set_elr_el3(SECURE,
    130 		       (uint64_t) &tsp_vectors->abort_yield_smc_entry);
    131 	uint64_t rc = tspd_synchronous_sp_entry(tsp_ctx);
    132 
    133 	if (rc != 0)
    134 		panic();
    135 
    136 	return 1;
    137 }
    138 
    139