/* * Copyright (C) 2022 Huawei Technologies Co., Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include "smc_call.h" #include "smc_smp.h" #include "teek_ns_client.h" #include "smc_abi.h" #ifndef CONFIG_ARCH32 void do_smc_transport(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) { isb(); wmb(); do { asm volatile( "mov x0, %[fid]\n" "mov x1, %[a1]\n" "mov x2, %[a2]\n" "mov x3, %[a3]\n" "mov x4, %[a4]\n" "mov x5, %[a5]\n" "mov x6, %[a6]\n" "mov x7, %[a7]\n" SMCCC_SMC_INST"\n" "str x0, [%[re0]]\n" "str x1, [%[re1]]\n" "str x2, [%[re2]]\n" "str x3, [%[re3]]\n" : [fid] "+r"(in->x0), [a1] "+r"(in->x1), [a2] "+r"(in->x2), [a3] "+r"(in->x3), [a4] "+r"(in->x4), [a5] "+r"(in->x5), [a6] "+r"(in->x6), [a7] "+r"(in->x7): [re0] "r"(&out->ret), [re1] "r"(&out->exit_reason), [re2] "r"(&out->ta), [re3] "r"(&out->target) : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"); } while (out->ret == TSP_REQUEST && wait != 0); isb(); wmb(); } #else void do_smc_transport(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) { isb(); wmb(); do { asm volatile( "mov r0, %[fid]\n" "mov r1, %[a1]\n" "mov r2, %[a2]\n" "mov r3, %[a3]\n" ".arch_extension sec\n" SMCCC_SMC_INST"\n" "str r0, [%[re0]]\n" "str r1, [%[re1]]\n" "str r2, [%[re2]]\n" "str r3, [%[re3]]\n" : [fid] "+r"(in->x0), [a1] "+r"(in->x1), [a2] "+r"(in->x2), [a3] "+r"(in->x3): [re0] "r"(&out->ret), [re1] "r"(&out->exit_reason), [re2] "r"(&out->ta), [re3] "r"(&out->target) : "r0", "r1", "r2", "r3"); } while (out->ret == TSP_REQUEST && wait != 0); isb(); wmb(); } #endif #ifdef CONFIG_THIRDPARTY_COMPATIBLE static void fix_params_offset(struct smc_out_params *out_param) { out_param->target = out_param->ta; out_param->ta = out_param->exit_reason; out_param->exit_reason = out_param->ret; out_param->ret = TSP_RESPONSE; if (out_param->exit_reason == TEE_EXIT_REASON_CRASH) { union crash_inf temp_info; temp_info.crash_reg[0] = out_param->ta; temp_info.crash_reg[1] = 0; temp_info.crash_reg[2] = out_param->target; temp_info.crash_msg.far = temp_info.crash_msg.elr; temp_info.crash_msg.elr = 0; out_param->ret = TSP_CRASH; out_param->exit_reason = temp_info.crash_reg[0]; out_param->ta = temp_info.crash_reg[1]; out_param->target = temp_info.crash_reg[2]; } } #endif void smc_req(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) { do_smc_transport(in, out, wait); #ifdef CONFIG_THIRDPARTY_COMPATIBLE fix_params_offset(out); #endif }