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