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