xref: /nrf52832-nimble/rt-thread/components/lwp/lwp.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2006-03-12     Bernard      first version
9*10465441SEvalZero  * 2018-11-02     heyuanjie    fix complie error in iar
10*10465441SEvalZero  */
11*10465441SEvalZero 
12*10465441SEvalZero #include <rtthread.h>
13*10465441SEvalZero #include <rthw.h>
14*10465441SEvalZero #include <dfs_posix.h>
15*10465441SEvalZero 
16*10465441SEvalZero #ifndef RT_USING_DFS
17*10465441SEvalZero     #error  "lwp need file system(RT_USING_DFS)"
18*10465441SEvalZero #endif
19*10465441SEvalZero 
20*10465441SEvalZero #include "lwp.h"
21*10465441SEvalZero 
22*10465441SEvalZero #define DBG_ENABLE
23*10465441SEvalZero #define DBG_SECTION_NAME    "LWP"
24*10465441SEvalZero #define DBG_COLOR
25*10465441SEvalZero #define DBG_LEVEL           DBG_WARNING
26*10465441SEvalZero #include <rtdbg.h>
27*10465441SEvalZero 
28*10465441SEvalZero extern void lwp_user_entry(void *args, const void *text, void *data);
29*10465441SEvalZero 
30*10465441SEvalZero /**
31*10465441SEvalZero  * RT-Thread light-weight process
32*10465441SEvalZero  */
lwp_set_kernel_sp(uint32_t * sp)33*10465441SEvalZero void lwp_set_kernel_sp(uint32_t *sp)
34*10465441SEvalZero {
35*10465441SEvalZero     struct rt_lwp *user_data;
36*10465441SEvalZero     user_data = (struct rt_lwp *)rt_thread_self()->lwp;
37*10465441SEvalZero     user_data->kernel_sp = sp;
38*10465441SEvalZero }
39*10465441SEvalZero 
lwp_get_kernel_sp(void)40*10465441SEvalZero uint32_t *lwp_get_kernel_sp(void)
41*10465441SEvalZero {
42*10465441SEvalZero     struct rt_lwp *user_data;
43*10465441SEvalZero     user_data = (struct rt_lwp *)rt_thread_self()->lwp;
44*10465441SEvalZero 
45*10465441SEvalZero     return user_data->kernel_sp;
46*10465441SEvalZero }
47*10465441SEvalZero 
lwp_argscopy(struct rt_lwp * lwp,int argc,char ** argv)48*10465441SEvalZero static int lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv)
49*10465441SEvalZero {
50*10465441SEvalZero     int size = sizeof(int)*3; /* store argc, argv, NULL */
51*10465441SEvalZero     int *args;
52*10465441SEvalZero     char *str;
53*10465441SEvalZero     char **new_argv;
54*10465441SEvalZero     int i;
55*10465441SEvalZero     int len;
56*10465441SEvalZero 
57*10465441SEvalZero     for (i = 0; i < argc; i ++)
58*10465441SEvalZero     {
59*10465441SEvalZero         size += (rt_strlen(argv[i]) + 1);
60*10465441SEvalZero     }
61*10465441SEvalZero     size  += (sizeof(int) * argc);
62*10465441SEvalZero 
63*10465441SEvalZero     args = (int*)rt_malloc(size);
64*10465441SEvalZero     if (args == RT_NULL)
65*10465441SEvalZero         return -1;
66*10465441SEvalZero 
67*10465441SEvalZero     str = (char*)((int)args + (argc + 3) * sizeof(int));
68*10465441SEvalZero     new_argv = (char**)&args[2];
69*10465441SEvalZero     args[0] = argc;
70*10465441SEvalZero     args[1] = (int)new_argv;
71*10465441SEvalZero 
72*10465441SEvalZero     for (i = 0; i < argc; i ++)
73*10465441SEvalZero     {
74*10465441SEvalZero         len = rt_strlen(argv[i]) + 1;
75*10465441SEvalZero         new_argv[i] = str;
76*10465441SEvalZero         rt_memcpy(str, argv[i], len);
77*10465441SEvalZero         str += len;
78*10465441SEvalZero     }
79*10465441SEvalZero     new_argv[i] = 0;
80*10465441SEvalZero     lwp->args = args;
81*10465441SEvalZero 
82*10465441SEvalZero     return 0;
83*10465441SEvalZero }
84*10465441SEvalZero 
lwp_load(const char * filename,struct rt_lwp * lwp,uint8_t * load_addr,size_t addr_size)85*10465441SEvalZero static int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size)
86*10465441SEvalZero {
87*10465441SEvalZero     int fd;
88*10465441SEvalZero     uint8_t *ptr;
89*10465441SEvalZero     int result = RT_EOK;
90*10465441SEvalZero     int nbytes;
91*10465441SEvalZero     struct lwp_header header;
92*10465441SEvalZero     struct lwp_chunk  chunk;
93*10465441SEvalZero 
94*10465441SEvalZero     /* check file name */
95*10465441SEvalZero     RT_ASSERT(filename != RT_NULL);
96*10465441SEvalZero     /* check lwp control block */
97*10465441SEvalZero     RT_ASSERT(lwp != RT_NULL);
98*10465441SEvalZero 
99*10465441SEvalZero     if (load_addr != RT_NULL)
100*10465441SEvalZero     {
101*10465441SEvalZero         lwp->lwp_type = LWP_TYPE_FIX_ADDR;
102*10465441SEvalZero         ptr = load_addr;
103*10465441SEvalZero     }
104*10465441SEvalZero     else
105*10465441SEvalZero     {
106*10465441SEvalZero         lwp->lwp_type = LWP_TYPE_DYN_ADDR;
107*10465441SEvalZero         ptr = RT_NULL;
108*10465441SEvalZero     }
109*10465441SEvalZero 
110*10465441SEvalZero     /* open lwp */
111*10465441SEvalZero     fd = open(filename, 0, O_RDONLY);
112*10465441SEvalZero     if (fd < 0)
113*10465441SEvalZero     {
114*10465441SEvalZero         dbg_log(DBG_ERROR, "open file:%s failed!\n", filename);
115*10465441SEvalZero         result = -RT_ENOSYS;
116*10465441SEvalZero         goto _exit;
117*10465441SEvalZero     }
118*10465441SEvalZero 
119*10465441SEvalZero     /* read lwp header */
120*10465441SEvalZero     nbytes = read(fd, &header, sizeof(struct lwp_header));
121*10465441SEvalZero     if (nbytes != sizeof(struct lwp_header))
122*10465441SEvalZero     {
123*10465441SEvalZero         dbg_log(DBG_ERROR, "read lwp header return error size: %d!\n", nbytes);
124*10465441SEvalZero         result = -RT_EIO;
125*10465441SEvalZero         goto _exit;
126*10465441SEvalZero     }
127*10465441SEvalZero 
128*10465441SEvalZero     /* check file header */
129*10465441SEvalZero     if (header.magic != LWP_MAGIC)
130*10465441SEvalZero     {
131*10465441SEvalZero         dbg_log(DBG_ERROR, "erro header magic number: 0x%02X\n", header.magic);
132*10465441SEvalZero         result = -RT_EINVAL;
133*10465441SEvalZero         goto _exit;
134*10465441SEvalZero     }
135*10465441SEvalZero 
136*10465441SEvalZero     /* read text chunk info */
137*10465441SEvalZero     nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
138*10465441SEvalZero     if (nbytes != sizeof(struct lwp_chunk))
139*10465441SEvalZero     {
140*10465441SEvalZero         dbg_log(DBG_ERROR, "read text chunk info failed!\n");
141*10465441SEvalZero         result = -RT_EIO;
142*10465441SEvalZero         goto _exit;
143*10465441SEvalZero     }
144*10465441SEvalZero 
145*10465441SEvalZero     dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
146*10465441SEvalZero             "text", /*chunk.name*/ chunk.total_len, chunk.data_len, chunk.data_len_space);
147*10465441SEvalZero 
148*10465441SEvalZero     /* load text */
149*10465441SEvalZero     {
150*10465441SEvalZero         lwp->text_size = RT_ALIGN(chunk.data_len_space, 4);
151*10465441SEvalZero         if (load_addr)
152*10465441SEvalZero             lwp->text_entry = ptr;
153*10465441SEvalZero         else
154*10465441SEvalZero         {
155*10465441SEvalZero #ifdef RT_USING_CACHE
156*10465441SEvalZero             lwp->text_entry = (rt_uint8_t *)rt_malloc_align(lwp->text_size, RT_CPU_CACHE_LINE_SZ);
157*10465441SEvalZero #else
158*10465441SEvalZero             lwp->text_entry = (rt_uint8_t *)rt_malloc(lwp->text_size);
159*10465441SEvalZero #endif
160*10465441SEvalZero 
161*10465441SEvalZero             if (lwp->text_entry == RT_NULL)
162*10465441SEvalZero             {
163*10465441SEvalZero                 dbg_log(DBG_ERROR, "alloc text memory faild!\n");
164*10465441SEvalZero                 result = -RT_ENOMEM;
165*10465441SEvalZero                 goto _exit;
166*10465441SEvalZero             }
167*10465441SEvalZero             else
168*10465441SEvalZero             {
169*10465441SEvalZero                 dbg_log(DBG_LOG, "lwp text malloc : %p, size: %d!\n", lwp->text_entry, lwp->text_size);
170*10465441SEvalZero             }
171*10465441SEvalZero         }
172*10465441SEvalZero         dbg_log(DBG_INFO, "load text %d  => (0x%08x, 0x%08x)\n", lwp->text_size, (uint32_t)lwp->text_entry, (uint32_t)lwp->text_entry + lwp->text_size);
173*10465441SEvalZero 
174*10465441SEvalZero         nbytes = read(fd, lwp->text_entry, chunk.data_len);
175*10465441SEvalZero         if (nbytes != chunk.data_len)
176*10465441SEvalZero         {
177*10465441SEvalZero             dbg_log(DBG_ERROR, "read text region from file failed!\n");
178*10465441SEvalZero             result = -RT_EIO;
179*10465441SEvalZero             goto _exit;
180*10465441SEvalZero         }
181*10465441SEvalZero #ifdef RT_USING_CACHE
182*10465441SEvalZero         else
183*10465441SEvalZero         {
184*10465441SEvalZero             rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size);
185*10465441SEvalZero             rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size);
186*10465441SEvalZero         }
187*10465441SEvalZero #endif
188*10465441SEvalZero 
189*10465441SEvalZero         if (ptr != RT_NULL) ptr += nbytes;
190*10465441SEvalZero 
191*10465441SEvalZero         /* skip text hole */
192*10465441SEvalZero         if ((chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len))
193*10465441SEvalZero         {
194*10465441SEvalZero             dbg_log(DBG_LOG, "skip text hole %d!\n", (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len));
195*10465441SEvalZero             lseek(fd, (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len), SEEK_CUR);
196*10465441SEvalZero         }
197*10465441SEvalZero     }
198*10465441SEvalZero 
199*10465441SEvalZero     /* load data */
200*10465441SEvalZero     nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
201*10465441SEvalZero     if (nbytes != sizeof(struct lwp_chunk))
202*10465441SEvalZero     {
203*10465441SEvalZero         dbg_log(DBG_ERROR, "read data chunk info failed!\n");
204*10465441SEvalZero         result = -RT_EIO;
205*10465441SEvalZero         goto _exit;
206*10465441SEvalZero     }
207*10465441SEvalZero 
208*10465441SEvalZero     dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
209*10465441SEvalZero             chunk.name, chunk.total_len, chunk.data_len, chunk.data_len_space);
210*10465441SEvalZero 
211*10465441SEvalZero     {
212*10465441SEvalZero         lwp->data_size = RT_ALIGN(chunk.data_len_space, 4);
213*10465441SEvalZero         if (load_addr)
214*10465441SEvalZero             lwp->data = ptr;
215*10465441SEvalZero         else
216*10465441SEvalZero         {
217*10465441SEvalZero             lwp->data = rt_malloc(lwp->data_size);
218*10465441SEvalZero             if (lwp->data == RT_NULL)
219*10465441SEvalZero             {
220*10465441SEvalZero                 dbg_log(DBG_ERROR, "alloc data memory faild!\n");
221*10465441SEvalZero                 result = -RT_ENOMEM;
222*10465441SEvalZero                 goto _exit;
223*10465441SEvalZero             }
224*10465441SEvalZero             else
225*10465441SEvalZero             {
226*10465441SEvalZero                 dbg_log(DBG_LOG, "lwp data malloc : %p, size: %d!\n", lwp->data, lwp->data_size);
227*10465441SEvalZero                 rt_memset(lwp->data, 0, lwp->data_size);
228*10465441SEvalZero             }
229*10465441SEvalZero         }
230*10465441SEvalZero 
231*10465441SEvalZero         dbg_log(DBG_INFO, "load data %d => (0x%08x, 0x%08x)\n", lwp->data_size, (uint32_t)lwp->data, (uint32_t)lwp->data + lwp->data_size);
232*10465441SEvalZero         nbytes = read(fd, lwp->data, chunk.data_len);
233*10465441SEvalZero         if (nbytes != chunk.data_len)
234*10465441SEvalZero         {
235*10465441SEvalZero             dbg_log(DBG_ERROR, "read data region from file failed!\n");
236*10465441SEvalZero             result = -RT_ERROR;
237*10465441SEvalZero             goto _exit;
238*10465441SEvalZero         }
239*10465441SEvalZero     }
240*10465441SEvalZero 
241*10465441SEvalZero _exit:
242*10465441SEvalZero     if (fd >= 0)
243*10465441SEvalZero         close(fd);
244*10465441SEvalZero 
245*10465441SEvalZero     if (result != RT_EOK)
246*10465441SEvalZero     {
247*10465441SEvalZero         if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
248*10465441SEvalZero         {
249*10465441SEvalZero             dbg_log(DBG_ERROR, "lwp dynamic load faild, %d\n", result);
250*10465441SEvalZero             if (lwp->text_entry)
251*10465441SEvalZero             {
252*10465441SEvalZero                 dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
253*10465441SEvalZero #ifdef RT_USING_CACHE
254*10465441SEvalZero                 rt_free_align(lwp->text_entry);
255*10465441SEvalZero #else
256*10465441SEvalZero                 rt_free(lwp->text_entry);
257*10465441SEvalZero #endif
258*10465441SEvalZero             }
259*10465441SEvalZero             if (lwp->data)
260*10465441SEvalZero             {
261*10465441SEvalZero                 dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
262*10465441SEvalZero                 rt_free(lwp->data);
263*10465441SEvalZero             }
264*10465441SEvalZero         }
265*10465441SEvalZero     }
266*10465441SEvalZero 
267*10465441SEvalZero     return result;
268*10465441SEvalZero }
269*10465441SEvalZero 
lwp_cleanup(struct rt_thread * tid)270*10465441SEvalZero static void lwp_cleanup(struct rt_thread *tid)
271*10465441SEvalZero {
272*10465441SEvalZero     struct rt_lwp *lwp;
273*10465441SEvalZero 
274*10465441SEvalZero     dbg_log(DBG_INFO, "thread: %s, stack_addr: %08X\n", tid->name, tid->stack_addr);
275*10465441SEvalZero 
276*10465441SEvalZero     lwp = (struct rt_lwp *)tid->lwp;
277*10465441SEvalZero 
278*10465441SEvalZero     if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
279*10465441SEvalZero     {
280*10465441SEvalZero         dbg_log(DBG_INFO, "dynamic lwp\n");
281*10465441SEvalZero         if (lwp->text_entry)
282*10465441SEvalZero         {
283*10465441SEvalZero             dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
284*10465441SEvalZero #ifdef RT_USING_CACHE
285*10465441SEvalZero             rt_free_align(lwp->text_entry);
286*10465441SEvalZero #else
287*10465441SEvalZero             rt_free(lwp->text_entry);
288*10465441SEvalZero #endif
289*10465441SEvalZero         }
290*10465441SEvalZero         if (lwp->data)
291*10465441SEvalZero         {
292*10465441SEvalZero             dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
293*10465441SEvalZero             rt_free(lwp->data);
294*10465441SEvalZero         }
295*10465441SEvalZero     }
296*10465441SEvalZero 
297*10465441SEvalZero     dbg_log(DBG_LOG, "lwp free memory pages\n");
298*10465441SEvalZero     rt_lwp_mem_deinit(lwp);
299*10465441SEvalZero 
300*10465441SEvalZero     /* cleanup fd table */
301*10465441SEvalZero     rt_free(lwp->fdt.fds);
302*10465441SEvalZero     rt_free(lwp->args);
303*10465441SEvalZero 
304*10465441SEvalZero     dbg_log(DBG_LOG, "lwp free: %p\n", lwp);
305*10465441SEvalZero     rt_free(lwp);
306*10465441SEvalZero 
307*10465441SEvalZero     /* TODO: cleanup fd table */
308*10465441SEvalZero }
309*10465441SEvalZero 
lwp_thread(void * parameter)310*10465441SEvalZero static void lwp_thread(void *parameter)
311*10465441SEvalZero {
312*10465441SEvalZero     rt_thread_t tid;
313*10465441SEvalZero     struct rt_lwp *lwp;
314*10465441SEvalZero 
315*10465441SEvalZero     lwp = (struct rt_lwp *)parameter;
316*10465441SEvalZero     rt_lwp_mem_init(lwp);
317*10465441SEvalZero     tid = rt_thread_self();
318*10465441SEvalZero     tid->lwp = lwp;
319*10465441SEvalZero     tid->cleanup = lwp_cleanup;
320*10465441SEvalZero 
321*10465441SEvalZero     lwp_user_entry(lwp->args, lwp->text_entry, lwp->data);
322*10465441SEvalZero }
323*10465441SEvalZero 
rt_lwp_self(void)324*10465441SEvalZero struct rt_lwp *rt_lwp_self(void)
325*10465441SEvalZero {
326*10465441SEvalZero     return (struct rt_lwp *)rt_thread_self()->lwp;
327*10465441SEvalZero }
328*10465441SEvalZero 
exec(char * filename,int argc,char ** argv)329*10465441SEvalZero int exec(char *filename, int argc, char **argv)
330*10465441SEvalZero {
331*10465441SEvalZero     struct rt_lwp *lwp;
332*10465441SEvalZero     int result;
333*10465441SEvalZero 
334*10465441SEvalZero     if (filename == RT_NULL)
335*10465441SEvalZero         return -RT_ERROR;
336*10465441SEvalZero 
337*10465441SEvalZero     lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
338*10465441SEvalZero     if (lwp == RT_NULL)
339*10465441SEvalZero     {
340*10465441SEvalZero         dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
341*10465441SEvalZero         return -RT_ENOMEM;
342*10465441SEvalZero     }
343*10465441SEvalZero     dbg_log(DBG_INFO, "lwp malloc : %p, size: %d!\n", lwp, sizeof(struct rt_lwp));
344*10465441SEvalZero 
345*10465441SEvalZero     rt_memset(lwp, 0, sizeof(*lwp));
346*10465441SEvalZero     if (lwp_argscopy(lwp, argc, argv) != 0)
347*10465441SEvalZero     {
348*10465441SEvalZero         rt_free(lwp);
349*10465441SEvalZero         return -ENOMEM;
350*10465441SEvalZero     }
351*10465441SEvalZero 
352*10465441SEvalZero     result = lwp_load(filename, lwp, RT_NULL, 0);
353*10465441SEvalZero     if (result == RT_EOK)
354*10465441SEvalZero     {
355*10465441SEvalZero         rt_thread_t tid;
356*10465441SEvalZero 
357*10465441SEvalZero         tid = rt_thread_create("user", lwp_thread, (void *)lwp,
358*10465441SEvalZero                                1024 * 4, 2, 200);
359*10465441SEvalZero         if (tid != RT_NULL)
360*10465441SEvalZero         {
361*10465441SEvalZero             dbg_log(DBG_LOG, "lwp kernel => (0x%08x, 0x%08x)\n", (rt_uint32_t)tid->stack_addr, (rt_uint32_t)tid->stack_addr + tid->stack_size);
362*10465441SEvalZero             rt_thread_startup(tid);
363*10465441SEvalZero             return RT_EOK;
364*10465441SEvalZero         }
365*10465441SEvalZero         else
366*10465441SEvalZero         {
367*10465441SEvalZero #ifdef RT_USING_CACHE
368*10465441SEvalZero             rt_free_align(lwp->text_entry);
369*10465441SEvalZero #else
370*10465441SEvalZero             rt_free(lwp->text_entry);
371*10465441SEvalZero #endif
372*10465441SEvalZero             rt_free(lwp->data);
373*10465441SEvalZero         }
374*10465441SEvalZero     }
375*10465441SEvalZero 
376*10465441SEvalZero     rt_free(lwp->args);
377*10465441SEvalZero     rt_free(lwp);
378*10465441SEvalZero 
379*10465441SEvalZero     return -RT_ERROR;
380*10465441SEvalZero }
381