lwp.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * File : clock.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. */
  23. #include <rtthread.h>
  24. #include <rthw.h>
  25. #include <dfs_posix.h>
  26. #ifdef RT_USING_FINSH
  27. #include <finsh.h>
  28. #endif
  29. #ifndef RT_USING_DFS
  30. #error "lwp need file system(RT_USING_DFS)"
  31. #endif
  32. #include "lwp.h"
  33. #define DBG_ENABLE
  34. #define DBG_SECTION_NAME "[LWP]"
  35. #define DBG_COLOR
  36. #define DBG_LEVEL DBG_LOG
  37. #include <rtdbg.h>
  38. extern rt_thread_t rt_current_thread;
  39. extern void lwp_user_entry(const void *text, void *data);
  40. /**
  41. * RT-Thread light-weight process
  42. */
  43. void lwp_set_kernel_sp(uint32_t *sp)
  44. {
  45. struct rt_lwp *user_data;
  46. user_data = (struct rt_lwp *)rt_current_thread->user_data;
  47. user_data->kernel_sp = sp;
  48. }
  49. uint32_t *lwp_get_kernel_sp(void)
  50. {
  51. struct rt_lwp *user_data;
  52. user_data = (struct rt_lwp *)rt_current_thread->user_data;
  53. return user_data->kernel_sp;
  54. }
  55. static int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size)
  56. {
  57. int fd;
  58. uint8_t *ptr;
  59. int result = RT_EOK;
  60. int nbytes;
  61. struct lwp_header header;
  62. struct lwp_chunk chunk;
  63. /* check file name */
  64. RT_ASSERT(filename != RT_NULL);
  65. /* check lwp control block */
  66. RT_ASSERT(lwp != RT_NULL);
  67. memset(lwp, 0x00, sizeof(struct rt_lwp));
  68. if (load_addr != RT_NULL)
  69. {
  70. lwp->lwp_type = LWP_TYPE_FIX_ADDR;
  71. ptr = load_addr;
  72. }
  73. else
  74. {
  75. lwp->lwp_type = LWP_TYPE_DYN_ADDR;
  76. ptr = RT_NULL;
  77. }
  78. /* open lwp */
  79. fd = open(filename, 0, O_RDONLY);
  80. if (fd < 0)
  81. {
  82. dbg_log(DBG_ERROR, "open file:%s failed!\n", filename);
  83. result = -RT_ENOSYS;
  84. goto _exit;
  85. }
  86. /* read lwp header */
  87. nbytes = read(fd, &header, sizeof(struct lwp_header));
  88. if (nbytes != sizeof(struct lwp_header))
  89. {
  90. dbg_log(DBG_ERROR, "read lwp header return error size: %d!\n", nbytes);
  91. result = -RT_EIO;
  92. goto _exit;
  93. }
  94. /* check file header */
  95. if (header.magic != LWP_MAGIC)
  96. {
  97. dbg_log(DBG_ERROR, "erro header magic number: 0x%02X\n", header.magic);
  98. result = -RT_EINVAL;
  99. goto _exit;
  100. }
  101. /* read text chunk info */
  102. nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
  103. if (nbytes != sizeof(struct lwp_chunk))
  104. {
  105. dbg_log(DBG_ERROR, "read text chunk info failed!\n");
  106. result = -RT_EIO;
  107. goto _exit;
  108. }
  109. dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
  110. "text", /*chunk.name*/ chunk.total_len, chunk.data_len, chunk.data_len_space);
  111. /* load text */
  112. {
  113. lwp->text_size = RT_ALIGN(chunk.data_len_space, 4);
  114. if (load_addr)
  115. lwp->text_entry = ptr;
  116. else
  117. {
  118. #ifdef RT_USING_CACHE
  119. lwp->text_entry = (rt_uint8_t *)rt_malloc_align(lwp->text_size, RT_CPU_CACHE_LINE_SZ);
  120. #else
  121. lwp->text_entry = (rt_uint8_t *)rt_malloc(lwp->text_size);
  122. #endif
  123. if (lwp->text_entry == RT_NULL)
  124. {
  125. dbg_log(DBG_ERROR, "alloc text memory faild!\n");
  126. result = -RT_ENOMEM;
  127. goto _exit;
  128. }
  129. else
  130. {
  131. dbg_log(DBG_LOG, "lwp text malloc : %p, size: %d!\n", lwp->text_entry, lwp->text_size);
  132. }
  133. }
  134. 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);
  135. nbytes = read(fd, lwp->text_entry, chunk.data_len);
  136. if (nbytes != chunk.data_len)
  137. {
  138. dbg_log(DBG_ERROR, "read text region from file failed!\n");
  139. result = -RT_EIO;
  140. goto _exit;
  141. }
  142. #ifdef RT_USING_CACHE
  143. else
  144. {
  145. rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size);
  146. rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size);
  147. }
  148. #endif
  149. if (ptr != RT_NULL) ptr += nbytes;
  150. /* skip text hole */
  151. if ((chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len))
  152. {
  153. dbg_log(DBG_LOG, "skip text hole %d!\n", (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len));
  154. lseek(fd, (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len), SEEK_CUR);
  155. }
  156. }
  157. /* load data */
  158. nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
  159. if (nbytes != sizeof(struct lwp_chunk))
  160. {
  161. dbg_log(DBG_ERROR, "read data chunk info failed!\n");
  162. result = -RT_EIO;
  163. goto _exit;
  164. }
  165. dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
  166. chunk.name, chunk.total_len, chunk.data_len, chunk.data_len_space);
  167. {
  168. lwp->data_size = RT_ALIGN(chunk.data_len_space, 4);
  169. if (load_addr)
  170. lwp->data = ptr;
  171. else
  172. {
  173. lwp->data = rt_malloc(lwp->data_size);
  174. if (lwp->data == RT_NULL)
  175. {
  176. dbg_log(DBG_ERROR, "alloc data memory faild!\n");
  177. result = -RT_ENOMEM;
  178. goto _exit;
  179. }
  180. else
  181. {
  182. dbg_log(DBG_LOG, "lwp data malloc : %p, size: %d!\n", lwp->data, lwp->data_size);
  183. rt_memset(lwp->data, 0, lwp->data_size);
  184. }
  185. }
  186. 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);
  187. nbytes = read(fd, lwp->data, chunk.data_len);
  188. if (nbytes != chunk.data_len)
  189. {
  190. dbg_log(DBG_ERROR, "read data region from file failed!\n");
  191. result = -RT_ERROR;
  192. goto _exit;
  193. }
  194. }
  195. _exit:
  196. if (fd >= 0)
  197. close(fd);
  198. if (result != RT_EOK)
  199. {
  200. if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
  201. {
  202. dbg_log(DBG_ERROR, "lwp dynamic load faild, %d\n", result);
  203. if (lwp->text_entry)
  204. {
  205. dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
  206. #ifdef RT_USING_CACHE
  207. rt_free_align(lwp->text_entry);
  208. #else
  209. rt_free(lwp->text_entry);
  210. #endif
  211. }
  212. if (lwp->data)
  213. {
  214. dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
  215. rt_free(lwp->data);
  216. }
  217. }
  218. }
  219. return result;
  220. }
  221. static void lwp_cleanup(struct rt_thread *tid)
  222. {
  223. struct rt_lwp *lwp;
  224. dbg_log(DBG_INFO, "thread: %s, stack_addr: %08X\n", tid->name, tid->stack_addr);
  225. lwp = (struct rt_lwp *)tid->user_data;
  226. if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
  227. {
  228. dbg_log(DBG_INFO, "dynamic lwp\n");
  229. if (lwp->text_entry)
  230. {
  231. dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
  232. #ifdef RT_USING_CACHE
  233. rt_free_align(lwp->text_entry);
  234. #else
  235. rt_free(lwp->text_entry);
  236. #endif
  237. }
  238. if (lwp->data)
  239. {
  240. dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
  241. rt_free(lwp->data);
  242. }
  243. }
  244. dbg_log(DBG_LOG, "lwp free memory pages\n");
  245. rt_lwp_mem_deinit(lwp);
  246. dbg_log(DBG_LOG, "lwp free: %p\n", lwp);
  247. rt_free(lwp);
  248. /* TODO: cleanup fd table */
  249. }
  250. static void lwp_thread(void *parameter)
  251. {
  252. volatile uint32_t tmp;
  253. rt_thread_t tid;
  254. struct rt_lwp *lwp;
  255. rt_kprintf("%08x %08x\n", &tmp, tmp);
  256. lwp = (struct rt_lwp *)parameter;
  257. rt_lwp_mem_init(lwp);
  258. tid = rt_thread_self();
  259. tid->user_data = (rt_uint32_t)lwp;
  260. tid->cleanup = lwp_cleanup;
  261. lwp_user_entry(lwp->text_entry, lwp->data);
  262. }
  263. struct rt_lwp *rt_lwp_self(void)
  264. {
  265. return (struct rt_lwp *)rt_thread_self()->user_data;
  266. }
  267. int exec(char *filename)
  268. {
  269. struct rt_lwp *lwp;
  270. int result;
  271. if (filename == RT_NULL)
  272. return -RT_ERROR;
  273. lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
  274. if (lwp == RT_NULL)
  275. {
  276. dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
  277. return -RT_ENOMEM;
  278. }
  279. dbg_log(DBG_INFO, "lwp malloc : %p, size: %d!\n", lwp, sizeof(struct rt_lwp));
  280. rt_memset(lwp, 0, sizeof(*lwp));
  281. result = lwp_load(filename, lwp, RT_NULL, 0);
  282. if (result == RT_EOK)
  283. {
  284. rt_thread_t tid;
  285. tid = rt_thread_create("user", lwp_thread, (void *)lwp,
  286. 1024 * 4, 2, 200);
  287. if (tid != RT_NULL)
  288. {
  289. 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);
  290. rt_thread_startup(tid);
  291. return RT_EOK;
  292. }
  293. else
  294. {
  295. #ifdef RT_USING_CACHE
  296. rt_free_align(lwp->text_entry);
  297. #else
  298. rt_free(lwp->text_entry);
  299. #endif
  300. rt_free(lwp->data);
  301. }
  302. }
  303. rt_free(lwp);
  304. return -RT_ERROR;
  305. }
  306. FINSH_FUNCTION_EXPORT(exec, loader a user app &run);
  307. int _exec(int argc, char **argv)
  308. {
  309. if (argc != 2)
  310. return -RT_ERROR;
  311. return exec(argv[1]);
  312. }
  313. MSH_CMD_EXPORT_ALIAS(_exec, exec, loader a user app &run);