1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include "drv.h"
14 #include <errno.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <securec.h>
18 #include <ipclib.h>
19 #include <unistd.h>
20 #include <tee_log.h>
21 #include <pthread.h>
22 #include <tee_config.h>
23 #include "tee_msg_type.h"
24
25 #define DRIVER_FRAME_NR 10U
26 #define MAX_DRV_NAME_LEN 32
27 #define ARGS_NUM 16
28
29 struct drv_op_info {
30 char name[MAX_DRV_NAME_LEN];
31 cref_t channel;
32 bool is_tbac_hooked;
33 };
34
35 static struct drv_op_info g_drv_op_info[DRIVER_FRAME_NR];
36 static uint32_t g_drv_frame_count;
37 static pthread_mutex_t g_framp_op_mutex = PTHREAD_MUTEX_INITIALIZER;
38
mutex_lock_ops(pthread_mutex_t * mtx)39 static int32_t mutex_lock_ops(pthread_mutex_t *mtx)
40 {
41 int32_t ret = pthread_mutex_lock(mtx);
42 if (ret == EOWNERDEAD) /* owner died, use consistent to recover and lock the mutex */
43 return pthread_mutex_consistent(mtx);
44
45 return ret;
46 }
47
mutex_unlock_ops(pthread_mutex_t * mtx)48 static void mutex_unlock_ops(pthread_mutex_t *mtx)
49 {
50 int32_t ret = pthread_mutex_unlock(mtx);
51 if (ret != 0)
52 tloge("mutex unlock failed with ret %d\n", ret);
53 }
54
is_valid_name(const char * name)55 static bool is_valid_name(const char *name)
56 {
57 if (name == NULL) {
58 tloge("name is NULL\n");
59 return false;
60 }
61
62 if (strnlen(name, MAX_DRV_NAME_LEN) == MAX_DRV_NAME_LEN) {
63 tloge("name len is too long\n");
64 return false;
65 }
66
67 return true;
68 }
69
get_info_idex_by_name(const char * name)70 static int32_t get_info_idex_by_name(const char *name)
71 {
72 uint32_t i;
73
74 if (mutex_lock_ops(&g_framp_op_mutex) != 0) {
75 tloge("mutex lock failed\n");
76 return -1;
77 }
78
79 for (i = 0; i <= g_drv_frame_count; i++) {
80 if (strncmp(name, g_drv_op_info[i].name, strlen(name) + 1) == 0) { /* check \0 */
81 mutex_unlock_ops(&g_framp_op_mutex);
82 return (int32_t)i;
83 }
84 }
85
86 mutex_unlock_ops(&g_framp_op_mutex);
87 return -1;
88 }
89
drv_init(const char * name)90 int32_t drv_init(const char *name)
91 {
92 int32_t rc = -1;
93 struct drv_op_info *op_info = NULL;
94
95 /* check arg */
96 if (!is_valid_name(name))
97 return rc;
98
99 if (mutex_lock_ops(&g_framp_op_mutex) != 0) {
100 tloge("mutex lock failed\n");
101 return rc;
102 }
103
104 if (g_drv_frame_count >= DRIVER_FRAME_NR) {
105 tloge("drv frame count overflow: %u\n", g_drv_frame_count);
106 goto unlock_out;
107 }
108
109 op_info = &g_drv_op_info[g_drv_frame_count];
110
111 /* get channel according to path */
112 rc = ipc_get_ch_from_path(name, &op_info->channel);
113 if (rc != 0) {
114 tloge("libdrv: get channel from pathmgr failed: %d\n", rc);
115 goto unlock_out;
116 }
117
118 if (memcpy_s(op_info->name, MAX_DRV_NAME_LEN, name, strlen(name)) != EOK) {
119 tloge("libdrv: %s memcpy name failed\n", name);
120 (void)memset_s(op_info->name, MAX_DRV_NAME_LEN, 0, MAX_DRV_NAME_LEN);
121 rc = -1;
122 goto unlock_out;
123 }
124
125 g_drv_frame_count++;
126 tlogd("libdrv: init ok for pid %d with s_rslot=0x%llx\n", getpid(), op_info->channel);
127
128 unlock_out:
129 mutex_unlock_ops(&g_framp_op_mutex);
130 return rc;
131 }
132
try_get_info_idex(const char * name)133 static int32_t try_get_info_idex(const char *name)
134 {
135 int32_t idex;
136
137 idex = get_info_idex_by_name(name);
138 if (idex < 0) {
139 if (drv_init(name) != 0) {
140 tloge("%s init failed\n", name);
141 return -1;
142 }
143
144 idex = get_info_idex_by_name(name);
145 if (idex < 0) {
146 tloge("%s failed to find info\n", name);
147 return -1;
148 }
149 }
150 return idex;
151 }
152
param_check(const char * name,struct drv_call_params * params,int32_t * idex)153 static int32_t param_check(const char *name, struct drv_call_params *params, int32_t *idex)
154 {
155 if (params == NULL || !is_valid_name(name)) {
156 tloge("invalid arguments\n");
157 return -1;
158 }
159
160 if ((params->nr < 0) || (params->nr > ARGS_NUM)) {
161 tloge("drv_call: invalid arguments\n");
162 return -1;
163 }
164
165 if ((params->nr != 0) && (params->args == NULL)) {
166 tloge("drv call nr and args not match\n");
167 return -1;
168 }
169
170 if ((params->rdata == NULL && params->rdata_len != 0) ||
171 (params->rdata != NULL && params->rdata_len == 0)) {
172 tloge("drv_call: bad rdata or rdata_len\n");
173 return -1;
174 }
175
176 *idex = try_get_info_idex(name);
177 if (*idex < 0) {
178 tloge("invalid idex, please check\n");
179 return -1;
180 }
181
182 return 0;
183 }
184
length_invalid(uint32_t ext_data_len,uint32_t rdata_len,uint32_t max_len)185 static int32_t length_invalid(uint32_t ext_data_len, uint32_t rdata_len, uint32_t max_len)
186 {
187 if ((ext_data_len + sizeof(struct drv_req_msg_t) < ext_data_len) ||
188 (sizeof(struct drv_req_msg_t) + ext_data_len > max_len) ||
189 (rdata_len + sizeof(struct drv_reply_msg_t) < rdata_len) ||
190 (sizeof(struct drv_reply_msg_t) + rdata_len > max_len))
191 return -1;
192
193 return 0;
194 }
195
calc_ext_data_len(const struct drv_call_params * params,uint32_t buf_size,uint32_t * ext_data_len)196 static int32_t calc_ext_data_len(const struct drv_call_params *params, uint32_t buf_size,
197 uint32_t *ext_data_len)
198 {
199 *ext_data_len = 0;
200 /* allocate memory for req/reply, alloc ext data for both req&reply */
201 if (params->lens != NULL) {
202 for (int32_t i = 0; i < params->nr; i++) {
203 /* data is 8-bytes aligned */
204 if (*ext_data_len + params->lens[i] < *ext_data_len) {
205 tloge("lens is overflow! lens[%d]=0x%x\n", i, params->lens[i]);
206 return -1;
207 }
208 *ext_data_len += params->lens[i];
209 }
210 }
211
212 if (length_invalid(*ext_data_len, params->rdata_len, buf_size) != 0) {
213 tloge("Oops, ext_data or rdata too long len=0x%x rlen=0x%x\n", *ext_data_len, params->rdata_len);
214 return -1;
215 }
216
217 return 0;
218 }
219
calc_ext_data_offset(struct drv_req_msg_t * msg,const struct drv_call_params * params,uint32_t ext_data_len)220 static int32_t calc_ext_data_offset(struct drv_req_msg_t *msg, const struct drv_call_params *params,
221 uint32_t ext_data_len)
222 {
223 uint32_t ext_remained;
224 char *ext_ptr = msg->data;
225
226 ext_remained = ext_data_len;
227 for (int32_t i = 0; i < params->nr; i++) {
228 if ((params->lens == NULL) || params->lens[i] == 0) {
229 msg->args[i] = params->args[i];
230 } else {
231 if ((void *)((uintptr_t)params->args[i]) == NULL) {
232 tloge("drv args %d is NULL, please check\n", i);
233 return -1;
234 }
235
236 if (memcpy_s(ext_ptr, ext_remained, (void *)((uintptr_t)params->args[i]), params->lens[i]) != EOK) {
237 tloge("drv copy failed\n");
238 return -1;
239 }
240 msg->args[i] = (uintptr_t)(ext_ptr - msg->data);
241 ext_ptr += params->lens[i];
242 ext_remained -= params->lens[i];
243 }
244 }
245
246 return 0;
247 }
248
249
drv_call_ex_new(const char * name,uint16_t id,struct drv_call_params * params)250 static int64_t drv_call_ex_new(const char *name, uint16_t id, struct drv_call_params *params)
251 {
252 char buf[SYSCAL_MSG_BUFFER_SIZE] = { 0 };
253 uint32_t ext_data_len;
254 int32_t idex;
255 /* msg_xfer_send_has_recv could handle send_buf and recv_buf point to the same addr */
256 struct drv_req_msg_t *msg = (struct drv_req_msg_t *)buf;
257 struct drv_reply_msg_t *rmsg = (struct drv_reply_msg_t *)buf;
258 int64_t func_ret = -1;
259
260 if (param_check(name, params, &idex) != 0)
261 return -1;
262
263 int32_t ret = calc_ext_data_len(params, sizeof(buf), &ext_data_len);
264 if (ret != 0)
265 return -1;
266
267 msg->header.send.msg_class = 0;
268 msg->header.send.msg_flags = 0;
269 msg->header.send.msg_id = id;
270 msg->header.send.msg_size = sizeof(struct drv_req_msg_t) + ext_data_len;
271
272 if (calc_ext_data_offset(msg, params, ext_data_len) != 0)
273 goto err_msg_call;
274
275 ret = ipc_msg_call(g_drv_op_info[idex].channel, msg, msg->header.send.msg_size, rmsg,
276 sizeof(struct drv_req_msg_t) + params->rdata_len, -1);
277 if (ret != 0) {
278 tloge("drv_call: ipc msg call 0x%llx failed: %d\n", (unsigned long long)g_drv_op_info[idex].channel, ret);
279 goto err_msg_call;
280 }
281
282 if (params->rdata != NULL) {
283 if (memcpy_s(params->rdata, params->rdata_len, rmsg->rdata, params->rdata_len) != EOK) {
284 tloge("memcpy rdata failed\n");
285 goto err_msg_call;
286 }
287 }
288
289 func_ret = rmsg->header.reply.ret_val;
290
291 err_msg_call:
292
293 return func_ret;
294 }
295
drv_call_new(const char * name,uint16_t id,uint64_t * args,uint32_t * lens,int32_t nr)296 int64_t drv_call_new(const char *name, uint16_t id, uint64_t *args, uint32_t *lens, int32_t nr)
297 {
298 struct drv_call_params params = {
299 args, lens, nr, NULL, 0
300 };
301
302 return drv_call_ex_new(name, id, ¶ms);
303 }
304