1419b0af8Sopenharmony_ci/* 2419b0af8Sopenharmony_ci * Copyright (C) 2022 Huawei Technologies Co., Ltd. 3419b0af8Sopenharmony_ci * Decription: agent manager function, such as register and send cmd 4419b0af8Sopenharmony_ci * 5419b0af8Sopenharmony_ci * This software is licensed under the terms of the GNU General Public 6419b0af8Sopenharmony_ci * License version 2, as published by the Free Software Foundation, and 7419b0af8Sopenharmony_ci * may be copied, distributed, and modified under those terms. 8419b0af8Sopenharmony_ci * 9419b0af8Sopenharmony_ci * This program is distributed in the hope that it will be useful, 10419b0af8Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11419b0af8Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12419b0af8Sopenharmony_ci * GNU General Public License for more details. 13419b0af8Sopenharmony_ci */ 14419b0af8Sopenharmony_ci#include "agent.h" 15419b0af8Sopenharmony_ci#include <linux/sched.h> 16419b0af8Sopenharmony_ci#include <linux/list.h> 17419b0af8Sopenharmony_ci#include <linux/mutex.h> 18419b0af8Sopenharmony_ci#include <linux/kthread.h> 19419b0af8Sopenharmony_ci#include <linux/freezer.h> 20419b0af8Sopenharmony_ci#include <linux/module.h> 21419b0af8Sopenharmony_ci#include <linux/version.h> 22419b0af8Sopenharmony_ci#include <linux/atomic.h> 23419b0af8Sopenharmony_ci#include <linux/fs.h> 24419b0af8Sopenharmony_ci#include <linux/file.h> 25419b0af8Sopenharmony_ci#include <linux/path.h> 26419b0af8Sopenharmony_ci#include <linux/uaccess.h> 27419b0af8Sopenharmony_ci#include <linux/mm.h> 28419b0af8Sopenharmony_ci#include <linux/mm_types.h> 29419b0af8Sopenharmony_ci#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE) 30419b0af8Sopenharmony_ci#include <linux/sched/mm.h> 31419b0af8Sopenharmony_ci#include <linux/sched/task.h> 32419b0af8Sopenharmony_ci#endif 33419b0af8Sopenharmony_ci#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE) 34419b0af8Sopenharmony_ci#include <linux/mman.h> 35419b0af8Sopenharmony_ci#else 36419b0af8Sopenharmony_ci#include <asm/mman.h> 37419b0af8Sopenharmony_ci#endif 38419b0af8Sopenharmony_ci#include <linux/signal.h> 39419b0af8Sopenharmony_ci#include <securec.h> 40419b0af8Sopenharmony_ci#ifdef CONFIG_MM_VLTMM 41419b0af8Sopenharmony_ci#include <linux/ion/mm_ion.h> 42419b0af8Sopenharmony_ci#endif 43419b0af8Sopenharmony_ci#ifdef CONFIG_MEMORY_VLTMM 44419b0af8Sopenharmony_ci#include <linux/dmabuf/mm_dma_heap.h> 45419b0af8Sopenharmony_ci#endif 46419b0af8Sopenharmony_ci#include "teek_client_constants.h" 47419b0af8Sopenharmony_ci#include "teek_ns_client.h" 48419b0af8Sopenharmony_ci#include "smc_smp.h" 49419b0af8Sopenharmony_ci#include "mem.h" 50419b0af8Sopenharmony_ci#include "tui.h" 51419b0af8Sopenharmony_ci#include "tc_ns_log.h" 52419b0af8Sopenharmony_ci#include "mailbox_mempool.h" 53419b0af8Sopenharmony_ci#include "tc_client_driver.h" 54419b0af8Sopenharmony_ci#include "cmdmonitor.h" 55419b0af8Sopenharmony_ci#include "agent_rpmb.h" 56419b0af8Sopenharmony_ci#include "ko_adapt.h" 57419b0af8Sopenharmony_ci#include "internal_functions.h" 58419b0af8Sopenharmony_ci#include "auth_base_impl.h" 59419b0af8Sopenharmony_ci 60419b0af8Sopenharmony_ci#ifdef CONFIG_CMS_CAHASH_AUTH 61419b0af8Sopenharmony_ci#define HASH_FILE_MAX_SIZE CONFIG_HASH_FILE_SIZE 62419b0af8Sopenharmony_ci#else 63419b0af8Sopenharmony_ci#define HASH_FILE_MAX_SIZE (16 * 1024) 64419b0af8Sopenharmony_ci#endif 65419b0af8Sopenharmony_ci#define AGENT_BUFF_SIZE (4 * 1024) 66419b0af8Sopenharmony_ci#define AGENT_MAX 32 67419b0af8Sopenharmony_ci#define PAGE_ORDER_RATIO 2 68419b0af8Sopenharmony_ci 69419b0af8Sopenharmony_cistatic struct list_head g_tee_agent_list; 70419b0af8Sopenharmony_ci 71419b0af8Sopenharmony_cistruct agent_control { 72419b0af8Sopenharmony_ci spinlock_t lock; 73419b0af8Sopenharmony_ci struct list_head agent_list; 74419b0af8Sopenharmony_ci}; 75419b0af8Sopenharmony_ci 76419b0af8Sopenharmony_cistatic struct agent_control g_agent_control; 77419b0af8Sopenharmony_ci 78419b0af8Sopenharmony_ciint __attribute__((weak)) is_allowed_agent_ca(const struct ca_info *ca, 79419b0af8Sopenharmony_ci bool check_agent_id) 80419b0af8Sopenharmony_ci{ 81419b0af8Sopenharmony_ci (void)ca; 82419b0af8Sopenharmony_ci (void)check_agent_id; 83419b0af8Sopenharmony_ci 84419b0af8Sopenharmony_ci return -EFAULT; 85419b0af8Sopenharmony_ci} 86419b0af8Sopenharmony_ci 87419b0af8Sopenharmony_cistatic int check_mm_struct(struct mm_struct *mm) 88419b0af8Sopenharmony_ci{ 89419b0af8Sopenharmony_ci if (!mm) 90419b0af8Sopenharmony_ci return -EINVAL; 91419b0af8Sopenharmony_ci 92419b0af8Sopenharmony_ci if (!mm->exe_file) { 93419b0af8Sopenharmony_ci mmput(mm); 94419b0af8Sopenharmony_ci return -EINVAL; 95419b0af8Sopenharmony_ci } 96419b0af8Sopenharmony_ci 97419b0af8Sopenharmony_ci return 0; 98419b0af8Sopenharmony_ci} 99419b0af8Sopenharmony_ci 100419b0af8Sopenharmony_ci#ifdef CONFIG_LIBLINUX 101419b0af8Sopenharmony_cichar *get_proc_dpath(char *path, int path_len) 102419b0af8Sopenharmony_ci{ 103419b0af8Sopenharmony_ci int rc; 104419b0af8Sopenharmony_ci char cmdstring[MAX_PATH_SIZE] = { 0 }; 105419b0af8Sopenharmony_ci 106419b0af8Sopenharmony_ci if (!path || path_len != MAX_PATH_SIZE) { 107419b0af8Sopenharmony_ci tloge("bad params\n"); 108419b0af8Sopenharmony_ci return NULL; 109419b0af8Sopenharmony_ci } 110419b0af8Sopenharmony_ci 111419b0af8Sopenharmony_ci if (memset_s(path, path_len, '\0', MAX_PATH_SIZE) != 0) { 112419b0af8Sopenharmony_ci tloge("memset error\n"); 113419b0af8Sopenharmony_ci return NULL; 114419b0af8Sopenharmony_ci } 115419b0af8Sopenharmony_ci 116419b0af8Sopenharmony_ci rc = sprintf_s(cmdstring, MAX_PATH_SIZE, "/proc/%d/exe", current->tgid); 117419b0af8Sopenharmony_ci if (rc < 0) { 118419b0af8Sopenharmony_ci tloge("set path in get proc dpath failed\n"); 119419b0af8Sopenharmony_ci return NULL; 120419b0af8Sopenharmony_ci } 121419b0af8Sopenharmony_ci 122419b0af8Sopenharmony_ci if (liblinux_pal_vfs_readlink(cmdstring, path, MAX_PATH_SIZE) == 0) { 123419b0af8Sopenharmony_ci tloge("get CA realpath in get proc dpath failed\n"); 124419b0af8Sopenharmony_ci return NULL; 125419b0af8Sopenharmony_ci } 126419b0af8Sopenharmony_ci 127419b0af8Sopenharmony_ci return path; 128419b0af8Sopenharmony_ci} 129419b0af8Sopenharmony_ci#else 130419b0af8Sopenharmony_cichar *get_proc_dpath(char *path, int path_len) 131419b0af8Sopenharmony_ci{ 132419b0af8Sopenharmony_ci char *dpath = NULL; 133419b0af8Sopenharmony_ci struct path base_path = { 134419b0af8Sopenharmony_ci .mnt = NULL, 135419b0af8Sopenharmony_ci .dentry = NULL 136419b0af8Sopenharmony_ci }; 137419b0af8Sopenharmony_ci struct mm_struct *mm = NULL; 138419b0af8Sopenharmony_ci struct file *exe_file = NULL; 139419b0af8Sopenharmony_ci 140419b0af8Sopenharmony_ci if (!path || path_len != MAX_PATH_SIZE) { 141419b0af8Sopenharmony_ci tloge("bad params\n"); 142419b0af8Sopenharmony_ci return NULL; 143419b0af8Sopenharmony_ci } 144419b0af8Sopenharmony_ci 145419b0af8Sopenharmony_ci if (memset_s(path, path_len, '\0', MAX_PATH_SIZE) != 0) { 146419b0af8Sopenharmony_ci tloge("memset error\n"); 147419b0af8Sopenharmony_ci return NULL; 148419b0af8Sopenharmony_ci } 149419b0af8Sopenharmony_ci 150419b0af8Sopenharmony_ci mm = get_task_mm(current); 151419b0af8Sopenharmony_ci if (check_mm_struct(mm) != 0) { 152419b0af8Sopenharmony_ci tloge("check mm_struct failed\n"); 153419b0af8Sopenharmony_ci return NULL; 154419b0af8Sopenharmony_ci } 155419b0af8Sopenharmony_ci#if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE) 156419b0af8Sopenharmony_ci exe_file = mm->exe_file; 157419b0af8Sopenharmony_ci#else 158419b0af8Sopenharmony_ci exe_file = get_mm_exe_file(mm); 159419b0af8Sopenharmony_ci#endif 160419b0af8Sopenharmony_ci if (!exe_file) { 161419b0af8Sopenharmony_ci mmput(mm); 162419b0af8Sopenharmony_ci return NULL; 163419b0af8Sopenharmony_ci } 164419b0af8Sopenharmony_ci 165419b0af8Sopenharmony_ci base_path = exe_file->f_path; 166419b0af8Sopenharmony_ci path_get(&base_path); 167419b0af8Sopenharmony_ci dpath = d_path(&base_path, path, MAX_PATH_SIZE); 168419b0af8Sopenharmony_ci path_put(&base_path); 169419b0af8Sopenharmony_ci#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) 170419b0af8Sopenharmony_ci fput(exe_file); 171419b0af8Sopenharmony_ci#endif 172419b0af8Sopenharmony_ci mmput(mm); 173419b0af8Sopenharmony_ci 174419b0af8Sopenharmony_ci return dpath; 175419b0af8Sopenharmony_ci} 176419b0af8Sopenharmony_ci#endif 177419b0af8Sopenharmony_ci 178419b0af8Sopenharmony_cistatic int get_ca_path_and_uid(struct ca_info *ca) 179419b0af8Sopenharmony_ci{ 180419b0af8Sopenharmony_ci char *path = NULL; 181419b0af8Sopenharmony_ci const struct cred *cred = NULL; 182419b0af8Sopenharmony_ci int message_size; 183419b0af8Sopenharmony_ci char *tpath = NULL; 184419b0af8Sopenharmony_ci 185419b0af8Sopenharmony_ci tpath = kmalloc(MAX_PATH_SIZE, GFP_KERNEL); 186419b0af8Sopenharmony_ci if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)tpath)) { 187419b0af8Sopenharmony_ci tloge("tpath kmalloc fail\n"); 188419b0af8Sopenharmony_ci return -ENOMEM; 189419b0af8Sopenharmony_ci } 190419b0af8Sopenharmony_ci 191419b0af8Sopenharmony_ci path = get_proc_dpath(tpath, MAX_PATH_SIZE); 192419b0af8Sopenharmony_ci if (IS_ERR_OR_NULL(path)) { 193419b0af8Sopenharmony_ci tloge("get process path failed\n"); 194419b0af8Sopenharmony_ci kfree(tpath); 195419b0af8Sopenharmony_ci return -ENOMEM; 196419b0af8Sopenharmony_ci } 197419b0af8Sopenharmony_ci 198419b0af8Sopenharmony_ci message_size = snprintf_s(ca->path, MAX_PATH_SIZE, 199419b0af8Sopenharmony_ci MAX_PATH_SIZE - 1, "%s", path); 200419b0af8Sopenharmony_ci if (message_size <= 0) { 201419b0af8Sopenharmony_ci tloge("pack path failed\n"); 202419b0af8Sopenharmony_ci kfree(tpath); 203419b0af8Sopenharmony_ci return -EFAULT; 204419b0af8Sopenharmony_ci } 205419b0af8Sopenharmony_ci 206419b0af8Sopenharmony_ci get_task_struct(current); 207419b0af8Sopenharmony_ci cred = koadpt_get_task_cred(current); 208419b0af8Sopenharmony_ci if (!cred) { 209419b0af8Sopenharmony_ci tloge("cred is NULL\n"); 210419b0af8Sopenharmony_ci kfree(tpath); 211419b0af8Sopenharmony_ci put_task_struct(current); 212419b0af8Sopenharmony_ci return -EACCES; 213419b0af8Sopenharmony_ci } 214419b0af8Sopenharmony_ci 215419b0af8Sopenharmony_ci ca->uid = cred->uid.val; 216419b0af8Sopenharmony_ci tlogd("ca_task->comm is %s, path is %s, ca uid is %u\n", 217419b0af8Sopenharmony_ci current->comm, path, cred->uid.val); 218419b0af8Sopenharmony_ci 219419b0af8Sopenharmony_ci put_cred(cred); 220419b0af8Sopenharmony_ci put_task_struct(current); 221419b0af8Sopenharmony_ci kfree(tpath); 222419b0af8Sopenharmony_ci return 0; 223419b0af8Sopenharmony_ci} 224419b0af8Sopenharmony_ci 225419b0af8Sopenharmony_ciint check_ext_agent_access(uint32_t agent_id) 226419b0af8Sopenharmony_ci{ 227419b0af8Sopenharmony_ci int ret; 228419b0af8Sopenharmony_ci struct ca_info agent_ca = { {0}, 0, 0 }; 229419b0af8Sopenharmony_ci 230419b0af8Sopenharmony_ci ret = get_ca_path_and_uid(&agent_ca); 231419b0af8Sopenharmony_ci if (ret != 0) { 232419b0af8Sopenharmony_ci tloge("get cp path or uid failed\n"); 233419b0af8Sopenharmony_ci return ret; 234419b0af8Sopenharmony_ci } 235419b0af8Sopenharmony_ci agent_ca.agent_id = agent_id; 236419b0af8Sopenharmony_ci 237419b0af8Sopenharmony_ci return is_allowed_agent_ca(&agent_ca, true); 238419b0af8Sopenharmony_ci} 239419b0af8Sopenharmony_ci 240419b0af8Sopenharmony_cistatic int get_buf_len(const uint8_t *inbuf, uint32_t *buf_len) 241419b0af8Sopenharmony_ci{ 242419b0af8Sopenharmony_ci if (copy_from_user(buf_len, inbuf, sizeof(*buf_len))) { 243419b0af8Sopenharmony_ci tloge("copy from user failed\n"); 244419b0af8Sopenharmony_ci return -EFAULT; 245419b0af8Sopenharmony_ci } 246419b0af8Sopenharmony_ci 247419b0af8Sopenharmony_ci if (*buf_len > HASH_FILE_MAX_SIZE) { 248419b0af8Sopenharmony_ci tloge("ERROR: file size[0x%x] too big\n", *buf_len); 249419b0af8Sopenharmony_ci return -EFAULT; 250419b0af8Sopenharmony_ci } 251419b0af8Sopenharmony_ci 252419b0af8Sopenharmony_ci return 0; 253419b0af8Sopenharmony_ci} 254419b0af8Sopenharmony_ci 255419b0af8Sopenharmony_cistatic int send_set_smc_cmd(struct mb_cmd_pack *mb_pack, 256419b0af8Sopenharmony_ci struct tc_ns_smc_cmd *smc_cmd, unsigned int cmd_id, 257419b0af8Sopenharmony_ci const uint8_t *buf_to_tee, uint32_t buf_len) 258419b0af8Sopenharmony_ci{ 259419b0af8Sopenharmony_ci int ret = 0; 260419b0af8Sopenharmony_ci 261419b0af8Sopenharmony_ci mb_pack->operation.paramtypes = TEE_PARAM_TYPE_VALUE_INPUT | 262419b0af8Sopenharmony_ci (TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM); 263419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.a = 264419b0af8Sopenharmony_ci (unsigned int)mailbox_virt_to_phys((uintptr_t)buf_to_tee); 265419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.b = 266419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)buf_to_tee) >> ADDR_TRANS_NUM; 267419b0af8Sopenharmony_ci mb_pack->operation.params[1].value.a = buf_len; 268419b0af8Sopenharmony_ci smc_cmd->cmd_type = CMD_TYPE_GLOBAL; 269419b0af8Sopenharmony_ci smc_cmd->cmd_id = cmd_id; 270419b0af8Sopenharmony_ci smc_cmd->operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); 271419b0af8Sopenharmony_ci smc_cmd->operation_h_phys = 272419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; 273419b0af8Sopenharmony_ci if (tc_ns_smc(smc_cmd) != 0) { 274419b0af8Sopenharmony_ci ret = -EPERM; 275419b0af8Sopenharmony_ci tloge("set native hash failed\n"); 276419b0af8Sopenharmony_ci } 277419b0af8Sopenharmony_ci 278419b0af8Sopenharmony_ci return ret; 279419b0af8Sopenharmony_ci} 280419b0af8Sopenharmony_ci 281419b0af8Sopenharmony_ciint tc_ns_set_native_hash(unsigned long arg, unsigned int cmd_id) 282419b0af8Sopenharmony_ci{ 283419b0af8Sopenharmony_ci int ret; 284419b0af8Sopenharmony_ci struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; 285419b0af8Sopenharmony_ci uint8_t *inbuf = (uint8_t *)(uintptr_t)arg; 286419b0af8Sopenharmony_ci uint32_t buf_len = 0; 287419b0af8Sopenharmony_ci uint8_t *buf_to_tee = NULL; 288419b0af8Sopenharmony_ci struct mb_cmd_pack *mb_pack = NULL; 289419b0af8Sopenharmony_ci 290419b0af8Sopenharmony_ci ret = check_teecd_auth(); 291419b0af8Sopenharmony_ci#ifdef CONFIG_CADAEMON_AUTH 292419b0af8Sopenharmony_ci if (ret != 0) 293419b0af8Sopenharmony_ci ret = check_cadaemon_auth(); 294419b0af8Sopenharmony_ci#endif 295419b0af8Sopenharmony_ci if (ret != 0) { 296419b0af8Sopenharmony_ci tloge("teecd or cadaemon auth failed, ret %d\n", ret); 297419b0af8Sopenharmony_ci return -EACCES; 298419b0af8Sopenharmony_ci } 299419b0af8Sopenharmony_ci 300419b0af8Sopenharmony_ci if (!inbuf) 301419b0af8Sopenharmony_ci return -EINVAL; 302419b0af8Sopenharmony_ci 303419b0af8Sopenharmony_ci if (get_buf_len(inbuf, &buf_len) != 0) 304419b0af8Sopenharmony_ci return -EFAULT; 305419b0af8Sopenharmony_ci 306419b0af8Sopenharmony_ci buf_to_tee = mailbox_alloc(buf_len, 0); 307419b0af8Sopenharmony_ci if (!buf_to_tee) { 308419b0af8Sopenharmony_ci tloge("failed to alloc memory!\n"); 309419b0af8Sopenharmony_ci return -ENOMEM; 310419b0af8Sopenharmony_ci } 311419b0af8Sopenharmony_ci 312419b0af8Sopenharmony_ci if (copy_from_user(buf_to_tee, inbuf, buf_len)) { 313419b0af8Sopenharmony_ci tloge("copy from user failed\n"); 314419b0af8Sopenharmony_ci mailbox_free(buf_to_tee); 315419b0af8Sopenharmony_ci return -EFAULT; 316419b0af8Sopenharmony_ci } 317419b0af8Sopenharmony_ci 318419b0af8Sopenharmony_ci mb_pack = mailbox_alloc_cmd_pack(); 319419b0af8Sopenharmony_ci if (!mb_pack) { 320419b0af8Sopenharmony_ci tloge("alloc cmd pack failed\n"); 321419b0af8Sopenharmony_ci mailbox_free(buf_to_tee); 322419b0af8Sopenharmony_ci return -ENOMEM; 323419b0af8Sopenharmony_ci } 324419b0af8Sopenharmony_ci 325419b0af8Sopenharmony_ci ret = send_set_smc_cmd(mb_pack, &smc_cmd, cmd_id, buf_to_tee, buf_len); 326419b0af8Sopenharmony_ci mailbox_free(buf_to_tee); 327419b0af8Sopenharmony_ci mailbox_free(mb_pack); 328419b0af8Sopenharmony_ci 329419b0af8Sopenharmony_ci return ret; 330419b0af8Sopenharmony_ci} 331419b0af8Sopenharmony_ci 332419b0af8Sopenharmony_ciint tc_ns_late_init(unsigned long arg) 333419b0af8Sopenharmony_ci{ 334419b0af8Sopenharmony_ci int ret = 0; 335419b0af8Sopenharmony_ci struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; 336419b0af8Sopenharmony_ci uint32_t index = (uint32_t)arg; /* index is uint32, no truncate risk */ 337419b0af8Sopenharmony_ci struct mb_cmd_pack *mb_pack = NULL; 338419b0af8Sopenharmony_ci 339419b0af8Sopenharmony_ci mb_pack = mailbox_alloc_cmd_pack(); 340419b0af8Sopenharmony_ci if (!mb_pack) { 341419b0af8Sopenharmony_ci tloge("alloc cmd pack failed\n"); 342419b0af8Sopenharmony_ci return -ENOMEM; 343419b0af8Sopenharmony_ci } 344419b0af8Sopenharmony_ci 345419b0af8Sopenharmony_ci mb_pack->operation.paramtypes = TEE_PARAM_TYPE_VALUE_INPUT; 346419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.a = index; 347419b0af8Sopenharmony_ci 348419b0af8Sopenharmony_ci smc_cmd.cmd_type = CMD_TYPE_GLOBAL; 349419b0af8Sopenharmony_ci smc_cmd.cmd_id = GLOBAL_CMD_ID_LATE_INIT; 350419b0af8Sopenharmony_ci smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); 351419b0af8Sopenharmony_ci smc_cmd.operation_h_phys = 352419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; 353419b0af8Sopenharmony_ci 354419b0af8Sopenharmony_ci if (tc_ns_smc(&smc_cmd)) { 355419b0af8Sopenharmony_ci ret = -EPERM; 356419b0af8Sopenharmony_ci tloge("late int failed\n"); 357419b0af8Sopenharmony_ci } 358419b0af8Sopenharmony_ci mailbox_free(mb_pack); 359419b0af8Sopenharmony_ci 360419b0af8Sopenharmony_ci return ret; 361419b0af8Sopenharmony_ci} 362419b0af8Sopenharmony_ci 363419b0af8Sopenharmony_civoid send_event_response_single(const struct tc_ns_dev_file *dev_file) 364419b0af8Sopenharmony_ci{ 365419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 366419b0af8Sopenharmony_ci struct smc_event_data *tmp = NULL; 367419b0af8Sopenharmony_ci unsigned long flags; 368419b0af8Sopenharmony_ci unsigned int agent_id = 0; 369419b0af8Sopenharmony_ci 370419b0af8Sopenharmony_ci if (!dev_file) 371419b0af8Sopenharmony_ci return; 372419b0af8Sopenharmony_ci 373419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 374419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, tmp, &g_agent_control.agent_list, 375419b0af8Sopenharmony_ci head) { 376419b0af8Sopenharmony_ci if (event_data->owner == dev_file) { 377419b0af8Sopenharmony_ci agent_id = event_data->agent_id; 378419b0af8Sopenharmony_ci break; 379419b0af8Sopenharmony_ci } 380419b0af8Sopenharmony_ci } 381419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 382419b0af8Sopenharmony_ci send_event_response(agent_id); 383419b0af8Sopenharmony_ci return; 384419b0af8Sopenharmony_ci} 385419b0af8Sopenharmony_ci 386419b0af8Sopenharmony_cistruct smc_event_data *find_event_control(unsigned int agent_id) 387419b0af8Sopenharmony_ci{ 388419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 389419b0af8Sopenharmony_ci struct smc_event_data *tmp_data = NULL; 390419b0af8Sopenharmony_ci unsigned long flags; 391419b0af8Sopenharmony_ci 392419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 393419b0af8Sopenharmony_ci list_for_each_entry(event_data, &g_agent_control.agent_list, head) { 394419b0af8Sopenharmony_ci if (event_data->agent_id == agent_id) { 395419b0af8Sopenharmony_ci tmp_data = event_data; 396419b0af8Sopenharmony_ci get_agent_event(event_data); 397419b0af8Sopenharmony_ci break; 398419b0af8Sopenharmony_ci } 399419b0af8Sopenharmony_ci } 400419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 401419b0af8Sopenharmony_ci 402419b0af8Sopenharmony_ci return tmp_data; 403419b0af8Sopenharmony_ci} 404419b0af8Sopenharmony_ci 405419b0af8Sopenharmony_cistatic void unmap_agent_buffer(struct smc_event_data *event_data) 406419b0af8Sopenharmony_ci{ 407419b0af8Sopenharmony_ci if (!event_data) { 408419b0af8Sopenharmony_ci tloge("event data is NULL\n"); 409419b0af8Sopenharmony_ci return; 410419b0af8Sopenharmony_ci } 411419b0af8Sopenharmony_ci 412419b0af8Sopenharmony_ci if (IS_ERR_OR_NULL(event_data->agent_buff_user)) 413419b0af8Sopenharmony_ci return; 414419b0af8Sopenharmony_ci 415419b0af8Sopenharmony_ci if (vm_munmap((unsigned long)(uintptr_t)event_data->agent_buff_user, 416419b0af8Sopenharmony_ci event_data->agent_buff_size) != 0) 417419b0af8Sopenharmony_ci tloge("unmap failed\n"); 418419b0af8Sopenharmony_ci 419419b0af8Sopenharmony_ci event_data->agent_buff_user = NULL; 420419b0af8Sopenharmony_ci} 421419b0af8Sopenharmony_ci 422419b0af8Sopenharmony_cistatic void free_event_control(unsigned int agent_id) 423419b0af8Sopenharmony_ci{ 424419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 425419b0af8Sopenharmony_ci struct smc_event_data *tmp_event = NULL; 426419b0af8Sopenharmony_ci unsigned long flags; 427419b0af8Sopenharmony_ci bool find = false; 428419b0af8Sopenharmony_ci 429419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 430419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, tmp_event, &g_agent_control.agent_list, head) { 431419b0af8Sopenharmony_ci if (event_data->agent_id == agent_id) { 432419b0af8Sopenharmony_ci list_del(&event_data->head); 433419b0af8Sopenharmony_ci find = true; 434419b0af8Sopenharmony_ci break; 435419b0af8Sopenharmony_ci } 436419b0af8Sopenharmony_ci } 437419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 438419b0af8Sopenharmony_ci 439419b0af8Sopenharmony_ci if (!find) 440419b0af8Sopenharmony_ci return; 441419b0af8Sopenharmony_ci 442419b0af8Sopenharmony_ci unmap_agent_buffer(event_data); 443419b0af8Sopenharmony_ci mailbox_free(event_data->agent_buff_kernel); 444419b0af8Sopenharmony_ci event_data->agent_buff_kernel = NULL; 445419b0af8Sopenharmony_ci put_agent_event(event_data); 446419b0af8Sopenharmony_ci} 447419b0af8Sopenharmony_ci 448419b0af8Sopenharmony_cistatic int init_agent_context(unsigned int agent_id, 449419b0af8Sopenharmony_ci const struct tc_ns_smc_cmd *smc_cmd, 450419b0af8Sopenharmony_ci struct smc_event_data **event_data) 451419b0af8Sopenharmony_ci{ 452419b0af8Sopenharmony_ci *event_data = find_event_control(agent_id); 453419b0af8Sopenharmony_ci if (!(*event_data)) { 454419b0af8Sopenharmony_ci tloge("agent %u not exist\n", agent_id); 455419b0af8Sopenharmony_ci return -EINVAL; 456419b0af8Sopenharmony_ci } 457419b0af8Sopenharmony_ci tlogd("agent-0x%x: returning client command", agent_id); 458419b0af8Sopenharmony_ci 459419b0af8Sopenharmony_ci /* store tui working device for terminate tui when device is closed. */ 460419b0af8Sopenharmony_ci if (is_tui_agent(agent_id)) { 461419b0af8Sopenharmony_ci tloge("TEE_TUI_AGENT_ID: pid-%d", current->pid); 462419b0af8Sopenharmony_ci set_tui_caller_info(smc_cmd->dev_file_id, current->pid); 463419b0af8Sopenharmony_ci } 464419b0af8Sopenharmony_ci 465419b0af8Sopenharmony_ci isb(); 466419b0af8Sopenharmony_ci wmb(); 467419b0af8Sopenharmony_ci 468419b0af8Sopenharmony_ci return 0; 469419b0af8Sopenharmony_ci} 470419b0af8Sopenharmony_ci 471419b0af8Sopenharmony_cistatic int wait_agent_response(struct smc_event_data *event_data) 472419b0af8Sopenharmony_ci{ 473419b0af8Sopenharmony_ci int ret = 0; 474419b0af8Sopenharmony_ci /* only userspace CA need freeze */ 475419b0af8Sopenharmony_ci bool need_freeze = !(current->flags & PF_KTHREAD); 476419b0af8Sopenharmony_ci bool sig_pending = !sigisemptyset(¤t->pending.signal); 477419b0af8Sopenharmony_ci bool answered = true; 478419b0af8Sopenharmony_ci int rc; 479419b0af8Sopenharmony_ci 480419b0af8Sopenharmony_ci do { 481419b0af8Sopenharmony_ci answered = true; 482419b0af8Sopenharmony_ci /* 483419b0af8Sopenharmony_ci * wait_event_freezable will be interrupted by signal and 484419b0af8Sopenharmony_ci * freezer which is called to free a userspace task in suspend. 485419b0af8Sopenharmony_ci * Freezing a task means wakeup a task by fake_signal_wake_up 486419b0af8Sopenharmony_ci * and let it have an opportunity to enter into 'refrigerator' 487419b0af8Sopenharmony_ci * by try_to_freeze used in wait_event_freezable. 488419b0af8Sopenharmony_ci * 489419b0af8Sopenharmony_ci * What scenes can be freezed ? 490419b0af8Sopenharmony_ci * 1. CA is waiting agent -> suspend -- OK 491419b0af8Sopenharmony_ci * 2. suspend -> CA start agent request -- OK 492419b0af8Sopenharmony_ci * 3. CA is waiting agent -> CA is killed -> suspend -- NOK 493419b0af8Sopenharmony_ci */ 494419b0af8Sopenharmony_ci if (need_freeze && !sig_pending) { 495419b0af8Sopenharmony_ci rc = wait_event_freezable(event_data->ca_pending_wq, 496419b0af8Sopenharmony_ci atomic_read(&event_data->ca_run)); 497419b0af8Sopenharmony_ci if (rc != -ERESTARTSYS) 498419b0af8Sopenharmony_ci continue; 499419b0af8Sopenharmony_ci if (!sigisemptyset(¤t->pending.signal)) 500419b0af8Sopenharmony_ci sig_pending = true; 501419b0af8Sopenharmony_ci tloge("agent wait event is interrupted by %s\n", 502419b0af8Sopenharmony_ci sig_pending ? "signal" : "freezer"); 503419b0af8Sopenharmony_ci /* 504419b0af8Sopenharmony_ci * When freezing a userspace task, fake_signal_wake_up 505419b0af8Sopenharmony_ci * only set TIF_SIGPENDING but not set a real signal. 506419b0af8Sopenharmony_ci * After task thawed, CA need wait agent response again 507419b0af8Sopenharmony_ci * so TIF_SIGPENDING need to be cleared. 508419b0af8Sopenharmony_ci */ 509419b0af8Sopenharmony_ci if (!sig_pending) 510419b0af8Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 511419b0af8Sopenharmony_ci answered = false; 512419b0af8Sopenharmony_ci } else { 513419b0af8Sopenharmony_ci rc = wait_event_timeout(event_data->ca_pending_wq, 514419b0af8Sopenharmony_ci atomic_read(&event_data->ca_run), 515419b0af8Sopenharmony_ci (long)(RESLEEP_TIMEOUT * HZ)); 516419b0af8Sopenharmony_ci if (rc) 517419b0af8Sopenharmony_ci continue; 518419b0af8Sopenharmony_ci tloge("agent wait event is timeout\n"); 519419b0af8Sopenharmony_ci /* if no kill signal, just resleep before agent wake */ 520419b0af8Sopenharmony_ci if (!sigkill_pending(current)) { 521419b0af8Sopenharmony_ci answered = false; 522419b0af8Sopenharmony_ci } else { 523419b0af8Sopenharmony_ci tloge("CA is killed, no need to \ 524419b0af8Sopenharmony_ciwait agent response\n"); 525419b0af8Sopenharmony_ci event_data->ret_flag = 0; 526419b0af8Sopenharmony_ci ret = -EFAULT; 527419b0af8Sopenharmony_ci } 528419b0af8Sopenharmony_ci } 529419b0af8Sopenharmony_ci } while (!answered); 530419b0af8Sopenharmony_ci 531419b0af8Sopenharmony_ci return ret; 532419b0af8Sopenharmony_ci} 533419b0af8Sopenharmony_ci 534419b0af8Sopenharmony_ciint agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, 535419b0af8Sopenharmony_ci unsigned int agent_id) 536419b0af8Sopenharmony_ci{ 537419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 538419b0af8Sopenharmony_ci int ret; 539419b0af8Sopenharmony_ci 540419b0af8Sopenharmony_ci if (!smc_cmd) { 541419b0af8Sopenharmony_ci tloge("smc_cmd is null\n"); 542419b0af8Sopenharmony_ci return -EINVAL; 543419b0af8Sopenharmony_ci } 544419b0af8Sopenharmony_ci 545419b0af8Sopenharmony_ci if (init_agent_context(agent_id, smc_cmd, &event_data)) 546419b0af8Sopenharmony_ci return -EINVAL; 547419b0af8Sopenharmony_ci 548419b0af8Sopenharmony_ci if (atomic_read(&event_data->agent_ready) == AGENT_CRASHED) { 549419b0af8Sopenharmony_ci tloge("agent 0x%x is killed and restarting\n", agent_id); 550419b0af8Sopenharmony_ci put_agent_event(event_data); 551419b0af8Sopenharmony_ci return -EFAULT; 552419b0af8Sopenharmony_ci } 553419b0af8Sopenharmony_ci 554419b0af8Sopenharmony_ci event_data->ret_flag = 1; 555419b0af8Sopenharmony_ci /* Wake up the agent that will process the command */ 556419b0af8Sopenharmony_ci tlogd("agent process work: wakeup the agent"); 557419b0af8Sopenharmony_ci wake_up(&event_data->wait_event_wq); 558419b0af8Sopenharmony_ci tlogd("agent 0x%x request, goto sleep, pe->run=%d\n", 559419b0af8Sopenharmony_ci agent_id, atomic_read(&event_data->ca_run)); 560419b0af8Sopenharmony_ci 561419b0af8Sopenharmony_ci ret = wait_agent_response(event_data); 562419b0af8Sopenharmony_ci atomic_set(&event_data->ca_run, 0); 563419b0af8Sopenharmony_ci put_agent_event(event_data); 564419b0af8Sopenharmony_ci 565419b0af8Sopenharmony_ci /* 566419b0af8Sopenharmony_ci * when agent work is done, reset cmd monitor time 567419b0af8Sopenharmony_ci * add agent call count, cause it's a new smc cmd. 568419b0af8Sopenharmony_ci */ 569419b0af8Sopenharmony_ci cmd_monitor_reset_context(); 570419b0af8Sopenharmony_ci return ret; 571419b0af8Sopenharmony_ci} 572419b0af8Sopenharmony_ci 573419b0af8Sopenharmony_ciint is_agent_alive(unsigned int agent_id) 574419b0af8Sopenharmony_ci{ 575419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 576419b0af8Sopenharmony_ci 577419b0af8Sopenharmony_ci event_data = find_event_control(agent_id); 578419b0af8Sopenharmony_ci if (event_data) { 579419b0af8Sopenharmony_ci put_agent_event(event_data); 580419b0af8Sopenharmony_ci return AGENT_ALIVE; 581419b0af8Sopenharmony_ci } 582419b0af8Sopenharmony_ci 583419b0af8Sopenharmony_ci return AGENT_DEAD; 584419b0af8Sopenharmony_ci} 585419b0af8Sopenharmony_ci 586419b0af8Sopenharmony_ciint tc_ns_wait_event(unsigned int agent_id) 587419b0af8Sopenharmony_ci{ 588419b0af8Sopenharmony_ci int ret = -EINVAL; 589419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 590419b0af8Sopenharmony_ci 591419b0af8Sopenharmony_ci tlogd("agent %u waits for command\n", agent_id); 592419b0af8Sopenharmony_ci 593419b0af8Sopenharmony_ci event_data = find_event_control(agent_id); 594419b0af8Sopenharmony_ci if (event_data) { 595419b0af8Sopenharmony_ci /* only when agent wait event, it's in ready state to work */ 596419b0af8Sopenharmony_ci atomic_set(&(event_data->agent_ready), AGENT_READY); 597419b0af8Sopenharmony_ci ret = wait_event_interruptible(event_data->wait_event_wq, event_data->ret_flag); 598419b0af8Sopenharmony_ci put_agent_event(event_data); 599419b0af8Sopenharmony_ci } 600419b0af8Sopenharmony_ci 601419b0af8Sopenharmony_ci return ret; 602419b0af8Sopenharmony_ci} 603419b0af8Sopenharmony_ci 604419b0af8Sopenharmony_ciint tc_ns_sync_sys_time(const struct tc_ns_client_time *tc_ns_time) 605419b0af8Sopenharmony_ci{ 606419b0af8Sopenharmony_ci struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; 607419b0af8Sopenharmony_ci int ret = 0; 608419b0af8Sopenharmony_ci struct mb_cmd_pack *mb_pack = NULL; 609419b0af8Sopenharmony_ci 610419b0af8Sopenharmony_ci if (!tc_ns_time) { 611419b0af8Sopenharmony_ci tloge("tc_ns_time is NULL input buffer\n"); 612419b0af8Sopenharmony_ci return -EINVAL; 613419b0af8Sopenharmony_ci } 614419b0af8Sopenharmony_ci 615419b0af8Sopenharmony_ci mb_pack = mailbox_alloc_cmd_pack(); 616419b0af8Sopenharmony_ci if (!mb_pack) { 617419b0af8Sopenharmony_ci tloge("alloc mb pack failed\n"); 618419b0af8Sopenharmony_ci return -ENOMEM; 619419b0af8Sopenharmony_ci } 620419b0af8Sopenharmony_ci 621419b0af8Sopenharmony_ci mb_pack->operation.paramtypes = TEE_PARAM_TYPE_VALUE_INPUT; 622419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.a = tc_ns_time->seconds; 623419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.b = tc_ns_time->millis; 624419b0af8Sopenharmony_ci 625419b0af8Sopenharmony_ci smc_cmd.cmd_type = CMD_TYPE_GLOBAL; 626419b0af8Sopenharmony_ci smc_cmd.cmd_id = GLOBAL_CMD_ID_ADJUST_TIME; 627419b0af8Sopenharmony_ci smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); 628419b0af8Sopenharmony_ci smc_cmd.operation_h_phys = 629419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; 630419b0af8Sopenharmony_ci if (tc_ns_smc(&smc_cmd)) { 631419b0af8Sopenharmony_ci tloge("tee adjust time failed, return error\n"); 632419b0af8Sopenharmony_ci ret = -EPERM; 633419b0af8Sopenharmony_ci } 634419b0af8Sopenharmony_ci mailbox_free(mb_pack); 635419b0af8Sopenharmony_ci 636419b0af8Sopenharmony_ci return ret; 637419b0af8Sopenharmony_ci} 638419b0af8Sopenharmony_ci 639419b0af8Sopenharmony_ciint sync_system_time_from_user(const struct tc_ns_client_time *user_time) 640419b0af8Sopenharmony_ci{ 641419b0af8Sopenharmony_ci int ret = 0; 642419b0af8Sopenharmony_ci struct tc_ns_client_time time = { 0 }; 643419b0af8Sopenharmony_ci 644419b0af8Sopenharmony_ci if (!user_time) { 645419b0af8Sopenharmony_ci tloge("user time is NULL input buffer\n"); 646419b0af8Sopenharmony_ci return -EINVAL; 647419b0af8Sopenharmony_ci } 648419b0af8Sopenharmony_ci 649419b0af8Sopenharmony_ci if (copy_from_user(&time, user_time, sizeof(time))) { 650419b0af8Sopenharmony_ci tloge("copy from user failed\n"); 651419b0af8Sopenharmony_ci return -EFAULT; 652419b0af8Sopenharmony_ci } 653419b0af8Sopenharmony_ci 654419b0af8Sopenharmony_ci ret = tc_ns_sync_sys_time(&time); 655419b0af8Sopenharmony_ci if (ret != 0) 656419b0af8Sopenharmony_ci tloge("sync system time from user failed, ret = 0x%x\n", ret); 657419b0af8Sopenharmony_ci 658419b0af8Sopenharmony_ci return ret; 659419b0af8Sopenharmony_ci} 660419b0af8Sopenharmony_ci 661419b0af8Sopenharmony_civoid sync_system_time_from_kernel(void) 662419b0af8Sopenharmony_ci{ 663419b0af8Sopenharmony_ci int ret = 0; 664419b0af8Sopenharmony_ci struct tc_ns_client_time time = { 0 }; 665419b0af8Sopenharmony_ci 666419b0af8Sopenharmony_ci struct time_spec kernel_time = {0}; 667419b0af8Sopenharmony_ci get_time_spec(&kernel_time); 668419b0af8Sopenharmony_ci 669419b0af8Sopenharmony_ci time.seconds = (uint32_t)kernel_time.ts.tv_sec; 670419b0af8Sopenharmony_ci time.millis = (uint32_t)(kernel_time.ts.tv_nsec / MS_TO_NS); 671419b0af8Sopenharmony_ci 672419b0af8Sopenharmony_ci ret = tc_ns_sync_sys_time(&time); 673419b0af8Sopenharmony_ci if (ret != 0) 674419b0af8Sopenharmony_ci tloge("sync system time from kernel failed, ret = 0x%x\n", ret); 675419b0af8Sopenharmony_ci 676419b0af8Sopenharmony_ci return; 677419b0af8Sopenharmony_ci} 678419b0af8Sopenharmony_ci 679419b0af8Sopenharmony_cistatic struct smc_event_data *check_response_access(unsigned int agent_id) 680419b0af8Sopenharmony_ci{ 681419b0af8Sopenharmony_ci struct smc_event_data *event_data = find_event_control(agent_id); 682419b0af8Sopenharmony_ci 683419b0af8Sopenharmony_ci if (!event_data) { 684419b0af8Sopenharmony_ci tloge("Can't get event_data\n"); 685419b0af8Sopenharmony_ci return NULL; 686419b0af8Sopenharmony_ci } 687419b0af8Sopenharmony_ci return event_data; 688419b0af8Sopenharmony_ci} 689419b0af8Sopenharmony_ci 690419b0af8Sopenharmony_cistatic void process_send_event_response(struct smc_event_data *event_data) 691419b0af8Sopenharmony_ci{ 692419b0af8Sopenharmony_ci if (event_data->ret_flag == 0) 693419b0af8Sopenharmony_ci return; 694419b0af8Sopenharmony_ci 695419b0af8Sopenharmony_ci event_data->ret_flag = 0; 696419b0af8Sopenharmony_ci /* Send the command back to the TA session waiting for it */ 697419b0af8Sopenharmony_ci tlogd("agent wakeup ca\n"); 698419b0af8Sopenharmony_ci atomic_set(&event_data->ca_run, 1); 699419b0af8Sopenharmony_ci /* make sure reset working_ca before wakeup CA */ 700419b0af8Sopenharmony_ci wake_up(&event_data->ca_pending_wq); 701419b0af8Sopenharmony_ci} 702419b0af8Sopenharmony_ci 703419b0af8Sopenharmony_ciint tc_ns_send_event_response(unsigned int agent_id) 704419b0af8Sopenharmony_ci{ 705419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 706419b0af8Sopenharmony_ci 707419b0af8Sopenharmony_ci event_data = check_response_access(agent_id); 708419b0af8Sopenharmony_ci if (!event_data) { 709419b0af8Sopenharmony_ci tlogd("agent %u pre-check failed\n", agent_id); 710419b0af8Sopenharmony_ci return -EINVAL; 711419b0af8Sopenharmony_ci } 712419b0af8Sopenharmony_ci 713419b0af8Sopenharmony_ci tlogd("agent %u sends answer back\n", agent_id); 714419b0af8Sopenharmony_ci process_send_event_response(event_data); 715419b0af8Sopenharmony_ci put_agent_event(event_data); 716419b0af8Sopenharmony_ci 717419b0af8Sopenharmony_ci return 0; 718419b0af8Sopenharmony_ci} 719419b0af8Sopenharmony_ci 720419b0af8Sopenharmony_civoid send_event_response(unsigned int agent_id) 721419b0af8Sopenharmony_ci{ 722419b0af8Sopenharmony_ci struct smc_event_data *event_data = find_event_control(agent_id); 723419b0af8Sopenharmony_ci 724419b0af8Sopenharmony_ci if (!event_data) { 725419b0af8Sopenharmony_ci tloge("Can't get event_data\n"); 726419b0af8Sopenharmony_ci return; 727419b0af8Sopenharmony_ci } 728419b0af8Sopenharmony_ci 729419b0af8Sopenharmony_ci tlogi("agent 0x%x sends answer back\n", agent_id); 730419b0af8Sopenharmony_ci atomic_set(&event_data->agent_ready, AGENT_CRASHED); 731419b0af8Sopenharmony_ci process_send_event_response(event_data); 732419b0af8Sopenharmony_ci put_agent_event(event_data); 733419b0af8Sopenharmony_ci} 734419b0af8Sopenharmony_ci 735419b0af8Sopenharmony_cistatic void init_restart_agent_node(struct tc_ns_dev_file *dev_file, 736419b0af8Sopenharmony_ci struct smc_event_data *event_data) 737419b0af8Sopenharmony_ci{ 738419b0af8Sopenharmony_ci tlogi("agent: 0x%x restarting\n", event_data->agent_id); 739419b0af8Sopenharmony_ci event_data->ret_flag = 0; 740419b0af8Sopenharmony_ci event_data->owner = dev_file; 741419b0af8Sopenharmony_ci atomic_set(&event_data->agent_ready, AGENT_REGISTERED); 742419b0af8Sopenharmony_ci init_waitqueue_head(&(event_data->wait_event_wq)); 743419b0af8Sopenharmony_ci init_waitqueue_head(&(event_data->send_response_wq)); 744419b0af8Sopenharmony_ci init_waitqueue_head(&(event_data->ca_pending_wq)); 745419b0af8Sopenharmony_ci atomic_set(&(event_data->ca_run), 0); 746419b0af8Sopenharmony_ci} 747419b0af8Sopenharmony_ci 748419b0af8Sopenharmony_cistatic int create_new_agent_node(struct tc_ns_dev_file *dev_file, 749419b0af8Sopenharmony_ci struct smc_event_data **event_data, unsigned int agent_id, 750419b0af8Sopenharmony_ci void **agent_buff, uint32_t agent_buff_size) 751419b0af8Sopenharmony_ci{ 752419b0af8Sopenharmony_ci *agent_buff = mailbox_alloc(agent_buff_size, MB_FLAG_ZERO); 753419b0af8Sopenharmony_ci if (!(*agent_buff)) { 754419b0af8Sopenharmony_ci tloge("alloc agent buff failed\n"); 755419b0af8Sopenharmony_ci return -ENOMEM; 756419b0af8Sopenharmony_ci } 757419b0af8Sopenharmony_ci *event_data = kzalloc(sizeof(**event_data), GFP_KERNEL); 758419b0af8Sopenharmony_ci if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(*event_data))) { 759419b0af8Sopenharmony_ci mailbox_free(*agent_buff); 760419b0af8Sopenharmony_ci *agent_buff = NULL; 761419b0af8Sopenharmony_ci *event_data = NULL; 762419b0af8Sopenharmony_ci tloge("alloc event data failed\n"); 763419b0af8Sopenharmony_ci return -ENOMEM; 764419b0af8Sopenharmony_ci } 765419b0af8Sopenharmony_ci (*event_data)->agent_id = agent_id; 766419b0af8Sopenharmony_ci (*event_data)->ret_flag = 0; 767419b0af8Sopenharmony_ci (*event_data)->agent_buff_kernel = *agent_buff; 768419b0af8Sopenharmony_ci (*event_data)->agent_buff_size = agent_buff_size; 769419b0af8Sopenharmony_ci (*event_data)->owner = dev_file; 770419b0af8Sopenharmony_ci atomic_set(&(*event_data)->agent_ready, AGENT_REGISTERED); 771419b0af8Sopenharmony_ci init_waitqueue_head(&(*event_data)->wait_event_wq); 772419b0af8Sopenharmony_ci init_waitqueue_head(&(*event_data)->send_response_wq); 773419b0af8Sopenharmony_ci INIT_LIST_HEAD(&(*event_data)->head); 774419b0af8Sopenharmony_ci init_waitqueue_head(&(*event_data)->ca_pending_wq); 775419b0af8Sopenharmony_ci atomic_set(&(*event_data)->ca_run, 0); 776419b0af8Sopenharmony_ci 777419b0af8Sopenharmony_ci return 0; 778419b0af8Sopenharmony_ci} 779419b0af8Sopenharmony_ci 780419b0af8Sopenharmony_ci#ifdef CONFIG_LIBLINUX 781419b0af8Sopenharmony_cistatic unsigned long agent_buffer_map(unsigned long buffer, uint32_t size) 782419b0af8Sopenharmony_ci{ 783419b0af8Sopenharmony_ci struct vm_area_struct *vma = NULL; 784419b0af8Sopenharmony_ci unsigned long user_addr; 785419b0af8Sopenharmony_ci int ret; 786419b0af8Sopenharmony_ci 787419b0af8Sopenharmony_ci void *priv = NULL; 788419b0af8Sopenharmony_ci pgprot_t pro; 789419b0af8Sopenharmony_ci pro.pgprot = VM_READ | VM_WRITE; 790419b0af8Sopenharmony_ci 791419b0af8Sopenharmony_ci size = PAGE_ALIGN(size); 792419b0af8Sopenharmony_ci if (!size) 793419b0af8Sopenharmony_ci return -ENOMEM; 794419b0af8Sopenharmony_ci 795419b0af8Sopenharmony_ci user_addr = liblinux_pal_usermap_prepare(user_addr, size, PROT_READ | PROT_WRITE, 796419b0af8Sopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, &priv); 797419b0af8Sopenharmony_ci if (IS_ERR_OR_NULL((const void *)user_addr)) { 798419b0af8Sopenharmony_ci tloge("agent usermap prepare failed\n"); 799419b0af8Sopenharmony_ci return user_addr; 800419b0af8Sopenharmony_ci } 801419b0af8Sopenharmony_ci liblinux_pal_usermap_finish((const void *)priv, !IS_ERR_VALUE(ret)); 802419b0af8Sopenharmony_ci 803419b0af8Sopenharmony_ci ret = remap_pfn_range(NULL, user_addr, buffer >> PAGE_SHIFT, size, pro); 804419b0af8Sopenharmony_ci if (ret) { 805419b0af8Sopenharmony_ci tloge("remap agent buffer failed, err=%d", ret); 806419b0af8Sopenharmony_ci goto err_out; 807419b0af8Sopenharmony_ci } 808419b0af8Sopenharmony_ci 809419b0af8Sopenharmony_ci return user_addr; 810419b0af8Sopenharmony_cierr_out: 811419b0af8Sopenharmony_ci if (vm_munmap(user_addr, size)) 812419b0af8Sopenharmony_ci tloge("munmap failed\n"); 813419b0af8Sopenharmony_ci return -EFAULT; 814419b0af8Sopenharmony_ci} 815419b0af8Sopenharmony_ci#else 816419b0af8Sopenharmony_cistatic unsigned long agent_buffer_map(unsigned long buffer, uint32_t size) 817419b0af8Sopenharmony_ci{ 818419b0af8Sopenharmony_ci struct vm_area_struct *vma = NULL; 819419b0af8Sopenharmony_ci unsigned long user_addr; 820419b0af8Sopenharmony_ci int ret; 821419b0af8Sopenharmony_ci 822419b0af8Sopenharmony_ci user_addr = vm_mmap(NULL, 0, size, PROT_READ | PROT_WRITE, 823419b0af8Sopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, 0); 824419b0af8Sopenharmony_ci if (IS_ERR_VALUE((uintptr_t)user_addr)) { 825419b0af8Sopenharmony_ci tloge("vm mmap failed\n"); 826419b0af8Sopenharmony_ci return user_addr; 827419b0af8Sopenharmony_ci } 828419b0af8Sopenharmony_ci 829419b0af8Sopenharmony_ci down_read(&mm_sem_lock(current->mm)); 830419b0af8Sopenharmony_ci vma = find_vma(current->mm, user_addr); 831419b0af8Sopenharmony_ci if (!vma) { 832419b0af8Sopenharmony_ci tloge("user_addr is not valid in vma"); 833419b0af8Sopenharmony_ci goto err_out; 834419b0af8Sopenharmony_ci } 835419b0af8Sopenharmony_ci 836419b0af8Sopenharmony_ci ret = remap_pfn_range(vma, user_addr, buffer >> PAGE_SHIFT, size, 837419b0af8Sopenharmony_ci vma->vm_page_prot); 838419b0af8Sopenharmony_ci if (ret != 0) { 839419b0af8Sopenharmony_ci tloge("remap agent buffer failed, err=%d", ret); 840419b0af8Sopenharmony_ci goto err_out; 841419b0af8Sopenharmony_ci } 842419b0af8Sopenharmony_ci 843419b0af8Sopenharmony_ci up_read(&mm_sem_lock(current->mm)); 844419b0af8Sopenharmony_ci return user_addr; 845419b0af8Sopenharmony_cierr_out: 846419b0af8Sopenharmony_ci up_read(&mm_sem_lock(current->mm)); 847419b0af8Sopenharmony_ci if (vm_munmap(user_addr, size)) 848419b0af8Sopenharmony_ci tloge("munmap failed\n"); 849419b0af8Sopenharmony_ci return -EFAULT; 850419b0af8Sopenharmony_ci} 851419b0af8Sopenharmony_ci#endif 852419b0af8Sopenharmony_ci 853419b0af8Sopenharmony_cistatic bool is_valid_agent(unsigned int agent_id, 854419b0af8Sopenharmony_ci unsigned int buffer_size, bool user_agent) 855419b0af8Sopenharmony_ci{ 856419b0af8Sopenharmony_ci (void)agent_id; 857419b0af8Sopenharmony_ci if (user_agent && (buffer_size > SZ_4K)) { 858419b0af8Sopenharmony_ci tloge("size: %u of user agent's shared mem is invalid\n", 859419b0af8Sopenharmony_ci buffer_size); 860419b0af8Sopenharmony_ci return false; 861419b0af8Sopenharmony_ci } 862419b0af8Sopenharmony_ci 863419b0af8Sopenharmony_ci return true; 864419b0af8Sopenharmony_ci} 865419b0af8Sopenharmony_ci 866419b0af8Sopenharmony_cistatic int is_agent_already_exist(unsigned int agent_id, 867419b0af8Sopenharmony_ci struct smc_event_data **event_data, struct tc_ns_dev_file *dev_file, bool *find_flag) 868419b0af8Sopenharmony_ci{ 869419b0af8Sopenharmony_ci unsigned long flags; 870419b0af8Sopenharmony_ci bool flag = false; 871419b0af8Sopenharmony_ci struct smc_event_data *agent_node = NULL; 872419b0af8Sopenharmony_ci 873419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 874419b0af8Sopenharmony_ci list_for_each_entry(agent_node, &g_agent_control.agent_list, head) { 875419b0af8Sopenharmony_ci if (agent_node->agent_id == agent_id) { 876419b0af8Sopenharmony_ci if (atomic_read(&agent_node->agent_ready) != AGENT_CRASHED) { 877419b0af8Sopenharmony_ci tloge("no allow agent proc to reg twice\n"); 878419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 879419b0af8Sopenharmony_ci return -EINVAL; 880419b0af8Sopenharmony_ci } 881419b0af8Sopenharmony_ci flag = true; 882419b0af8Sopenharmony_ci get_agent_event(agent_node); 883419b0af8Sopenharmony_ci /* 884419b0af8Sopenharmony_ci * We find the agent event_data aready in agent_list, it indicate agent 885419b0af8Sopenharmony_ci * didn't unregister normally, so the event_data will be reused. 886419b0af8Sopenharmony_ci */ 887419b0af8Sopenharmony_ci init_restart_agent_node(dev_file, agent_node); 888419b0af8Sopenharmony_ci break; 889419b0af8Sopenharmony_ci } 890419b0af8Sopenharmony_ci } 891419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 892419b0af8Sopenharmony_ci *find_flag = flag; 893419b0af8Sopenharmony_ci if (flag) 894419b0af8Sopenharmony_ci *event_data = agent_node; 895419b0af8Sopenharmony_ci return 0; 896419b0af8Sopenharmony_ci} 897419b0af8Sopenharmony_ci 898419b0af8Sopenharmony_cistatic void add_event_node_to_list(struct smc_event_data *event_data) 899419b0af8Sopenharmony_ci{ 900419b0af8Sopenharmony_ci unsigned long flags; 901419b0af8Sopenharmony_ci 902419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 903419b0af8Sopenharmony_ci list_add_tail(&event_data->head, &g_agent_control.agent_list); 904419b0af8Sopenharmony_ci atomic_set(&event_data->usage, 1); 905419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 906419b0af8Sopenharmony_ci} 907419b0af8Sopenharmony_ci 908419b0af8Sopenharmony_cistatic int register_agent_to_tee(unsigned int agent_id, const void *agent_buff, uint32_t agent_buff_size) 909419b0af8Sopenharmony_ci{ 910419b0af8Sopenharmony_ci int ret = 0; 911419b0af8Sopenharmony_ci struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; 912419b0af8Sopenharmony_ci struct mb_cmd_pack *mb_pack = NULL; 913419b0af8Sopenharmony_ci 914419b0af8Sopenharmony_ci mb_pack = mailbox_alloc_cmd_pack(); 915419b0af8Sopenharmony_ci if (!mb_pack) { 916419b0af8Sopenharmony_ci tloge("alloc mailbox failed\n"); 917419b0af8Sopenharmony_ci return -ENOMEM; 918419b0af8Sopenharmony_ci } 919419b0af8Sopenharmony_ci 920419b0af8Sopenharmony_ci mb_pack->operation.paramtypes = TEE_PARAM_TYPE_VALUE_INPUT | 921419b0af8Sopenharmony_ci (TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM); 922419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.a = 923419b0af8Sopenharmony_ci mailbox_virt_to_phys((uintptr_t)agent_buff); 924419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.b = 925419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)agent_buff) >> ADDR_TRANS_NUM; 926419b0af8Sopenharmony_ci mb_pack->operation.params[1].value.a = agent_buff_size; 927419b0af8Sopenharmony_ci smc_cmd.cmd_type = CMD_TYPE_GLOBAL; 928419b0af8Sopenharmony_ci smc_cmd.cmd_id = GLOBAL_CMD_ID_REGISTER_AGENT; 929419b0af8Sopenharmony_ci smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); 930419b0af8Sopenharmony_ci smc_cmd.operation_h_phys = 931419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; 932419b0af8Sopenharmony_ci smc_cmd.agent_id = agent_id; 933419b0af8Sopenharmony_ci 934419b0af8Sopenharmony_ci if (tc_ns_smc(&smc_cmd)) { 935419b0af8Sopenharmony_ci ret = -EPERM; 936419b0af8Sopenharmony_ci tloge("register agent to tee failed\n"); 937419b0af8Sopenharmony_ci } 938419b0af8Sopenharmony_ci mailbox_free(mb_pack); 939419b0af8Sopenharmony_ci 940419b0af8Sopenharmony_ci return ret; 941419b0af8Sopenharmony_ci} 942419b0af8Sopenharmony_ci 943419b0af8Sopenharmony_cistatic int get_agent_buffer(struct smc_event_data *event_data, 944419b0af8Sopenharmony_ci bool user_agent, void **buffer) 945419b0af8Sopenharmony_ci{ 946419b0af8Sopenharmony_ci /* agent first start or restart, both need a remap */ 947419b0af8Sopenharmony_ci if (user_agent) { 948419b0af8Sopenharmony_ci event_data->agent_buff_user = 949419b0af8Sopenharmony_ci (void *)(uintptr_t)agent_buffer_map( 950419b0af8Sopenharmony_ci mailbox_virt_to_phys((uintptr_t)event_data->agent_buff_kernel), 951419b0af8Sopenharmony_ci event_data->agent_buff_size); 952419b0af8Sopenharmony_ci if (IS_ERR(event_data->agent_buff_user)) { 953419b0af8Sopenharmony_ci tloge("vm map agent buffer failed\n"); 954419b0af8Sopenharmony_ci return -EFAULT; 955419b0af8Sopenharmony_ci } 956419b0af8Sopenharmony_ci *buffer = event_data->agent_buff_user; 957419b0af8Sopenharmony_ci } else { 958419b0af8Sopenharmony_ci *buffer = event_data->agent_buff_kernel; 959419b0af8Sopenharmony_ci } 960419b0af8Sopenharmony_ci 961419b0af8Sopenharmony_ci return 0; 962419b0af8Sopenharmony_ci} 963419b0af8Sopenharmony_ci 964419b0af8Sopenharmony_ciint tc_ns_register_agent(struct tc_ns_dev_file *dev_file, 965419b0af8Sopenharmony_ci unsigned int agent_id, unsigned int buffer_size, 966419b0af8Sopenharmony_ci void **buffer, bool user_agent) 967419b0af8Sopenharmony_ci{ 968419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 969419b0af8Sopenharmony_ci int ret = -EINVAL; 970419b0af8Sopenharmony_ci bool find_flag = false; 971419b0af8Sopenharmony_ci void *agent_buff = NULL; 972419b0af8Sopenharmony_ci uint32_t size_align; 973419b0af8Sopenharmony_ci 974419b0af8Sopenharmony_ci /* dev can be null */ 975419b0af8Sopenharmony_ci if (!buffer) 976419b0af8Sopenharmony_ci return ret; 977419b0af8Sopenharmony_ci 978419b0af8Sopenharmony_ci if (!is_valid_agent(agent_id, buffer_size, user_agent)) 979419b0af8Sopenharmony_ci return ret; 980419b0af8Sopenharmony_ci 981419b0af8Sopenharmony_ci size_align = ALIGN(buffer_size, SZ_4K); 982419b0af8Sopenharmony_ci 983419b0af8Sopenharmony_ci if (is_agent_already_exist(agent_id, &event_data, dev_file, &find_flag)) 984419b0af8Sopenharmony_ci return ret; 985419b0af8Sopenharmony_ci if (!find_flag) { 986419b0af8Sopenharmony_ci ret = create_new_agent_node(dev_file, &event_data, 987419b0af8Sopenharmony_ci agent_id, &agent_buff, size_align); 988419b0af8Sopenharmony_ci if (ret != 0) 989419b0af8Sopenharmony_ci return ret; 990419b0af8Sopenharmony_ci } 991419b0af8Sopenharmony_ci 992419b0af8Sopenharmony_ci if (get_agent_buffer(event_data, user_agent, buffer)) 993419b0af8Sopenharmony_ci goto release_rsrc; 994419b0af8Sopenharmony_ci 995419b0af8Sopenharmony_ci /* find_flag is false means it's a new agent register */ 996419b0af8Sopenharmony_ci if (!find_flag) { 997419b0af8Sopenharmony_ci /* 998419b0af8Sopenharmony_ci * Obtain share memory which is released 999419b0af8Sopenharmony_ci * in tc_ns_unregister_agent 1000419b0af8Sopenharmony_ci */ 1001419b0af8Sopenharmony_ci ret = register_agent_to_tee(agent_id, agent_buff, size_align); 1002419b0af8Sopenharmony_ci if (ret != 0) { 1003419b0af8Sopenharmony_ci unmap_agent_buffer(event_data); 1004419b0af8Sopenharmony_ci goto release_rsrc; 1005419b0af8Sopenharmony_ci } 1006419b0af8Sopenharmony_ci add_event_node_to_list(event_data); 1007419b0af8Sopenharmony_ci } 1008419b0af8Sopenharmony_ci if (find_flag) 1009419b0af8Sopenharmony_ci put_agent_event(event_data); /* match get action */ 1010419b0af8Sopenharmony_ci return 0; 1011419b0af8Sopenharmony_ci 1012419b0af8Sopenharmony_cirelease_rsrc: 1013419b0af8Sopenharmony_ci if (find_flag) 1014419b0af8Sopenharmony_ci put_agent_event(event_data); /* match get action */ 1015419b0af8Sopenharmony_ci else 1016419b0af8Sopenharmony_ci kfree(event_data); /* here event_data can never be NULL */ 1017419b0af8Sopenharmony_ci 1018419b0af8Sopenharmony_ci if (agent_buff) 1019419b0af8Sopenharmony_ci mailbox_free(agent_buff); 1020419b0af8Sopenharmony_ci return ret; 1021419b0af8Sopenharmony_ci} 1022419b0af8Sopenharmony_ci 1023419b0af8Sopenharmony_ciint tc_ns_unregister_agent(unsigned int agent_id) 1024419b0af8Sopenharmony_ci{ 1025419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 1026419b0af8Sopenharmony_ci int ret = 0; 1027419b0af8Sopenharmony_ci struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; 1028419b0af8Sopenharmony_ci struct mb_cmd_pack *mb_pack = NULL; 1029419b0af8Sopenharmony_ci 1030419b0af8Sopenharmony_ci event_data = find_event_control(agent_id); 1031419b0af8Sopenharmony_ci if (!event_data || !event_data->agent_buff_kernel) { 1032419b0af8Sopenharmony_ci tloge("agent is not found or kaddr is not allocated\n"); 1033419b0af8Sopenharmony_ci return -EINVAL; 1034419b0af8Sopenharmony_ci } 1035419b0af8Sopenharmony_ci 1036419b0af8Sopenharmony_ci mb_pack = mailbox_alloc_cmd_pack(); 1037419b0af8Sopenharmony_ci if (!mb_pack) { 1038419b0af8Sopenharmony_ci tloge("alloc mailbox failed\n"); 1039419b0af8Sopenharmony_ci put_agent_event(event_data); 1040419b0af8Sopenharmony_ci return -ENOMEM; 1041419b0af8Sopenharmony_ci } 1042419b0af8Sopenharmony_ci mb_pack->operation.paramtypes = TEE_PARAM_TYPE_VALUE_INPUT | 1043419b0af8Sopenharmony_ci (TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM); 1044419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.a = 1045419b0af8Sopenharmony_ci mailbox_virt_to_phys((uintptr_t)event_data->agent_buff_kernel); 1046419b0af8Sopenharmony_ci mb_pack->operation.params[0].value.b = 1047419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)event_data->agent_buff_kernel) >> ADDR_TRANS_NUM; 1048419b0af8Sopenharmony_ci mb_pack->operation.params[1].value.a = SZ_4K; 1049419b0af8Sopenharmony_ci smc_cmd.cmd_type = CMD_TYPE_GLOBAL; 1050419b0af8Sopenharmony_ci smc_cmd.cmd_id = GLOBAL_CMD_ID_UNREGISTER_AGENT; 1051419b0af8Sopenharmony_ci smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); 1052419b0af8Sopenharmony_ci smc_cmd.operation_h_phys = 1053419b0af8Sopenharmony_ci (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; 1054419b0af8Sopenharmony_ci smc_cmd.agent_id = agent_id; 1055419b0af8Sopenharmony_ci tlogd("unregistering agent 0x%x\n", agent_id); 1056419b0af8Sopenharmony_ci 1057419b0af8Sopenharmony_ci if (tc_ns_smc(&smc_cmd) == 0) { 1058419b0af8Sopenharmony_ci free_event_control(agent_id); 1059419b0af8Sopenharmony_ci } else { 1060419b0af8Sopenharmony_ci ret = -EPERM; 1061419b0af8Sopenharmony_ci tloge("unregister agent failed\n"); 1062419b0af8Sopenharmony_ci } 1063419b0af8Sopenharmony_ci put_agent_event(event_data); 1064419b0af8Sopenharmony_ci mailbox_free(mb_pack); 1065419b0af8Sopenharmony_ci return ret; 1066419b0af8Sopenharmony_ci} 1067419b0af8Sopenharmony_ci 1068419b0af8Sopenharmony_cibool is_system_agent(const struct tc_ns_dev_file *dev_file) 1069419b0af8Sopenharmony_ci{ 1070419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 1071419b0af8Sopenharmony_ci struct smc_event_data *tmp = NULL; 1072419b0af8Sopenharmony_ci bool system_agent = false; 1073419b0af8Sopenharmony_ci unsigned long flags; 1074419b0af8Sopenharmony_ci 1075419b0af8Sopenharmony_ci if (!dev_file) 1076419b0af8Sopenharmony_ci return system_agent; 1077419b0af8Sopenharmony_ci 1078419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 1079419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, tmp, &g_agent_control.agent_list, 1080419b0af8Sopenharmony_ci head) { 1081419b0af8Sopenharmony_ci if (event_data->owner == dev_file) { 1082419b0af8Sopenharmony_ci system_agent = true; 1083419b0af8Sopenharmony_ci break; 1084419b0af8Sopenharmony_ci } 1085419b0af8Sopenharmony_ci } 1086419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 1087419b0af8Sopenharmony_ci 1088419b0af8Sopenharmony_ci return system_agent; 1089419b0af8Sopenharmony_ci} 1090419b0af8Sopenharmony_ci 1091419b0af8Sopenharmony_civoid send_crashed_event_response_all(const struct tc_ns_dev_file *dev_file) 1092419b0af8Sopenharmony_ci{ 1093419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 1094419b0af8Sopenharmony_ci struct smc_event_data *tmp = NULL; 1095419b0af8Sopenharmony_ci unsigned int agent_id[AGENT_MAX] = {0}; 1096419b0af8Sopenharmony_ci unsigned int i = 0; 1097419b0af8Sopenharmony_ci unsigned long flags; 1098419b0af8Sopenharmony_ci 1099419b0af8Sopenharmony_ci if (!dev_file) 1100419b0af8Sopenharmony_ci return; 1101419b0af8Sopenharmony_ci 1102419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 1103419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, tmp, &g_agent_control.agent_list, 1104419b0af8Sopenharmony_ci head) { 1105419b0af8Sopenharmony_ci if (event_data->owner == dev_file && i < AGENT_MAX) 1106419b0af8Sopenharmony_ci agent_id[i++] = event_data->agent_id; 1107419b0af8Sopenharmony_ci } 1108419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 1109419b0af8Sopenharmony_ci 1110419b0af8Sopenharmony_ci for (i = 0; i < AGENT_MAX; i++) { 1111419b0af8Sopenharmony_ci if (agent_id[i] != 0) 1112419b0af8Sopenharmony_ci send_event_response(agent_id[i]); 1113419b0af8Sopenharmony_ci } 1114419b0af8Sopenharmony_ci 1115419b0af8Sopenharmony_ci return; 1116419b0af8Sopenharmony_ci} 1117419b0af8Sopenharmony_ci 1118419b0af8Sopenharmony_civoid tee_agent_clear_dev_owner(const struct tc_ns_dev_file *dev_file) 1119419b0af8Sopenharmony_ci{ 1120419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 1121419b0af8Sopenharmony_ci struct smc_event_data *tmp = NULL; 1122419b0af8Sopenharmony_ci unsigned long flags; 1123419b0af8Sopenharmony_ci 1124419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 1125419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, tmp, &g_agent_control.agent_list, 1126419b0af8Sopenharmony_ci head) { 1127419b0af8Sopenharmony_ci if (event_data->owner == dev_file) { 1128419b0af8Sopenharmony_ci event_data->owner = NULL; 1129419b0af8Sopenharmony_ci break; 1130419b0af8Sopenharmony_ci } 1131419b0af8Sopenharmony_ci } 1132419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 1133419b0af8Sopenharmony_ci} 1134419b0af8Sopenharmony_ci 1135419b0af8Sopenharmony_ci 1136419b0af8Sopenharmony_cistatic int def_tee_agent_work(void *instance) 1137419b0af8Sopenharmony_ci{ 1138419b0af8Sopenharmony_ci int ret = 0; 1139419b0af8Sopenharmony_ci struct tee_agent_kernel_ops *agent_instance = NULL; 1140419b0af8Sopenharmony_ci 1141419b0af8Sopenharmony_ci agent_instance = instance; 1142419b0af8Sopenharmony_ci while (!kthread_should_stop()) { 1143419b0af8Sopenharmony_ci tlogd("%s agent loop++++\n", agent_instance->agent_name); 1144419b0af8Sopenharmony_ci ret = tc_ns_wait_event(agent_instance->agent_id); 1145419b0af8Sopenharmony_ci if (ret != 0) { 1146419b0af8Sopenharmony_ci tloge("%s wait event fail\n", 1147419b0af8Sopenharmony_ci agent_instance->agent_name); 1148419b0af8Sopenharmony_ci break; 1149419b0af8Sopenharmony_ci } 1150419b0af8Sopenharmony_ci if (agent_instance->tee_agent_work) { 1151419b0af8Sopenharmony_ci ret = agent_instance->tee_agent_work(agent_instance); 1152419b0af8Sopenharmony_ci if (ret != 0) 1153419b0af8Sopenharmony_ci tloge("%s agent work fail\n", 1154419b0af8Sopenharmony_ci agent_instance->agent_name); 1155419b0af8Sopenharmony_ci } 1156419b0af8Sopenharmony_ci ret = tc_ns_send_event_response(agent_instance->agent_id); 1157419b0af8Sopenharmony_ci if (ret != 0) { 1158419b0af8Sopenharmony_ci tloge("%s send event response fail\n", 1159419b0af8Sopenharmony_ci agent_instance->agent_name); 1160419b0af8Sopenharmony_ci break; 1161419b0af8Sopenharmony_ci } 1162419b0af8Sopenharmony_ci tlogd("%s agent loop----\n", agent_instance->agent_name); 1163419b0af8Sopenharmony_ci } 1164419b0af8Sopenharmony_ci 1165419b0af8Sopenharmony_ci return ret; 1166419b0af8Sopenharmony_ci} 1167419b0af8Sopenharmony_ci 1168419b0af8Sopenharmony_cistatic int def_tee_agent_run(struct tee_agent_kernel_ops *agent_instance) 1169419b0af8Sopenharmony_ci{ 1170419b0af8Sopenharmony_ci struct tc_ns_dev_file dev = {0}; 1171419b0af8Sopenharmony_ci int ret; 1172419b0af8Sopenharmony_ci 1173419b0af8Sopenharmony_ci /* 1. Register agent buffer to TEE */ 1174419b0af8Sopenharmony_ci ret = tc_ns_register_agent(&dev, agent_instance->agent_id, 1175419b0af8Sopenharmony_ci agent_instance->agent_buff_size, &agent_instance->agent_buff, 1176419b0af8Sopenharmony_ci false); 1177419b0af8Sopenharmony_ci if (ret != 0) { 1178419b0af8Sopenharmony_ci tloge("register agent buffer fail,ret =0x%x\n", ret); 1179419b0af8Sopenharmony_ci ret = -EINVAL; 1180419b0af8Sopenharmony_ci goto out; 1181419b0af8Sopenharmony_ci } 1182419b0af8Sopenharmony_ci 1183419b0af8Sopenharmony_ci /* 2. Creat thread to run agent */ 1184419b0af8Sopenharmony_ci agent_instance->agent_thread = 1185419b0af8Sopenharmony_ci kthread_create(def_tee_agent_work, agent_instance, 1186419b0af8Sopenharmony_ci "agent_%s", agent_instance->agent_name); 1187419b0af8Sopenharmony_ci if (IS_ERR_OR_NULL(agent_instance->agent_thread)) { 1188419b0af8Sopenharmony_ci tloge("kthread create fail\n"); 1189419b0af8Sopenharmony_ci ret = PTR_ERR(agent_instance->agent_thread); 1190419b0af8Sopenharmony_ci agent_instance->agent_thread = NULL; 1191419b0af8Sopenharmony_ci goto out; 1192419b0af8Sopenharmony_ci } 1193419b0af8Sopenharmony_ci tz_kthread_bind_mask(agent_instance->agent_thread); 1194419b0af8Sopenharmony_ci wake_up_process(agent_instance->agent_thread); 1195419b0af8Sopenharmony_ci return 0; 1196419b0af8Sopenharmony_ci 1197419b0af8Sopenharmony_ciout: 1198419b0af8Sopenharmony_ci return ret; 1199419b0af8Sopenharmony_ci} 1200419b0af8Sopenharmony_ci 1201419b0af8Sopenharmony_cistatic int def_tee_agent_stop(struct tee_agent_kernel_ops *agent_instance) 1202419b0af8Sopenharmony_ci{ 1203419b0af8Sopenharmony_ci int ret; 1204419b0af8Sopenharmony_ci 1205419b0af8Sopenharmony_ci if (tc_ns_send_event_response(agent_instance->agent_id) != 0) 1206419b0af8Sopenharmony_ci tloge("failed to send response for agent %u\n", 1207419b0af8Sopenharmony_ci agent_instance->agent_id); 1208419b0af8Sopenharmony_ci ret = tc_ns_unregister_agent(agent_instance->agent_id); 1209419b0af8Sopenharmony_ci if (ret != 0) 1210419b0af8Sopenharmony_ci tloge("failed to unregister agent %u\n", 1211419b0af8Sopenharmony_ci agent_instance->agent_id); 1212419b0af8Sopenharmony_ci if (!IS_ERR_OR_NULL(agent_instance->agent_thread)) 1213419b0af8Sopenharmony_ci kthread_stop(agent_instance->agent_thread); 1214419b0af8Sopenharmony_ci 1215419b0af8Sopenharmony_ci return 0; 1216419b0af8Sopenharmony_ci} 1217419b0af8Sopenharmony_ci 1218419b0af8Sopenharmony_cistatic struct tee_agent_kernel_ops g_def_tee_agent_ops = { 1219419b0af8Sopenharmony_ci .agent_name = "default", 1220419b0af8Sopenharmony_ci .agent_id = 0, 1221419b0af8Sopenharmony_ci .tee_agent_init = NULL, 1222419b0af8Sopenharmony_ci .tee_agent_run = def_tee_agent_run, 1223419b0af8Sopenharmony_ci .tee_agent_work = NULL, 1224419b0af8Sopenharmony_ci .tee_agent_exit = NULL, 1225419b0af8Sopenharmony_ci .tee_agent_stop = def_tee_agent_stop, 1226419b0af8Sopenharmony_ci .tee_agent_crash_work = NULL, 1227419b0af8Sopenharmony_ci .agent_buff_size = PAGE_SIZE, 1228419b0af8Sopenharmony_ci .list = LIST_HEAD_INIT(g_def_tee_agent_ops.list) 1229419b0af8Sopenharmony_ci}; 1230419b0af8Sopenharmony_ci 1231419b0af8Sopenharmony_cistatic int tee_agent_kernel_init(void) 1232419b0af8Sopenharmony_ci{ 1233419b0af8Sopenharmony_ci struct tee_agent_kernel_ops *agent_ops = NULL; 1234419b0af8Sopenharmony_ci int ret = 0; 1235419b0af8Sopenharmony_ci 1236419b0af8Sopenharmony_ci list_for_each_entry(agent_ops, &g_tee_agent_list, list) { 1237419b0af8Sopenharmony_ci /* Check the agent validity */ 1238419b0af8Sopenharmony_ci if (!agent_ops->agent_id || 1239419b0af8Sopenharmony_ci !agent_ops->agent_name || 1240419b0af8Sopenharmony_ci !agent_ops->tee_agent_work) { 1241419b0af8Sopenharmony_ci tloge("agent is invalid\n"); 1242419b0af8Sopenharmony_ci continue; 1243419b0af8Sopenharmony_ci } 1244419b0af8Sopenharmony_ci tlogd("ready to init %s agent, id=0x%x\n", 1245419b0af8Sopenharmony_ci agent_ops->agent_name, agent_ops->agent_id); 1246419b0af8Sopenharmony_ci 1247419b0af8Sopenharmony_ci /* Set agent buff size */ 1248419b0af8Sopenharmony_ci if (!agent_ops->agent_buff_size) 1249419b0af8Sopenharmony_ci agent_ops->agent_buff_size = 1250419b0af8Sopenharmony_ci g_def_tee_agent_ops.agent_buff_size; 1251419b0af8Sopenharmony_ci 1252419b0af8Sopenharmony_ci /* Initialize the agent */ 1253419b0af8Sopenharmony_ci if (agent_ops->tee_agent_init) 1254419b0af8Sopenharmony_ci ret = agent_ops->tee_agent_init(agent_ops); 1255419b0af8Sopenharmony_ci else if (g_def_tee_agent_ops.tee_agent_init) 1256419b0af8Sopenharmony_ci ret = g_def_tee_agent_ops.tee_agent_init(agent_ops); 1257419b0af8Sopenharmony_ci else 1258419b0af8Sopenharmony_ci tlogw("agent id %u has no init function\n", 1259419b0af8Sopenharmony_ci agent_ops->agent_id); 1260419b0af8Sopenharmony_ci if (ret != 0) { 1261419b0af8Sopenharmony_ci tloge("tee_agent_init %s failed\n", 1262419b0af8Sopenharmony_ci agent_ops->agent_name); 1263419b0af8Sopenharmony_ci continue; 1264419b0af8Sopenharmony_ci } 1265419b0af8Sopenharmony_ci 1266419b0af8Sopenharmony_ci /* Run the agent */ 1267419b0af8Sopenharmony_ci if (agent_ops->tee_agent_run) 1268419b0af8Sopenharmony_ci ret = agent_ops->tee_agent_run(agent_ops); 1269419b0af8Sopenharmony_ci else if (g_def_tee_agent_ops.tee_agent_run) 1270419b0af8Sopenharmony_ci ret = g_def_tee_agent_ops.tee_agent_run(agent_ops); 1271419b0af8Sopenharmony_ci else 1272419b0af8Sopenharmony_ci tlogw("agent id %u has no run function\n", 1273419b0af8Sopenharmony_ci agent_ops->agent_id); 1274419b0af8Sopenharmony_ci 1275419b0af8Sopenharmony_ci if (ret != 0) { 1276419b0af8Sopenharmony_ci tloge("tee_agent_run %s failed\n", 1277419b0af8Sopenharmony_ci agent_ops->agent_name); 1278419b0af8Sopenharmony_ci if (agent_ops->tee_agent_exit) 1279419b0af8Sopenharmony_ci agent_ops->tee_agent_exit(agent_ops); 1280419b0af8Sopenharmony_ci continue; 1281419b0af8Sopenharmony_ci } 1282419b0af8Sopenharmony_ci } 1283419b0af8Sopenharmony_ci 1284419b0af8Sopenharmony_ci return 0; 1285419b0af8Sopenharmony_ci} 1286419b0af8Sopenharmony_ci 1287419b0af8Sopenharmony_cistatic void tee_agent_kernel_exit(void) 1288419b0af8Sopenharmony_ci{ 1289419b0af8Sopenharmony_ci struct tee_agent_kernel_ops *agent_ops = NULL; 1290419b0af8Sopenharmony_ci 1291419b0af8Sopenharmony_ci list_for_each_entry(agent_ops, &g_tee_agent_list, list) { 1292419b0af8Sopenharmony_ci /* Stop the agent */ 1293419b0af8Sopenharmony_ci if (agent_ops->tee_agent_stop) 1294419b0af8Sopenharmony_ci agent_ops->tee_agent_stop(agent_ops); 1295419b0af8Sopenharmony_ci else if (g_def_tee_agent_ops.tee_agent_stop) 1296419b0af8Sopenharmony_ci g_def_tee_agent_ops.tee_agent_stop(agent_ops); 1297419b0af8Sopenharmony_ci else 1298419b0af8Sopenharmony_ci tlogw("agent id %u has no stop function\n", 1299419b0af8Sopenharmony_ci agent_ops->agent_id); 1300419b0af8Sopenharmony_ci 1301419b0af8Sopenharmony_ci /* Uninitialize the agent */ 1302419b0af8Sopenharmony_ci if (agent_ops->tee_agent_exit) 1303419b0af8Sopenharmony_ci agent_ops->tee_agent_exit(agent_ops); 1304419b0af8Sopenharmony_ci else if (g_def_tee_agent_ops.tee_agent_exit) 1305419b0af8Sopenharmony_ci g_def_tee_agent_ops.tee_agent_exit(agent_ops); 1306419b0af8Sopenharmony_ci else 1307419b0af8Sopenharmony_ci tlogw("agent id %u has no exit function\n", 1308419b0af8Sopenharmony_ci agent_ops->agent_id); 1309419b0af8Sopenharmony_ci } 1310419b0af8Sopenharmony_ci} 1311419b0af8Sopenharmony_ci 1312419b0af8Sopenharmony_ciint tee_agent_clear_work(struct tc_ns_client_context *context, 1313419b0af8Sopenharmony_ci unsigned int dev_file_id) 1314419b0af8Sopenharmony_ci{ 1315419b0af8Sopenharmony_ci struct tee_agent_kernel_ops *agent_ops = NULL; 1316419b0af8Sopenharmony_ci 1317419b0af8Sopenharmony_ci list_for_each_entry(agent_ops, &g_tee_agent_list, list) { 1318419b0af8Sopenharmony_ci if (agent_ops->tee_agent_crash_work) 1319419b0af8Sopenharmony_ci agent_ops->tee_agent_crash_work(agent_ops, 1320419b0af8Sopenharmony_ci context, dev_file_id); 1321419b0af8Sopenharmony_ci } 1322419b0af8Sopenharmony_ci return 0; 1323419b0af8Sopenharmony_ci} 1324419b0af8Sopenharmony_ci 1325419b0af8Sopenharmony_ciint tee_agent_kernel_register(struct tee_agent_kernel_ops *new_agent) 1326419b0af8Sopenharmony_ci{ 1327419b0af8Sopenharmony_ci if (!new_agent) 1328419b0af8Sopenharmony_ci return -EINVAL; 1329419b0af8Sopenharmony_ci 1330419b0af8Sopenharmony_ci INIT_LIST_HEAD(&new_agent->list); 1331419b0af8Sopenharmony_ci list_add_tail(&new_agent->list, &g_tee_agent_list); 1332419b0af8Sopenharmony_ci 1333419b0af8Sopenharmony_ci return 0; 1334419b0af8Sopenharmony_ci} 1335419b0af8Sopenharmony_ci 1336419b0af8Sopenharmony_civoid agent_init(void) 1337419b0af8Sopenharmony_ci{ 1338419b0af8Sopenharmony_ci spin_lock_init(&g_agent_control.lock); 1339419b0af8Sopenharmony_ci INIT_LIST_HEAD(&g_agent_control.agent_list); 1340419b0af8Sopenharmony_ci INIT_LIST_HEAD(&g_tee_agent_list); 1341419b0af8Sopenharmony_ci 1342419b0af8Sopenharmony_ci rpmb_agent_register(); 1343419b0af8Sopenharmony_ci#if defined(CONFIG_MM_VLTMM) || defined(CONFIG_MEMORY_VLTMM) 1344419b0af8Sopenharmony_ci (void)vltmm_agent_register(); 1345419b0af8Sopenharmony_ci#endif 1346419b0af8Sopenharmony_ci if (tee_agent_kernel_init()) 1347419b0af8Sopenharmony_ci tloge("tee agent kernel init failed\n"); 1348419b0af8Sopenharmony_ci return; 1349419b0af8Sopenharmony_ci} 1350419b0af8Sopenharmony_ci 1351419b0af8Sopenharmony_civoid free_agent(void) 1352419b0af8Sopenharmony_ci{ 1353419b0af8Sopenharmony_ci struct smc_event_data *event_data = NULL; 1354419b0af8Sopenharmony_ci struct smc_event_data *temp = NULL; 1355419b0af8Sopenharmony_ci unsigned long flags; 1356419b0af8Sopenharmony_ci 1357419b0af8Sopenharmony_ci tee_agent_kernel_exit(); 1358419b0af8Sopenharmony_ci 1359419b0af8Sopenharmony_ci spin_lock_irqsave(&g_agent_control.lock, flags); 1360419b0af8Sopenharmony_ci list_for_each_entry_safe(event_data, temp, &g_agent_control.agent_list, head) { 1361419b0af8Sopenharmony_ci list_del(&event_data->head); 1362419b0af8Sopenharmony_ci unmap_agent_buffer(event_data); 1363419b0af8Sopenharmony_ci mailbox_free(event_data->agent_buff_kernel); 1364419b0af8Sopenharmony_ci event_data->agent_buff_kernel = NULL; 1365419b0af8Sopenharmony_ci kfree(event_data); 1366419b0af8Sopenharmony_ci } 1367419b0af8Sopenharmony_ci spin_unlock_irqrestore(&g_agent_control.lock, flags); 1368419b0af8Sopenharmony_ci} 1369