1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2013-02-26     prife        first version for win32
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <rtm.h>
14 
15 #ifdef RT_USING_MODULE
16 
17 #define DBG_TAG           "simulator.module.win32"
18 #define DBG_LVL           DBG_INFO
19 #include <rtdbg.h>
20 
rt_module_init_object_container(struct rt_module * module)21 void rt_module_init_object_container(struct rt_module *module)
22 {
23     RT_ASSERT(module != RT_NULL);
24 
25     /* initialize object container - thread */
26     rt_list_init(&(module->module_object[RT_Object_Class_Thread].object_list));
27     module->module_object[RT_Object_Class_Thread].object_size = sizeof(struct rt_thread);
28     module->module_object[RT_Object_Class_Thread].type = RT_Object_Class_Thread;
29 
30 #ifdef RT_USING_SEMAPHORE
31     /* initialize object container - semaphore */
32     rt_list_init(&(module->module_object[RT_Object_Class_Semaphore].object_list));
33     module->module_object[RT_Object_Class_Semaphore].object_size = sizeof(struct rt_semaphore);
34     module->module_object[RT_Object_Class_Semaphore].type = RT_Object_Class_Semaphore;
35 #endif
36 
37 #ifdef RT_USING_MUTEX
38     /* initialize object container - mutex */
39     rt_list_init(&(module->module_object[RT_Object_Class_Mutex].object_list));
40     module->module_object[RT_Object_Class_Mutex].object_size = sizeof(struct rt_mutex);
41     module->module_object[RT_Object_Class_Mutex].type = RT_Object_Class_Mutex;
42 #endif
43 
44 #ifdef RT_USING_EVENT
45     /* initialize object container - event */
46     rt_list_init(&(module->module_object[RT_Object_Class_Event].object_list));
47     module->module_object[RT_Object_Class_Event].object_size = sizeof(struct rt_event);
48     module->module_object[RT_Object_Class_Event].type = RT_Object_Class_Event;
49 #endif
50 
51 #ifdef RT_USING_MAILBOX
52     /* initialize object container - mailbox */
53     rt_list_init(&(module->module_object[RT_Object_Class_MailBox].object_list));
54     module->module_object[RT_Object_Class_MailBox].object_size = sizeof(struct rt_mailbox);
55     module->module_object[RT_Object_Class_MailBox].type = RT_Object_Class_MailBox;
56 #endif
57 
58 #ifdef RT_USING_MESSAGEQUEUE
59     /* initialize object container - message queue */
60     rt_list_init(&(module->module_object[RT_Object_Class_MessageQueue].object_list));
61     module->module_object[RT_Object_Class_MessageQueue].object_size = sizeof(struct rt_messagequeue);
62     module->module_object[RT_Object_Class_MessageQueue].type = RT_Object_Class_MessageQueue;
63 #endif
64 
65 #ifdef RT_USING_MEMHEAP
66     /* initialize object container - memory heap */
67     rt_list_init(&(module->module_object[RT_Object_Class_MemHeap].object_list));
68     module->module_object[RT_Object_Class_MemHeap].object_size = sizeof(struct rt_memheap);
69     module->module_object[RT_Object_Class_MemHeap].type = RT_Object_Class_MemHeap;
70 #endif
71 
72 #ifdef RT_USING_MEMPOOL
73     /* initialize object container - memory pool */
74     rt_list_init(&(module->module_object[RT_Object_Class_MemPool].object_list));
75     module->module_object[RT_Object_Class_MemPool].object_size = sizeof(struct rt_mempool);
76     module->module_object[RT_Object_Class_MemPool].type = RT_Object_Class_MemPool;
77 #endif
78 
79 #ifdef RT_USING_DEVICE
80     /* initialize object container - device */
81     rt_list_init(&(module->module_object[RT_Object_Class_Device].object_list));
82     module->module_object[RT_Object_Class_Device].object_size = sizeof(struct rt_device);
83     module->module_object[RT_Object_Class_Device].type = RT_Object_Class_Device;
84 #endif
85 
86     /* initialize object container - timer */
87     rt_list_init(&(module->module_object[RT_Object_Class_Timer].object_list));
88     module->module_object[RT_Object_Class_Timer].object_size = sizeof(struct rt_timer);
89     module->module_object[RT_Object_Class_Timer].type = RT_Object_Class_Timer;
90 }
91 
92 #ifdef RT_USING_HOOK
93 static void (*rt_module_load_hook)(rt_module_t module);
94 static void (*rt_module_unload_hook)(rt_module_t module);
95 
96 /**
97  * @addtogroup Hook
98  */
99 
100 /*@{*/
101 
102 /**
103  * This function will set a hook function, which will be invoked when module
104  * be loaded to system.
105  *
106  * @param hook the hook function
107  */
rt_module_load_sethook(void (* hook)(rt_module_t module))108 void rt_module_load_sethook(void (*hook)(rt_module_t module))
109 {
110     rt_module_load_hook = hook;
111 }
112 
113 /**
114  * This function will set a hook function, which will be invoked when module
115  * be unloaded from system.
116  *
117  * @param hook the hook function
118  */
rt_module_unload_sethook(void (* hook)(rt_module_t module))119 void rt_module_unload_sethook(void (*hook)(rt_module_t module))
120 {
121     rt_module_unload_hook = hook;
122 }
123 
124 /*@}*/
125 #endif
126 
127 /**
128  * @ingroup SystemInit
129  *
130  * This function will initialize system module
131  */
rt_system_module_init(void)132 int rt_system_module_init(void)
133 {
134     return 0;
135 }
136 
137 /**
138  * This function will return self module object
139  *
140  * @return the self module object
141  */
rt_module_self(void)142 rt_module_t rt_module_self(void)
143 {
144     rt_thread_t tid;
145 
146     tid = rt_thread_self();
147     if (tid == RT_NULL)
148         return RT_NULL;
149 
150     /* return current module */
151     return (rt_module_t)tid->parent.module_id;
152 }
153 RTM_EXPORT(rt_module_self);
154 
155 /**
156  * This function will find the specified module.
157  *
158  * @param name the name of module finding
159  *
160  * @return the module
161  */
rt_module_find(const char * name)162 rt_module_t rt_module_find(const char *name)
163 {
164     struct rt_object_information *information;
165     struct rt_object *object;
166     struct rt_list_node *node;
167 
168     RT_DEBUG_NOT_IN_INTERRUPT;
169 
170     /* enter critical */
171     rt_enter_critical();
172 
173     /* try to find device object */
174     information = rt_object_get_information(RT_Object_Class_Module);
175     RT_ASSERT(information != RT_NULL);
176 
177     for (node = information->object_list.next;
178         node != &(information->object_list);
179         node = node->next)
180     {
181         object = rt_list_entry(node, struct rt_object, list);
182         if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
183         {
184             /* leave critical */
185             rt_exit_critical();
186 
187             return (rt_module_t)object;
188         }
189     }
190 
191     /* leave critical */
192     rt_exit_critical();
193 
194     /* not found */
195     return RT_NULL;
196 }
197 RTM_EXPORT(rt_module_find);
198 
199 #ifdef RT_USING_DFS
200 #include <windows.h>
201 #include <dfs_file.h>
202 #include <unistd.h>
203 #include <stdio.h>
204 #include <sys/stat.h>
205 #include <sys/statfs.h>
206 extern char * dfs_win32_dirdup(char * path);
_module_name(const char * path)207 static char* _module_name(const char *path)
208 {
209     const char *first, *end, *ptr;
210     char *name;
211     int size;
212 
213     ptr   = (char *)path;
214     first = ptr;
215     end   = path + rt_strlen(path);
216 
217     while (*ptr != '\0')
218     {
219         if (*ptr == '/')
220             first = ptr + 1;
221         if (*ptr == '.')
222             end = ptr - 1;
223 
224         ptr ++;
225     }
226 
227     size = end - first + 1;
228     name = rt_malloc(size);
229     rt_strncpy(name, first, size);
230     name[size] = '\0';
231 
232     return name;
233 }
234 
235 typedef int (*appentry_t)(void);
236 /**
237  * This function will load a module from a file
238  *
239  * @param path the full path of application module
240  *
241  * @return the module object
242  */
rt_module_open(const char * path)243 rt_module_t rt_module_open(const char *path)
244 {
245     struct dfs_filesystem *fs;
246     appentry_t fptr;
247     HINSTANCE hinstlib;
248     rt_module_t module;
249 
250     char * winpath = RT_NULL;
251     char * name = RT_NULL;
252 
253     RT_DEBUG_NOT_IN_INTERRUPT;
254 
255     /* check parameters */
256     RT_ASSERT(path != RT_NULL);
257 
258     /* app module should only in DFS_WIN32 */
259     fs = dfs_filesystem_lookup(path);
260     if ((fs == RT_NULL) || (strcmp(fs->ops->name,"wdir") != 0))
261     {
262         rt_kprintf("invalid path: %s\n", path);
263         return RT_NULL;
264     }
265 
266     /* change path */
267     // len = strlen(path+1);
268     if ((winpath = dfs_win32_dirdup((char *)path)) == RT_NULL)
269     {
270         rt_kprintf("out of memory, exit");
271         return RT_NULL;
272     }
273 
274     hinstlib = LoadLibrary(winpath);
275     if (hinstlib == NULL)
276     {
277         rt_kprintf("error: unable to open %s\n", winpath);
278         return RT_NULL;
279     }
280 
281     fptr = (appentry_t)GetProcAddress(hinstlib, "main");
282     if (fptr == NULL)
283     {
284         rt_kprintf("error: unable to find function in %s\n", winpath);
285         FreeLibrary(hinstlib);
286         return RT_NULL;
287     }
288 
289     /* get the name of the module */
290     name = _module_name(path);
291 
292     /* allocate module */
293     module = (struct rt_module *)rt_object_allocate(RT_Object_Class_Module, name);
294     if (!module) return RT_NULL;
295 
296     module->nref = 0;
297     module->module_entry = fptr;
298 
299     /* init module object container */
300     rt_module_init_object_container(module);
301 
302     /* increase module reference count */
303     module->nref ++;
304 
305     if (module->module_entry != 0)
306     {
307 #ifdef RT_USING_SLAB
308         /* init module memory allocator */
309         module->mem_list = RT_NULL;
310 
311         /* create page array */
312         module->page_array =
313             (void *)rt_malloc(PAGE_COUNT_MAX * sizeof(struct rt_page_info));
314         module->page_cnt = 0;
315 #endif
316 
317         /* create module thread */
318         module->module_thread =
319             rt_thread_create(name,
320             (void(*)(void *))module->module_entry, RT_NULL,
321             2048, RT_THREAD_PRIORITY_MAX - 2, 10);
322 
323         LOG_D("thread entry %#x", module->module_entry);
324 
325         /* set module id */
326         module->module_thread->parent.module_id = (void *)module;
327         module->parent.flag = RT_MODULE_FLAG_WITHENTRY;
328 
329         /* startup module thread */
330         rt_thread_startup(module->module_thread);
331     }
332     else
333     {
334         /* without entry point */
335         module->parent.flag |= RT_MODULE_FLAG_WITHOUTENTRY;
336     }
337 
338 #ifdef RT_USING_HOOK
339     if (rt_module_load_hook != RT_NULL)
340     {
341         rt_module_load_hook(module);
342     }
343 #endif
344 
345     rt_free(name);
346     return module;
347     /* FreeLibrary(hinstlib); */
348 }
349 
350 #if defined(RT_USING_FINSH)
351 #include <finsh.h>
352 FINSH_FUNCTION_EXPORT_ALIAS(rt_module_open, exec, exec module from a file);
353 #endif
354 
355 #endif
356 
357 #define RT_MODULE_ARG_MAX    8
_rt_module_split_arg(char * cmd,rt_size_t length,char * argv[])358 static int _rt_module_split_arg(char* cmd, rt_size_t length, char* argv[])
359 {
360     int argc = 0;
361     char *ptr = cmd;
362 
363     while ((ptr - cmd) < length)
364     {
365         /* strip bank and tab */
366         while ((*ptr == ' ' || *ptr == '\t') && (ptr -cmd)< length)
367             *ptr++ = '\0';
368         /* check whether it's the end of line */
369         if ((ptr - cmd)>= length) break;
370 
371         /* handle string with quote */
372         if (*ptr == '"')
373         {
374             argv[argc++] = ++ptr;
375 
376             /* skip this string */
377             while (*ptr != '"' && (ptr-cmd) < length)
378                 if (*ptr ++ == '\\')  ptr ++;
379             if ((ptr - cmd) >= length) break;
380 
381             /* skip '"' */
382             *ptr ++ = '\0';
383         }
384         else
385         {
386             argv[argc++] = ptr;
387             while ((*ptr != ' ' && *ptr != '\t') && (ptr - cmd) < length)
388                 ptr ++;
389         }
390 
391         if (argc >= RT_MODULE_ARG_MAX) break;
392     }
393 
394     return argc;
395 }
396 
397 /* module main thread entry */
module_main_entry(void * parameter)398 static void module_main_entry(void* parameter)
399 {
400     int argc;
401     char *argv[RT_MODULE_ARG_MAX];
402     typedef int (*main_func_t)(int argc, char** argv);
403 
404     rt_module_t module = (rt_module_t) parameter;
405     if (module == RT_NULL || module->module_cmd_line == RT_NULL) return;
406 
407     rt_memset(argv, 0x00, sizeof(argv));
408     argc = _rt_module_split_arg((char*)module->module_cmd_line, module->module_cmd_size, argv);
409     if (argc == 0) return ;
410 
411     /* do the main function */
412     ((main_func_t)module->module_entry)(argc, argv);
413     return;
414 }
415 
416 /**
417  * This function will do a executable program with main function and parameters.
418  *
419  * @param path the full path of application module
420  * @param cmd_line the command line of program
421  * @param size the size of command line of program
422  *
423  * @return the module object
424  */
rt_module_exec_cmd(const char * path,const char * cmd_line,int line_size)425 rt_module_t rt_module_exec_cmd(const char *path, const char* cmd_line, int line_size)
426 {
427     struct dfs_filesystem *fs;
428     appentry_t fptr;
429     HINSTANCE hinstlib;
430     rt_module_t module;
431 
432     char * winpath = RT_NULL;
433     char * name = RT_NULL;
434     char *full_path = RT_NULL;
435 
436     RT_DEBUG_NOT_IN_INTERRUPT;
437 
438     /* check parameters */
439     RT_ASSERT(path != RT_NULL);
440 
441     if (*path != '/')
442     {
443         full_path = dfs_normalize_path(RT_NULL, path);
444     }
445     else
446     {
447         full_path = (const char*)path;
448     }
449 
450     /* app module should only in DFS_WIN32 */
451     fs = dfs_filesystem_lookup(full_path);
452     if ((fs == RT_NULL) || (strcmp(fs->ops->name,"wdir") != 0))
453     {
454         rt_kprintf("invalid path: %s\n", path);
455         goto __exit;
456     }
457 
458     /* change path */
459     // len = strlen(full_path + 1);
460     if ((winpath = dfs_win32_dirdup((char *)full_path)) == RT_NULL)
461     {
462         rt_kprintf("out of memory, exit", path);
463         goto __exit;
464     }
465 
466     hinstlib = LoadLibrary(winpath);
467     if (hinstlib == NULL)
468     {
469         rt_kprintf("error: unable to open %s\n", winpath);
470         goto __exit;
471     }
472 
473     fptr = (appentry_t)GetProcAddress(hinstlib, "main");
474     if (fptr == NULL)
475     {
476         rt_kprintf("error: unable to find function in %s\n", winpath);
477         FreeLibrary(hinstlib);
478         goto __exit;
479     }
480 
481     /* release winpath */
482     rt_free(winpath);
483 
484     /* get the name of the module */
485     name = _module_name(path);
486 
487     /* allocate module */
488     module = (struct rt_module *)rt_object_allocate(RT_Object_Class_Module, name);
489     if (!module)
490     {
491         goto __exit;
492     }
493 
494     module->nref = 0;
495     module->module_entry = fptr;
496 
497     /* init module object container */
498     rt_module_init_object_container(module);
499 
500     /* increase module reference count */
501     module->nref ++;
502 
503     if (module->module_entry != 0)
504     {
505         /* set module argument */
506         module->module_cmd_line = (rt_uint8_t*)rt_malloc(line_size + 1);
507         rt_memcpy(module->module_cmd_line, cmd_line, line_size);
508         module->module_cmd_line[line_size] = '\0';
509         module->module_cmd_size = line_size;
510 
511 #ifdef RT_USING_SLAB
512         /* init module memory allocator */
513         module->mem_list = RT_NULL;
514 
515         /* create page array */
516         module->page_array =
517             (void *)rt_malloc(PAGE_COUNT_MAX * sizeof(struct rt_page_info));
518         module->page_cnt = 0;
519 #endif
520 
521         /* create module thread */
522         module->module_thread = rt_thread_create(name,
523             module_main_entry, module,
524             2048, RT_THREAD_PRIORITY_MAX - 2, 10);
525 
526         /* set module id */
527         module->module_thread->parent.module_id = (void *)module;
528         module->parent.flag = RT_MODULE_FLAG_WITHENTRY;
529 
530         /* startup module thread */
531         rt_thread_startup(module->parent.module_thread);
532     }
533     else
534     {
535         /* without entry point */
536         module->parent.flag |= RT_MODULE_FLAG_WITHOUTENTRY;
537     }
538 
539 #ifdef RT_USING_HOOK
540     if (rt_module_load_hook != RT_NULL)
541     {
542         rt_module_load_hook(module);
543     }
544 #endif
545 
546     rt_free(name);
547     return module;
548 
549 __exit:
550     if (full_path != path) rt_free(full_path);
551     if (name != RT_NULL)   rt_free(full_path);
552     if (winpath != RT_NULL)rt_free(winpath);
553 
554     return RT_NULL;
555     /* FreeLibrary(hinstlib); */
556 }
557 
rt_module_destroy(rt_module_t module)558 rt_err_t rt_module_destroy(rt_module_t module)
559 {
560     return 0;
561 }
562 
rt_module_unload(rt_module_t module)563 rt_err_t rt_module_unload(rt_module_t module)
564 {
565     return 0;
566 }
567 
568 #endif
569