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