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(&current->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(&current->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