lwp.c 9.6 KB

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