• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
303 }
304