• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3  * Licensed under the Mulan PSL v2.
4  * You can use this software according to the terms and conditions of the Mulan PSL v2.
5  * You may obtain a copy of Mulan PSL v2 at:
6  *     http://license.coscl.org.cn/MulanPSL2
7  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8  * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9  * PURPOSE.
10  * See the Mulan PSL v2 for more details.
11  */
12 
13 #include "teed_common.h"
14 
15 #include <string.h>
16 #include <assert.h>
17 #include <arch_helpers.h>
18 #include <context_mgmt.h>
19 #include "teed_private.h"
20 #include "teed_helpers.h"
21 /*
22  * Given a secure payload entrypoint info pointer, entry point PC, register
23  * width, cpu id & pointer to a context data structure, this function will
24  * initialize tee context and entry point info for the secure payload
25  */
teed_init_tee_ep_state(struct entry_point_info * ep,uint32_t rw,uintptr_t pc,tee_context_t * tee_ctx)26 void teed_init_tee_ep_state(struct entry_point_info *ep,
27                       uint32_t rw,
28                       uintptr_t pc,
29                       tee_context_t *tee_ctx)
30 {
31     uint32_t ep_attr;
32     uint32_t ee;
33     uint32_t daif;
34     /* Passing a NULL context is a critical programming error */
35     assert(tee_ctx != NULL);
36     assert(ep != NULL);
37     assert(pc != INVALID_PC_ADDR);
38 
39     /*
40      * We support AArch64 TEE for now.
41      * Associate this context with the cpu specified
42      */
43     ee = (uint32_t)SPSR_E_LITTLE;
44     tee_ctx->mpidr = read_mpidr_el1();
45     tee_ctx->state = (uint32_t)TEE_PSTATE_OFF;
46     set_tee_pstate(tee_ctx->state, TEE_PSTATE_OFF);
47     clr_yield_smc_active_flag(tee_ctx->state);
48 
49     cm_set_context(&tee_ctx->cpu_context, SECURE);
50 
51     /* initialise an entrypoint to set up the CPU context */
52     ep_attr = SECURE | EP_ST_ENABLE;
53     bool ee_bit_flag = (read_sctlr_el3() & SCTLR_EE_BIT) == 0 ? false : true;
54     if (ee_bit_flag) {
55         ep_attr |= EP_EE_BIG;
56         ee = SPSR_E_BIG;
57     }
58     SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
59     ep->pc = pc;
60     if (rw == TEE_AARCH64) {
61         ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
62     } else {
63         daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
64         ep->spsr = SPSR_MODE32(MODE32_svc, pc & SPSR_T_MASK, ee, daif);
65     }
66 
67     memset(&ep->args, 0, sizeof(ep->args));
68 }
69 
70 /*
71  * This function takes an SP context pointer and:
72  * 1. Applies the S-EL1 system register context from tee_ctx->cpu_context.
73  * 2. Saves the current C runtime state (callee saved registers) on the stack
74  *    frame and saves a reference to this state.
75  * 3. Calls el3_exit() so that the EL3 system and general purpose registers
76  *    from the tee_ctx->cpu_context are used to enter the secure payload image.
77  */
teed_synchronous_sp_entry(tee_context_t * tee_ctx)78 uint64_t teed_synchronous_sp_entry(tee_context_t *tee_ctx)
79 {
80     uint64_t rc;
81     assert(tee_ctx != NULL);
82     assert(tee_ctx->rt_context == INVALID_C_RT_CTX);
83 
84     /* Apply the Secure EL1 system register context and switch to it */
85     assert(cm_get_context(SECURE) == &tee_ctx->cpu_context);
86 
87     cm_el1_sysregs_context_restore(SECURE);
88     cm_set_next_eret_context(SECURE);
89     rc = teed_enter_sp(&tee_ctx->rt_context);
90 #if ENABLE_ASSERTIONS
91     tee_ctx->rt_context = INVALID_C_RT_CTX;
92 #endif
93 
94     return rc;
95 }
96 
97 /*
98  * This function takes an SP context pointer and:
99  * 1. Saves the S-EL1 system register context tp tee_ctx->cpu_context.
100  * 2. Restores the current C runtime state (callee saved registers) from the
101  *    stack frame using the reference to this state saved in teed_enter_sp().
102  * 3. It does not need to save any general purpose or EL3 system register state
103  *    as the generic smc entry routine should have saved those.
104  */
teed_synchronous_sp_exit(const tee_context_t * tee_ctx,uint64_t ret)105 void teed_synchronous_sp_exit(const tee_context_t *tee_ctx, uint64_t ret)
106 {
107     assert(tee_ctx != NULL);
108     /* Save the Secure EL1 system register context */
109     assert(cm_get_context(SECURE) == &tee_ctx->cpu_context);
110     cm_el1_sysregs_context_save(SECURE);
111     int64_t init_context_saved = get_tee_init_context_saved();
112 
113     tee_context_t *tee_context_tmp = get_teed_sp_init_context();
114     assert(tee_context_tmp != NULL);
115     if (init_context_saved == INIT_CONTEXT_NOT_SAVED) {
116         memcpy(tee_context_tmp, tee_ctx, sizeof(*tee_context_tmp));
117         set_tee_init_context_saved(INIT_CONTEXT_SAVED);
118     }
119     assert(tee_ctx->rt_context != INVALID_C_RT_CTX);
120     teed_exit_sp(tee_ctx->rt_context, ret);
121     printf("sp exit: Should never reach here\n");
122     assert(0);
123 }
124