1 /* 2 * Copyright (c) 2015, Linaro Limited 3 * All rights reserved. 4 * Copyright (c) 2014, STMicroelectronics International N.V. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <tee/entry_fast.h> 31 #include <optee_msg.h> 32 #include <sm/optee_smc.h> 33 #include <kernel/generic_boot.h> 34 #include <kernel/tee_l2cc_mutex.h> 35 #include <kernel/misc.h> 36 #include <mm/core_mmu.h> 37 38 static void tee_entry_get_shm_config(struct thread_smc_args *args) 39 { 40 args->a0 = OPTEE_SMC_RETURN_OK; 41 args->a1 = default_nsec_shm_paddr; 42 args->a2 = default_nsec_shm_size; 43 /* Should this be TEESMC cache attributes instead? */ 44 args->a3 = core_mmu_is_shm_cached(); 45 } 46 47 static void tee_entry_fastcall_l2cc_mutex(struct thread_smc_args *args) 48 { 49 TEE_Result ret; 50 #ifdef ARM32 51 paddr_t pa = 0; 52 53 switch (args->a1) { 54 case OPTEE_SMC_L2CC_MUTEX_GET_ADDR: 55 ret = tee_get_l2cc_mutex(&pa); 56 reg_pair_from_64(pa, &args->a2, &args->a3); 57 break; 58 case OPTEE_SMC_L2CC_MUTEX_SET_ADDR: 59 pa = reg_pair_to_64(args->a2, args->a3); 60 ret = tee_set_l2cc_mutex(&pa); 61 break; 62 case OPTEE_SMC_L2CC_MUTEX_ENABLE: 63 ret = tee_enable_l2cc_mutex(); 64 break; 65 case OPTEE_SMC_L2CC_MUTEX_DISABLE: 66 ret = tee_disable_l2cc_mutex(); 67 break; 68 default: 69 args->a0 = OPTEE_SMC_RETURN_EBADCMD; 70 return; 71 } 72 #else 73 ret = TEE_ERROR_NOT_SUPPORTED; 74 #endif 75 if (ret == TEE_ERROR_NOT_SUPPORTED) 76 args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION; 77 else if (ret) 78 args->a0 = OPTEE_SMC_RETURN_EBADADDR; 79 else 80 args->a0 = OPTEE_SMC_RETURN_OK; 81 } 82 83 static void tee_entry_exchange_capabilities(struct thread_smc_args *args) 84 { 85 bool dyn_shm_en = false; 86 87 /* 88 * Currently we ignore OPTEE_SMC_NSEC_CAP_UNIPROCESSOR. 89 * 90 * The memory mapping of shared memory is defined as normal 91 * shared memory for SMP systems and normal memory for UP 92 * systems. Currently we map all memory as shared in secure 93 * world. 94 * 95 * When translation tables are created with shared bit cleared for 96 * uniprocessor systems we'll need to check 97 * OPTEE_SMC_NSEC_CAP_UNIPROCESSOR. 98 */ 99 100 if (args->a1 & ~OPTEE_SMC_NSEC_CAP_UNIPROCESSOR) { 101 /* Unknown capability. */ 102 args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL; 103 return; 104 } 105 106 args->a0 = OPTEE_SMC_RETURN_OK; 107 args->a1 = OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM; 108 109 #if defined(CFG_DYN_SHM_CAP) 110 dyn_shm_en = core_mmu_nsec_ddr_is_defined(); 111 if (dyn_shm_en) 112 args->a1 |= OPTEE_SMC_SEC_CAP_DYNAMIC_SHM; 113 #endif 114 115 IMSG("Dynamic shared memory is %sabled", dyn_shm_en ? "en" : "dis"); 116 } 117 118 static void tee_entry_disable_shm_cache(struct thread_smc_args *args) 119 { 120 uint64_t cookie; 121 122 if (!thread_disable_prealloc_rpc_cache(&cookie)) { 123 args->a0 = OPTEE_SMC_RETURN_EBUSY; 124 return; 125 } 126 127 if (!cookie) { 128 args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL; 129 return; 130 } 131 132 args->a0 = OPTEE_SMC_RETURN_OK; 133 args->a1 = cookie >> 32; 134 args->a2 = cookie; 135 } 136 137 static void tee_entry_enable_shm_cache(struct thread_smc_args *args) 138 { 139 if (thread_enable_prealloc_rpc_cache()) 140 args->a0 = OPTEE_SMC_RETURN_OK; 141 else 142 args->a0 = OPTEE_SMC_RETURN_EBUSY; 143 } 144 145 static void tee_entry_boot_secondary(struct thread_smc_args *args) 146 { 147 #if defined(CFG_BOOT_SECONDARY_REQUEST) 148 if (!generic_boot_core_release(args->a1, (paddr_t)(args->a3))) 149 args->a0 = OPTEE_SMC_RETURN_OK; 150 else 151 args->a0 = OPTEE_SMC_RETURN_EBADCMD; 152 #else 153 args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL; 154 #endif 155 } 156 157 void tee_entry_fast(struct thread_smc_args *args) 158 { 159 switch (args->a0) { 160 161 /* Generic functions */ 162 case OPTEE_SMC_CALLS_COUNT: 163 tee_entry_get_api_call_count(args); 164 break; 165 case OPTEE_SMC_CALLS_UID: 166 tee_entry_get_api_uuid(args); 167 break; 168 case OPTEE_SMC_CALLS_REVISION: 169 tee_entry_get_api_revision(args); 170 break; 171 case OPTEE_SMC_CALL_GET_OS_UUID: 172 tee_entry_get_os_uuid(args); 173 break; 174 case OPTEE_SMC_CALL_GET_OS_REVISION: 175 tee_entry_get_os_revision(args); 176 break; 177 178 /* OP-TEE specific SMC functions */ 179 case OPTEE_SMC_GET_SHM_CONFIG: 180 tee_entry_get_shm_config(args); 181 break; 182 case OPTEE_SMC_L2CC_MUTEX: 183 tee_entry_fastcall_l2cc_mutex(args); 184 break; 185 case OPTEE_SMC_EXCHANGE_CAPABILITIES: 186 tee_entry_exchange_capabilities(args); 187 break; 188 case OPTEE_SMC_DISABLE_SHM_CACHE: 189 tee_entry_disable_shm_cache(args); 190 break; 191 case OPTEE_SMC_ENABLE_SHM_CACHE: 192 tee_entry_enable_shm_cache(args); 193 break; 194 case OPTEE_SMC_BOOT_SECONDARY: 195 tee_entry_boot_secondary(args); 196 break; 197 198 default: 199 args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION; 200 break; 201 } 202 } 203 204 size_t tee_entry_generic_get_api_call_count(void) 205 { 206 /* 207 * All the different calls handled in this file. If the specific 208 * target has additional calls it will call this function and 209 * add the number of calls the target has added. 210 */ 211 return 9; 212 } 213 214 void __weak tee_entry_get_api_call_count(struct thread_smc_args *args) 215 { 216 args->a0 = tee_entry_generic_get_api_call_count(); 217 } 218 219 void __weak tee_entry_get_api_uuid(struct thread_smc_args *args) 220 { 221 args->a0 = OPTEE_MSG_UID_0; 222 args->a1 = OPTEE_MSG_UID_1; 223 args->a2 = OPTEE_MSG_UID_2; 224 args->a3 = OPTEE_MSG_UID_3; 225 } 226 227 void __weak tee_entry_get_api_revision(struct thread_smc_args *args) 228 { 229 args->a0 = OPTEE_MSG_REVISION_MAJOR; 230 args->a1 = OPTEE_MSG_REVISION_MINOR; 231 } 232 233 void __weak tee_entry_get_os_uuid(struct thread_smc_args *args) 234 { 235 args->a0 = OPTEE_MSG_OS_OPTEE_UUID_0; 236 args->a1 = OPTEE_MSG_OS_OPTEE_UUID_1; 237 args->a2 = OPTEE_MSG_OS_OPTEE_UUID_2; 238 args->a3 = OPTEE_MSG_OS_OPTEE_UUID_3; 239 } 240 241 void __weak tee_entry_get_os_revision(struct thread_smc_args *args) 242 { 243 args->a0 = CFG_OPTEE_REVISION_MAJOR; 244 args->a1 = CFG_OPTEE_REVISION_MINOR; 245 } 246