1 /* 2 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <string.h> 9 10 #include <arch_helpers.h> 11 #include <common/bl_common.h> 12 #include <lib/el3_runtime/context_mgmt.h> 13 14 #include "tlkd_private.h" 15 16 #define AT_MASK 3 17 18 /******************************************************************************* 19 * This function helps the SP to translate NS/S virtual addresses. 20 ******************************************************************************/ 21 uint64_t tlkd_va_translate(uintptr_t va, int type) 22 { 23 uint64_t pa; 24 25 if (type & TLK_TRANSLATE_NS_VADDR) { 26 27 /* save secure context */ 28 cm_el1_sysregs_context_save(SECURE); 29 30 /* restore non-secure context */ 31 cm_el1_sysregs_context_restore(NON_SECURE); 32 33 /* switch NS bit to start using 64-bit, non-secure mappings */ 34 write_scr(cm_get_scr_el3(NON_SECURE)); 35 isb(); 36 } 37 38 int at = type & AT_MASK; 39 switch (at) { 40 case 0: 41 AT(ats12e1r, va); 42 break; 43 case 1: 44 AT(ats12e1w, va); 45 break; 46 case 2: 47 AT(ats12e0r, va); 48 break; 49 case 3: 50 AT(ats12e0w, va); 51 break; 52 default: 53 assert(0); /* Unreachable */ 54 break; 55 } 56 57 /* get the (NS/S) physical address */ 58 isb(); 59 pa = read_par_el1(); 60 61 /* Restore secure state */ 62 if (type & TLK_TRANSLATE_NS_VADDR) { 63 64 /* restore secure context */ 65 cm_el1_sysregs_context_restore(SECURE); 66 67 /* switch NS bit to start using 32-bit, secure mappings */ 68 write_scr(cm_get_scr_el3(SECURE)); 69 isb(); 70 } 71 72 return pa; 73 } 74 75 /******************************************************************************* 76 * Given a secure payload entrypoint, register width, cpu id & pointer to a 77 * context data structure, this function will create a secure context ready for 78 * programming an entry into the secure payload. 79 ******************************************************************************/ 80 void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point, 81 uint32_t rw, 82 uint64_t pc, 83 tlk_context_t *tlk_ctx) 84 { 85 uint32_t ep_attr, spsr; 86 87 /* Passing a NULL context is a critical programming error */ 88 assert(tlk_ctx); 89 assert(tlk_entry_point); 90 assert(pc); 91 92 /* Associate this context with the cpu specified */ 93 tlk_ctx->mpidr = read_mpidr_el1(); 94 clr_yield_smc_active_flag(tlk_ctx->state); 95 cm_set_context(&tlk_ctx->cpu_ctx, SECURE); 96 97 if (rw == SP_AARCH64) 98 spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); 99 else 100 spsr = SPSR_MODE32(MODE32_svc, 101 SPSR_T_ARM, 102 read_sctlr_el3() & SCTLR_EE_BIT, 103 DISABLE_ALL_EXCEPTIONS); 104 105 /* initialise an entrypoint to set up the CPU context */ 106 ep_attr = SECURE | EP_ST_ENABLE; 107 if (read_sctlr_el3() & SCTLR_EE_BIT) 108 ep_attr |= EP_EE_BIG; 109 SET_PARAM_HEAD(tlk_entry_point, PARAM_EP, VERSION_1, ep_attr); 110 111 tlk_entry_point->pc = pc; 112 tlk_entry_point->spsr = spsr; 113 } 114 115 /******************************************************************************* 116 * This function takes a TLK context pointer and: 117 * 1. Applies the S-EL1 system register context from tlk_ctx->cpu_ctx. 118 * 2. Saves the current C runtime state (callee saved registers) on the stack 119 * frame and saves a reference to this state. 120 * 3. Calls el3_exit() so that the EL3 system and general purpose registers 121 * from the tlk_ctx->cpu_ctx are used to enter the secure payload image. 122 ******************************************************************************/ 123 uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx) 124 { 125 uint64_t rc; 126 127 /* Passing a NULL context is a critical programming error */ 128 assert(tlk_ctx); 129 130 /* Apply the Secure EL1 system register context and switch to it */ 131 assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx); 132 cm_el1_sysregs_context_restore(SECURE); 133 cm_set_next_eret_context(SECURE); 134 135 rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx); 136 #if ENABLE_ASSERTIONS 137 tlk_ctx->c_rt_ctx = 0; 138 #endif 139 140 return rc; 141 } 142 143 /******************************************************************************* 144 * This function takes a TLK context pointer and: 145 * 1. Saves the S-EL1 system register context to tlk_ctx->cpu_ctx. 146 * 2. Restores the current C runtime state (callee saved registers) from the 147 * stack frame using reference to this state saved in tlkd_enter_sp(). 148 * 3. It does not need to save any general purpose or EL3 system register state 149 * as the generic smc entry routine should have saved those. 150 ******************************************************************************/ 151 void tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx, uint64_t ret) 152 { 153 /* Passing a NULL context is a critical programming error */ 154 assert(tlk_ctx); 155 156 /* Save the Secure EL1 system register context */ 157 assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx); 158 cm_el1_sysregs_context_save(SECURE); 159 160 assert(tlk_ctx->c_rt_ctx != 0); 161 tlkd_exit_sp(tlk_ctx->c_rt_ctx, ret); 162 163 /* Should never reach here */ 164 assert(0); 165 } 166