• 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 <stddef.h>
14 #include <tee_config.h>
15 #include "securec.h"
16 #include "ta_framework.h"
17 #include "gtask_inner.h"
18 #include "mem_manager.h"
19 #include "session_manager.h"
20 #include "agent_manager.h"
21 #include "service_manager.h"
22 #include "global_task.h"
23 #include "tee_log.h"
24 #include "tee_app_load_srv.h"
25 #include "tee_property_api.h"
26 #include "timer_export.h"
27 #include <teecall.h>
28 #include "tee_init.h"
29 #include <string.h>
30 #include <ipclib.h>
31 #include "init.h"
32 #include "initlib.h"
33 #include "gtask_config.h"
34 
35 #include "gtask_adapt.h"
36 #include "dynload.h"
37 #include "task_adaptor_pub.h"
38 #include "tee_property_inner.h"
39 #include "tee_ext_api.h"
40 #include "tee_task_exception.h"
41 #include "tee_ns_cmd_dispatch.h"
42 #include "tee_s_cmd_dispatch.h"
43 #include "tee_compat_check.h"
44 #include "tee_load_lib.h"
45 #include <ipclib_hal.h>
46 #include <usrsyscall_irq.h>
47 #include <sched.h>
48 
49 #define GT_MSG_REV_SIZE 512
50 
51 /* From 1970 to 2050 */
52 #define SYSTIME_SET_MAX            ((2050U - 1970U) * 365U * 24U * 60U * 60U)
53 #define PHY_ADDR_HIGHER_BITS_INDEX 3
54 #define PHY_ADDR_LOWER_BITS_INDEX  1
55 #define SMC_CMD_RESULT_INDEX       0
56 #define SMC_CMD_ADDR_INDEX         1
57 #define SMC_CMD_TYPE_INDEX         2
58 #define SMC_CMD_ADDR_TRANS_INDEX   3
59 
60 static kernel_shared_varibles_t g_k_variables;
61 
62 static nwd_cmd_t *g_nwd_cmd = NULL;
63 
64 /* It can be modified only by gtask, we can use it to check if the bitmap
65  * in g_nwd_cmd is right. */
66 static DECLEAR_BITMAP(cmd_doing_bitmap, MAX_SMC_CMD);
67 
68 static bool g_systime_set_flag = false;
69 
acquire_smc_buf_lock(uint32_t * lock)70 static void acquire_smc_buf_lock(uint32_t *lock)
71 {
72     int rc;
73     rc = disable_local_irq();
74     if (rc != 0)
75         tee_abort("disable_local_irq failed: %x\n", rc);
76     do
77         rc = __sync_bool_compare_and_swap(lock, 0, 1);
78     while (!rc);
79     asm volatile("dmb sy");
80 }
81 
release_smc_buf_lock(uint32_t * lock)82 static void release_smc_buf_lock(uint32_t *lock)
83 {
84     int rc;
85     asm volatile("dmb sy");
86     *lock = 0;
87     asm volatile("dmb sy");
88     rc = enable_local_irq();
89     if (rc != 0)
90         tee_abort("enable_local_irq failed: %x\n", rc);
91 }
92 
93 /*
94  * start internal service tasks
95  */
init_internal_tasks(void)96 static void init_internal_tasks(void)
97 {
98     /* load all internal tasks */
99     load_internal_task(LOAD_ALL_TASKS);
100 
101     task_adapt_init();
102 }
103 
104 /*
105  * setup smc cmd shared mem for TEE
106  */
init_smc_cmd_mem(void)107 static void init_smc_cmd_mem(void)
108 {
109     bool init_done = false;
110     int ret;
111 
112     /* Setup the shared buffer for communication
113      * between tzdriver and global task */
114     while (!init_done) {
115         (void)ipc_msg_rcv(OS_WAIT_FOREVER, (uint32_t *)NULL, NULL, 0);
116 
117         tlogd("initializing...\n");
118         /* the smc cmd mem setup params from REE received */
119         ret = tee_pull_kernel_variables(&g_k_variables);
120         if (ret != 0) {
121             tloge("pullKernelVariables failed...\n");
122             continue;
123         }
124 
125         tlogd("init cmd: 0x%x 0x%x 0x%llx...\n", g_k_variables.params_stack[SMC_CMD_ADDR_INDEX],
126               g_k_variables.params_stack[SMC_CMD_TYPE_INDEX], g_k_variables.params_stack[SMC_CMD_ADDR_TRANS_INDEX]);
127 
128         /* setup the smc cmd mem in TEE */
129         if (g_k_variables.params_stack[SMC_CMD_TYPE_INDEX] == CMD_TYPE_SECURE_CONFIG) {
130             /* init g_nwd_cmd */
131             paddr_t tmp_phy = g_k_variables.params_stack[PHY_ADDR_LOWER_BITS_INDEX] |
132                               ((paddr_t)g_k_variables.params_stack[PHY_ADDR_HIGHER_BITS_INDEX] << SHIFT_OFFSET);
133             g_nwd_cmd = map_ns_cmd(tmp_phy);
134             if (g_nwd_cmd == NULL) {
135                 tloge("map ns memory failed\n");
136                 continue;
137             }
138 
139             init_done                       = true;
140         }
141     }
142 }
143 
setup_init_info(void)144 static void setup_init_info(void)
145 {
146     generate_teeos_compat_level(((uint32_t *)(void *)g_nwd_cmd->in),
147         COMPAT_LEVEL_BUF_LEN);
148 }
149 
is_abort_cmd(const smc_cmd_t * cmd)150 bool is_abort_cmd(const smc_cmd_t *cmd)
151 {
152     if (cmd == NULL)
153         return false;
154 
155     if (cmd->cmd_type == CMD_TYPE_GLOBAL && cmd->cmd_id == GLOBAL_CMD_ID_KILL_TASK)
156         return true;
157 
158     return false;
159 }
160 
restore_cmd_in(const smc_cmd_t * cmd)161 void restore_cmd_in(const smc_cmd_t *cmd)
162 {
163     uint32_t index;
164 
165     if (cmd == NULL)
166         return;
167 
168     index = cmd->event_nr;
169     if (index >= MAX_SMC_CMD) {
170         tloge("invalid idex: %u\n", index);
171         return;
172     }
173 
174     acquire_smc_buf_lock(&g_nwd_cmd->smc_lock);
175     if (index != g_nwd_cmd->in[index].event_nr) {
176         tloge("event_nr not match, %u/%u\n", index, g_nwd_cmd->in[index].event_nr);
177         release_smc_buf_lock(&g_nwd_cmd->smc_lock);
178         return;
179     }
180 
181     if (memcpy_s(&g_nwd_cmd->in[index], sizeof(smc_cmd_t), cmd, sizeof(smc_cmd_t)) != EOK)
182         tloge("copy restore cmd failed\n");
183     release_smc_buf_lock(&g_nwd_cmd->smc_lock);
184 }
185 
get_last_in_cmd(smc_cmd_t * cmd)186 static int get_last_in_cmd(smc_cmd_t *cmd)
187 {
188     errno_t rc = EOK;
189     int ret    = GT_ERR_END_CMD;
190     static uint32_t last_index = MAX_SMC_CMD;
191     uint32_t i = last_index;
192 
193     acquire_smc_buf_lock(&g_nwd_cmd->smc_lock);
194     do {
195         if (i == MAX_SMC_CMD)
196             i = 0;
197         if (test_bit(i, g_nwd_cmd->in_bitmap) && !test_bit(i, g_nwd_cmd->doing_bitmap)) {
198             if (test_bit(i, cmd_doing_bitmap) && !is_abort_cmd(&g_nwd_cmd->in[i])) {
199                 /* in this case, maybe the in_bitmap/doing_bitmap in g_nwd_cmd
200                  * was modified by malicious, so we will skip this cmd. */
201                 tloge("find a unreasonable in-cmd, cmd id=0x%x, cmd type=%u\n",
202                     g_nwd_cmd->in[i].cmd_id, g_nwd_cmd->in[i].cmd_type);
203                 set_bit(i, g_nwd_cmd->doing_bitmap);
204                 /* skip this cmd */
205                 continue;
206             }
207 
208             rc = memcpy_s(cmd, sizeof(smc_cmd_t), &g_nwd_cmd->in[i], sizeof(smc_cmd_t));
209             if (rc != EOK) {
210                 break;
211             }
212 
213             /* check if cmd->event_nr is compatible the index in bitmap */
214             if (cmd->event_nr != i) {
215                 tloge("it's a invalid cmd, event_nr/bitmap=%u/%u\n", cmd->event_nr, i);
216                 set_bit(i, g_nwd_cmd->doing_bitmap);
217                 /* skip this cmd */
218                 continue;
219             }
220 
221             __asm__ volatile("isb");
222             __asm__ volatile("dsb sy");
223             set_bit(i, g_nwd_cmd->doing_bitmap);
224             if (!is_abort_cmd(&g_nwd_cmd->in[i]))
225                 set_bit(i, cmd_doing_bitmap);
226 
227             last_index = i + 1;
228             ret = GT_ERR_OK;
229             break;
230         }
231         i++;
232     } while (i != last_index);
233     release_smc_buf_lock(&g_nwd_cmd->smc_lock);
234     if (rc != EOK) {
235         tloge("memcopy in cmd failed\n");
236         ret = GT_ERR_END_CMD;
237     }
238     if (cmd->event_nr >= MAX_SMC_CMD) {
239         tloge("invalid event_nr: %u\n", cmd->event_nr);
240         ret = GT_ERR_END_CMD;
241     }
242 
243     return ret;
244 }
245 
put_last_out_cmd(const smc_cmd_t * cmd)246 int put_last_out_cmd(const smc_cmd_t *cmd)
247 {
248     errno_t rc;
249 
250     if (cmd == NULL)
251         return GT_ERR_END_CMD;
252 
253     if (cmd->event_nr >= MAX_SMC_CMD) {
254         tloge("invalid event_nr: %u\n", cmd->event_nr);
255         return GT_ERR_END_CMD;
256     }
257     /* when ta session return to REE, need to umap ca2ta releation; otherwise when ca crash may kill wrong ta session */
258     if ((cmd->ret_val != TEE_PENDING) && (cmd->ret_val != TEE_PENDING2)) {
259         if (g_cur_session != NULL)
260             g_cur_session->cmd_in.ca_pid = 0;
261     }
262     acquire_smc_buf_lock(&g_nwd_cmd->smc_lock);
263 
264     rc = memcpy_s(&g_nwd_cmd->out[cmd->event_nr], sizeof(smc_cmd_t), cmd, sizeof(smc_cmd_t));
265     if (rc != EOK) {
266         release_smc_buf_lock(&g_nwd_cmd->smc_lock);
267         tloge("memcpy out cmd failed\n");
268         return GT_ERR_END_CMD;
269     }
270     __asm__ volatile("isb");
271     __asm__ volatile("dsb sy");
272     set_bit(cmd->event_nr, g_nwd_cmd->out_bitmap);
273     clear_bit(cmd->event_nr, cmd_doing_bitmap);
274     release_smc_buf_lock(&g_nwd_cmd->smc_lock);
275 
276     return GT_ERR_OK;
277 }
278 
ns_cmd_response(smc_cmd_t * cmd)279 void ns_cmd_response(smc_cmd_t *cmd)
280 {
281     if (cmd == NULL)
282         return;
283 
284     if (cmd->ret_val != TEE_PENDING) {
285         TEE_Result ret = copy_pam_to_src(cmd->cmd_id, false);
286         if (ret != TEE_SUCCESS)
287             cmd->ret_val = ret;
288 
289         ret = unmap_ns_operation(cmd);
290         if (ret != TEE_SUCCESS)
291             tloge("ns cmd unmap ns fail:%08X\n", ret);
292     }
293 
294     errno_t ret_i = put_last_out_cmd(cmd);
295     if (ret_i != GT_ERR_OK)
296         tloge("ns cmd put fail:%d\n", ret_i);
297 }
298 
handle_time_adjust(const smc_cmd_t * cmd)299 TEE_Result handle_time_adjust(const smc_cmd_t *cmd)
300 {
301     TEE_Result ret;
302     tee_time_kernel time;
303     uint32_t param_type = 0;
304     TEE_Param *params = NULL;
305 
306     if (cmd == NULL)
307         return TEE_ERROR_BAD_PARAMETERS;
308 
309     if (g_systime_set_flag) {
310         tlogd("The time seems already been adjusted");
311         return TEE_SUCCESS;
312     }
313 
314     if (cmd_global_ns_get_params(cmd, &param_type, &params) != TEE_SUCCESS) {
315         tloge("cmd_global_ns_get_params failed");
316         return TEE_ERROR_BAD_PARAMETERS;
317     }
318 
319     if (params == NULL)
320         return TEE_ERROR_BAD_PARAMETERS;
321 
322     time.seconds = (int32_t)params->value.a;
323     time.millis = (int32_t)params->value.b;
324     if ((uint32_t)time.seconds <= SYSTIME_SET_MAX) {
325 #ifdef CONFIG_OFF_DRV_TIMER
326         ret = teecall_cap_time_sync(time.seconds, time.millis);
327 #else
328         ret = adjust_sys_time(&time);
329 #endif
330         if (ret != TEE_SUCCESS)
331             return ret;
332 
333         g_systime_set_flag = true;
334     } else {
335         tloge("time adjust failed\n");
336         ret = TEE_ERROR_GENERIC;
337     }
338 
339     return ret;
340 }
341 
342 /*
343  * handle open_session cmds which is called from process_ta_common_cmd
344  * just for Complexity check.
345  * DO NOT USE this func in anyother situations.
346  */
347 extern struct service_struct *g_cur_service;
processs_opensession(smc_cmd_t * cmd,uint32_t cmd_type,uint32_t task_id,bool * async,const struct ta2ta_info_t * ta2ta_info)348 static TEE_Result processs_opensession(smc_cmd_t *cmd, uint32_t cmd_type, uint32_t task_id, bool *async,
349                                        const struct ta2ta_info_t *ta2ta_info)
350 {
351     TEE_Result ret;
352     uint32_t userid = 0;
353 
354     ret = open_session(cmd, cmd_type, task_id, ta2ta_info);
355     if (ret == TEE_SUCCESS) {
356         *async = true;
357 
358         if (g_cur_session->cmd_type == CMD_TYPE_NS_TO_SECURE) {
359             /*
360              * here restore cmd is to save cmd->context, if TA open session is stuck,
361              * we need context to find the stuck session to kill TA
362              */
363             restore_cmd_in(cmd);
364 
365             userid = g_cur_session->cmd_in.uid / PER_USER_RANGE;
366         }
367 
368         task_adapt_register_ta(g_cur_session->task_id, userid, g_cur_service->property.ssa_enum_enable,
369                                &g_cur_service->property.uuid);
370     }
371 
372     return ret;
373 }
374 
375 /*
376  * handle both ca2ta and ta2ta cmds
377  */
process_ta_common_cmd(smc_cmd_t * cmd,uint32_t cmd_type,uint32_t task_id,bool * async,const struct ta2ta_info_t * ta2ta_info)378 TEE_Result process_ta_common_cmd(smc_cmd_t *cmd, uint32_t cmd_type, uint32_t task_id, bool *async,
379                                  const struct ta2ta_info_t *ta2ta_info)
380 {
381     TEE_Result ret;
382     bool sync = false;
383     uint32_t cmd_id;
384 
385     if (cmd == NULL || async == NULL)
386         return TEE_ERROR_BAD_PARAMETERS;
387 
388     cmd_id = cmd->cmd_id;
389     switch (cmd_id) {
390     case GLOBAL_CMD_ID_OPEN_SESSION:
391         if (cmd_type == CMD_TYPE_SECURE_TO_SECURE) {
392             tlogd("ta2ta is running\n");
393             if (g_cur_service == NULL) {
394                 tloge("cur service is null\n");
395                 return TEE_ERROR_BAD_PARAMETERS;
396             }
397         }
398         ret = processs_opensession(cmd, cmd_type, task_id, async, ta2ta_info);
399         break;
400     case GLOBAL_CMD_ID_CLOSE_SESSION:
401         ret = close_session(cmd, cmd_type, &sync);
402         if (ret == TEE_SUCCESS && false == sync)
403             *async = true;
404         break;
405     default:
406         ret = TEE_ERROR_INVALID_CMD;
407         break;
408     }
409 
410     return ret;
411 }
412 
tee_get_max_api_level(void)413 static uint32_t tee_get_max_api_level(void)
414 {
415     uint32_t value = 0;
416 
417     if (TEE_GetPropertyAsU32(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.api_level", &value) != TEE_SUCCESS)
418         return TEE_MAX_API_LEVEL_CONFIG;
419 
420     return value;
421 }
422 
get_tee_version(const smc_cmd_t * cmd)423 TEE_Result get_tee_version(const smc_cmd_t *cmd)
424 {
425     unsigned int version;
426     uint32_t param_type  = 0;
427     TEE_Param *params    = NULL;
428 
429     if (cmd == NULL)
430         return TEE_ERROR_BAD_PARAMETERS;
431 
432     if (cmd_global_ns_get_params(cmd, &param_type, &params) != TEE_SUCCESS) {
433         tloge("cmd_global_ns_get_params failed");
434         return TEE_ERROR_BAD_PARAMETERS;
435     }
436     if (params == NULL)
437         return TEE_ERROR_BAD_PARAMETERS;
438     if (TEE_PARAM_TYPE_GET(param_type, 0) != TEE_PARAM_TYPE_VALUE_OUTPUT) {
439         tloge("Bad expected parameter types: 0x%x\n", TEE_PARAM_TYPE_GET(param_type, 0));
440         return TEE_ERROR_BAD_PARAMETERS;
441     }
442     version         = tee_get_max_api_level();
443     params->value.a = version;
444 
445     return TEE_SUCCESS;
446 }
447 
process_load_image(smc_cmd_t * cmd,bool * async)448 TEE_Result process_load_image(smc_cmd_t *cmd, bool *async)
449 {
450     TEE_Result ret;
451 
452     ret = load_secure_file_image(cmd, async);
453     if (ret == TEE_ERROR_IMG_VERIFY_FAIL || ret == TEE_ERROR_IMG_PARSE_FAIL || ret == TEE_ERROR_IMG_ELF_LOAD_FAIL ||
454         ret == TEE_ERROR_IMG_DECRYPTO_FAIL)
455         tloge("load_secure_app_image failed\n");
456     return ret;
457 }
458 
check_ns_cmd(smc_cmd_t * cmd)459 static int check_ns_cmd(smc_cmd_t *cmd)
460 {
461     TEE_Result ret;
462 
463     /* check phy_addr in smc_cmd is in mailbox or not */
464     ret = check_cmd_in_mailbox_range(cmd);
465     if (ret != TEE_SUCCESS) {
466         tloge("mailbox check failed, cmd type=%u, cmd id=%u, ret = 0x%x\n",
467             cmd->cmd_type, cmd->cmd_id, ret);
468         goto error;
469     }
470 
471     ret = init_ta_context(cmd);
472     if (ret != TEE_SUCCESS) {
473         tloge("init TA context failed, cmd type=%u, cmd id=%u, ret = 0x%x\n",
474             cmd->cmd_type, cmd->cmd_id, ret);
475         goto error;
476     }
477 
478     return GT_ERR_OK;
479 
480 error:
481     cmd->ret_val = ret;
482     if (put_last_out_cmd(cmd) != GT_ERR_OK)
483         tloge("put last out cmd fail\n");
484     return GT_ERR_END_CMD;
485 }
486 
handle_ns_cmd(void)487 static int handle_ns_cmd(void)
488 {
489     int gt_err_ret;
490     smc_cmd_t cmd;
491 
492     (void)memset_s(&cmd, sizeof(cmd), 0, sizeof(cmd));
493     /* get lastest smc cmd from smc mem */
494     gt_err_ret = get_last_in_cmd(&cmd);
495     if (gt_err_ret != GT_ERR_OK)
496         return gt_err_ret;
497 
498     set_tee_return_origin(&cmd, TEE_ORIGIN_TEE);
499 
500     if (cmd.cmd_type == CMD_TYPE_BUILDIN_AGENT)
501         return handle_service_agent_back_cmd(&cmd);
502 
503     if (cmd.cmd_type == CMD_TYPE_TA_AGENT ||
504         cmd.cmd_type == CMD_TYPE_TA2TA_AGENT)
505         return handle_ta_agent_back_cmd(&cmd);
506 
507     if (cmd.cmd_type == CMD_TYPE_GLOBAL && cmd.cmd_id == GLOBAL_CMD_ID_KILL_TASK)
508         return handle_kill_task(&cmd);
509 
510     gt_err_ret = check_ns_cmd(&cmd);
511     if (gt_err_ret != GT_ERR_OK)
512         return gt_err_ret;
513 
514     if (dispatch_ns_cmd(&cmd) != TEE_SUCCESS)
515         return GT_ERR_END_CMD;
516 
517     return GT_ERR_OK;
518 }
519 
is_cmd_in_unproceed(void)520 static int is_cmd_in_unproceed(void)
521 {
522     uint32_t i;
523     int ret = 0;
524 
525     acquire_smc_buf_lock(&g_nwd_cmd->smc_lock);
526     for (i = 0; i < MAX_SMC_CMD; i++) {
527         if (test_bit(i, g_nwd_cmd->in_bitmap) && !test_bit(i, g_nwd_cmd->doing_bitmap)) {
528             ret = 1;
529             break;
530         }
531     }
532     release_smc_buf_lock(&g_nwd_cmd->smc_lock);
533 
534     return ret;
535 }
536 
gtask_main_init(void)537 static int32_t gtask_main_init(void)
538 {
539     if (ta_framework_init()) {
540         tloge("ta_framework init failed\n");
541         while (1)
542             (void)sched_yield();
543     }
544     init_internal_tasks();
545 #ifdef __aarch64__
546     tlogi("Gtask (64bit) Execute Successfully and jump to Linux kernel\n");
547 #else
548     tlogi("Gtask Execute Successfully and jump to Linux kernel\n");
549 #endif
550 
551     init_smc_cmd_mem();
552     setup_init_info();
553 
554     return GT_ERR_OK;
555 }
556 
is_ns_cmd(uint32_t task_id,uint32_t back_cmd)557 bool is_ns_cmd(uint32_t task_id, uint32_t back_cmd)
558 {
559     (void)back_cmd;
560     if (taskid_to_pid(task_id) == SMCMGR_PID)
561         return true;
562     return false;
563 }
564 
gtask_main(void)565 void gtask_main(void)
566 {
567     TEE_Result ret;
568     uint32_t back_cmd;
569     uint32_t task_id;
570     tlogd("global TEETaskEntry start\n");
571 
572     if (gtask_main_init() != GT_ERR_OK)
573         return;
574 
575     while (1) {
576         uint8_t buffer[GT_MSG_REV_SIZE] = { 0 };
577 
578         reset_ta_context();
579         back_cmd = 0;
580         task_id  = TASK_ID_NULL;
581 
582         /* We still have incomming notifications, don't block yet */
583         if (is_cmd_in_unproceed()) {
584             if (ipc_msg_rcv_a(0, (uint32_t *)(&back_cmd), buffer, GT_MSG_REV_SIZE, &task_id)) {
585                 task_id  = SMCMGR_PID;
586                 back_cmd = 0;
587                 tlogd("Still having incoming notifications\n");
588             }
589         } else {
590             ret = ipc_msg_rcv_a(OS_WAIT_FOREVER, (uint32_t *)(&back_cmd), buffer, GT_MSG_REV_SIZE, &task_id);
591             if (ret != 0) {
592                 tloge("global_task rcv error %x\n", ret);
593                 continue;
594             }
595         }
596 
597         tlogd("received back cmd =%x, task_id=%d\n", back_cmd, task_id);
598 
599         /* tzdriver SIQ schedule is not needed NOW */
600         if (is_ns_cmd(task_id, back_cmd)) {
601             /* handle cmd from ree */
602             (void)handle_ns_cmd();
603         } else {
604             /* handle cmd from tee */
605             (void)handle_s_cmd(back_cmd, task_id, buffer, GT_MSG_REV_SIZE);
606         }
607     }
608 }
609