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 */ 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 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 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 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 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 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 324 struct rt_lwp *rt_lwp_self(void) 325 { 326 return (struct rt_lwp *)rt_thread_self()->lwp; 327 } 328 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