From bca65f30a90857287dc1371ddbc8d5f165691c7f Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 10 Jun 2018 17:57:34 +0800 Subject: [PATCH] [lwP] Add light weight process component. --- components/Kconfig | 2 + components/dfs/include/dfs.h | 8 + components/dfs/src/dfs.c | 133 ++++- components/lwp/Kconfig | 7 + components/lwp/SConscript | 20 + components/lwp/arch/arm/cortex-m3/lwp_gcc.S | 176 ++++++ components/lwp/arch/arm/cortex-m3/lwp_iar.S | 176 ++++++ components/lwp/arch/arm/cortex-m3/lwp_rvds.S | 184 ++++++ components/lwp/arch/arm/cortex-m4/lwp_gcc.S | 210 +++++++ components/lwp/arch/arm/cortex-m4/lwp_iar.S | 215 +++++++ components/lwp/arch/arm/cortex-m4/lwp_rvds.S | 219 +++++++ components/lwp/arch/arm/cortex-m7/lwp_gcc.S | 210 +++++++ components/lwp/arch/arm/cortex-m7/lwp_iar.S | 215 +++++++ components/lwp/arch/arm/cortex-m7/lwp_rvds.S | 219 +++++++ components/lwp/lwp.c | 364 ++++++++++++ components/lwp/lwp.h | 83 +++ components/lwp/lwp_mem.c | 232 ++++++++ components/lwp/lwp_mem.h | 34 ++ components/lwp/lwp_memheap.c | 590 +++++++++++++++++++ components/lwp/lwp_memheap.h | 74 +++ components/lwp/lwp_syscall.c | 242 ++++++++ components/lwp/lwp_syscall.h | 78 +++ 22 files changed, 3675 insertions(+), 16 deletions(-) create mode 100644 components/lwp/Kconfig create mode 100644 components/lwp/SConscript create mode 100644 components/lwp/arch/arm/cortex-m3/lwp_gcc.S create mode 100644 components/lwp/arch/arm/cortex-m3/lwp_iar.S create mode 100644 components/lwp/arch/arm/cortex-m3/lwp_rvds.S create mode 100644 components/lwp/arch/arm/cortex-m4/lwp_gcc.S create mode 100644 components/lwp/arch/arm/cortex-m4/lwp_iar.S create mode 100644 components/lwp/arch/arm/cortex-m4/lwp_rvds.S create mode 100644 components/lwp/arch/arm/cortex-m7/lwp_gcc.S create mode 100644 components/lwp/arch/arm/cortex-m7/lwp_iar.S create mode 100644 components/lwp/arch/arm/cortex-m7/lwp_rvds.S create mode 100644 components/lwp/lwp.c create mode 100644 components/lwp/lwp.h create mode 100644 components/lwp/lwp_mem.c create mode 100644 components/lwp/lwp_mem.h create mode 100644 components/lwp/lwp_memheap.c create mode 100644 components/lwp/lwp_memheap.h create mode 100644 components/lwp/lwp_syscall.c create mode 100644 components/lwp/lwp_syscall.h diff --git a/components/Kconfig b/components/Kconfig index ed5c137d3..3bcae8e16 100644 --- a/components/Kconfig +++ b/components/Kconfig @@ -26,6 +26,8 @@ source "$RTT_DIR/components/drivers/Kconfig" source "$RTT_DIR/components/libc/Kconfig" +source "$RTT_DIR/components/lwp/Kconfig" + source "$RTT_DIR/components/net/Kconfig" source "$RTT_DIR/components/vbus/Kconfig" diff --git a/components/dfs/include/dfs.h b/components/dfs/include/dfs.h index 91ef42ab5..f17458bd6 100644 --- a/components/dfs/include/dfs.h +++ b/components/dfs/include/dfs.h @@ -95,6 +95,12 @@ struct dirent char d_name[DFS_PATH_MAX]; /* The null-terminated file name */ }; +struct dfs_fdtable +{ + uint32_t maxfd; + struct dfs_fd **fds; +}; + /* Initialization of dfs */ int dfs_init(void); @@ -110,6 +116,8 @@ struct dfs_fd *fd_get(int fd); void fd_put(struct dfs_fd *fd); int fd_is_open(const char *pathname); +struct dfs_fdtable* dfs_fdtable_get(void); + #ifdef __cplusplus } #endif diff --git a/components/dfs/src/dfs.c b/components/dfs/src/dfs.c index 858399fd1..f613168a4 100644 --- a/components/dfs/src/dfs.c +++ b/components/dfs/src/dfs.c @@ -21,12 +21,16 @@ * Date Author Notes * 2005-02-22 Bernard The first version. * 2017-12-11 Bernard Use rt_free to instead of free in fd_is_open(). + * 2018-03-20 Heyuanjie dynamic allocation FD */ #include #include #include #include "dfs_private.h" +#ifdef RT_USING_LWP +#include +#endif /* Global variables */ const struct dfs_filesystem_ops *filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; @@ -39,7 +43,8 @@ static struct rt_mutex fslock; char working_directory[DFS_PATH_MAX] = {"/"}; #endif -struct dfs_fd fd_table[DFS_FD_MAX]; +static struct dfs_fdtable _fdtab; +static int fd_alloc(struct dfs_fdtable *fdt, int startfd); /** * @addtogroup DFS @@ -57,7 +62,7 @@ int dfs_init(void) /* clear filesystem table */ memset(filesystem_table, 0, sizeof(filesystem_table)); /* clean fd table */ - memset(fd_table, 0, sizeof(fd_table)); + memset(&_fdtab, 0, sizeof(_fdtab)); /* create device filesystem lock */ rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO); @@ -90,9 +95,13 @@ INIT_PREV_EXPORT(dfs_init); */ void dfs_lock(void) { - rt_err_t result; + rt_err_t result = -RT_EBUSY; + + while (result == -RT_EBUSY) + { + result = rt_mutex_take(&fslock, RT_WAITING_FOREVER); + } - result = rt_mutex_take(&fslock, RT_WAITING_FOREVER); if (result != RT_EOK) { RT_ASSERT(0); @@ -109,6 +118,54 @@ void dfs_unlock(void) rt_mutex_release(&fslock); } +static int fd_alloc(struct dfs_fdtable *fdt, int startfd) +{ + int idx; + + /* find an empty fd entry */ + for (idx = startfd; idx < fdt->maxfd; idx++) + { + if (fdt->fds[idx] == RT_NULL) + break; + if (fdt->fds[idx]->ref_count == 0) + break; + } + + /* allocate a larger FD container */ + if (idx == fdt->maxfd && fdt->maxfd < DFS_FD_MAX) + { + int cnt, index; + struct dfs_fd **fds; + + /* increase the number of FD with 4 step length */ + cnt = fdt->maxfd + 4; + cnt = cnt > DFS_FD_MAX? DFS_FD_MAX : cnt; + + fds = rt_realloc(fdt->fds, cnt * sizeof(struct dfs_fd *)); + if (fds == NULL) goto __out; /* return fdt->maxfd */ + + /* clean the new allocated fds */ + for (index = fdt->maxfd; index < cnt; index ++) + { + fds[index] = NULL; + } + + fdt->fds = fds; + fdt->maxfd = cnt; + } + + /* allocate 'struct dfs_fd' */ + if (idx < fdt->maxfd &&fdt->fds[idx] == RT_NULL) + { + fdt->fds[idx] = rt_malloc(sizeof(struct dfs_fd)); + if (fdt->fds[idx] == RT_NULL) + idx = fdt->maxfd; + } + +__out: + return idx; +} + /** * @ingroup Fd * This function will allocate a file descriptor. @@ -119,21 +176,23 @@ int fd_new(void) { struct dfs_fd *d; int idx; + struct dfs_fdtable *fdt; + fdt = dfs_fdtable_get(); /* lock filesystem */ dfs_lock(); /* find an empty fd entry */ - for (idx = 0; idx < DFS_FD_MAX && fd_table[idx].ref_count > 0; idx++); + idx = fd_alloc(fdt, 0); /* can't find an empty fd entry */ - if (idx == DFS_FD_MAX) + if (idx == fdt->maxfd) { idx = -(1 + DFS_FD_OFFSET); goto __result; } - d = &(fd_table[idx]); + d = fdt->fds[idx]; d->ref_count = 1; d->magic = DFS_FD_MAGIC; @@ -154,13 +213,15 @@ __result: struct dfs_fd *fd_get(int fd) { struct dfs_fd *d; + struct dfs_fdtable *fdt; + fdt = dfs_fdtable_get(); fd = fd - DFS_FD_OFFSET; - if (fd < 0 || fd >= DFS_FD_MAX) + if (fd < 0 || fd >= fdt->maxfd) return NULL; dfs_lock(); - d = &fd_table[fd]; + d = fdt->fds[fd]; /* check dfs_fd valid or not */ if (d->magic != DFS_FD_MAGIC) @@ -186,12 +247,25 @@ void fd_put(struct dfs_fd *fd) RT_ASSERT(fd != NULL); dfs_lock(); + fd->ref_count --; /* clear this fd entry */ if (fd->ref_count == 0) { - memset(fd, 0, sizeof(struct dfs_fd)); + int index; + struct dfs_fdtable *fdt; + + fdt = dfs_fdtable_get(); + for (index = 0; index < fdt->maxfd; index ++) + { + if (fdt->fds[index] == fd) + { + rt_free(fd); + fdt->fds[index] = 0; + break; + } + } } dfs_unlock(); } @@ -211,7 +285,9 @@ int fd_is_open(const char *pathname) unsigned int index; struct dfs_filesystem *fs; struct dfs_fd *fd; + struct dfs_fdtable *fdt; + fdt = dfs_fdtable_get(); fullpath = dfs_normalize_path(NULL, pathname); if (fullpath != NULL) { @@ -233,11 +309,10 @@ int fd_is_open(const char *pathname) dfs_lock(); - for (index = 0; index < DFS_FD_MAX; index++) + for (index = 0; index < fdt->maxfd; index++) { - fd = &(fd_table[index]); - if (fd->fops == NULL) - continue; + fd = fdt->fds[index]; + if (fd == NULL) continue; if (fd->fops == fs->ops->fops && strcmp(fd->path, mountpath) == 0) { @@ -414,17 +489,43 @@ up_one: return fullpath; } RTM_EXPORT(dfs_normalize_path); + +/** + * This function will get the file descriptor table of current process. + */ +struct dfs_fdtable* dfs_fdtable_get(void) +{ + struct dfs_fdtable *fdt; +#ifdef RT_USING_LWP + struct rt_lwp *lwp; + + lwp = (struct rt_lwp *)rt_thread_self()->user_data; + if (lwp) + fdt = &lwp->fdt; + else + fdt = &_fdtab; +#else + fdt = &_fdtab; +#endif + + return fdt; +} + #ifdef RT_USING_FINSH #include int list_fd(void) { int index; + struct dfs_fdtable *fd_table; + + fd_table = dfs_fdtable_get(); + if (!fd_table) return -1; rt_enter_critical(); - for (index = 0; index < DFS_FD_MAX; index ++) + for (index = 0; index < fd_table->maxfd; index ++) { - struct dfs_fd *fd = &(fd_table[index]); + struct dfs_fd *fd = fd_table->fds[index]; if (fd->fops) { diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig new file mode 100644 index 000000000..e3f13a3b6 --- /dev/null +++ b/components/lwp/Kconfig @@ -0,0 +1,7 @@ +config RT_USING_LWP + bool "Using light-weight process" + select RT_USING_DFS + depends on ARCH_ARM_CORTEX_M + default n + help + The lwP is a light weight process running in user mode. diff --git a/components/lwp/SConscript b/components/lwp/SConscript new file mode 100644 index 000000000..f54d9422e --- /dev/null +++ b/components/lwp/SConscript @@ -0,0 +1,20 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [] + +support_arch = {"arm": ["cortex-m3", "cortex-m4", "cortex-m7"]} +platform_file = {'armcc': 'rvds.S', 'gcc': 'gcc.S', 'iar': 'iar.S'} + +if rtconfig.PLATFORM in platform_file.keys(): # support platforms + if rtconfig.ARCH in support_arch.keys() and rtconfig.CPU in support_arch[rtconfig.ARCH]: + # arch/arm/cortex-m7/lwp_gcc.S + asm_path = 'arch/' + rtconfig.ARCH + '/' + rtconfig.CPU + '/*_' + platform_file[rtconfig.PLATFORM] + src = Glob('*.c') + Glob(asm_path) + CPPPATH = [cwd] + +group = DefineGroup('lwP', src, depend = ['RT_USING_LWP'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/lwp/arch/arm/cortex-m3/lwp_gcc.S b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S new file mode 100644 index 000000000..8c866f999 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S @@ -0,0 +1,176 @@ +/* + * File : lwp_gcc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +.cpu cortex-m3 +.syntax unified +.thumb +.text + +/* + * void* lwp_get_sys_api(rt_uint32_t number); + */ +.global lwp_get_sys_api +.global lwp_get_kernel_sp +.global lwp_set_kernel_sp + + +/* + * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); + */ +.global lwp_user_entry +.type lwp_user_entry, % function +lwp_user_entry: + PUSH {R0 - R1} /* push text&data addr. */ + + MOV R0, SP /* v1 = SP */ + BL lwp_set_kernel_sp /* lwp_set_kernel_sp(v1) */ + + POP {R0 - R1} /* pop app address to R1. */ + + /* set CPU to user-thread mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 /* use PSP, user-thread mode. */ + MSR CONTROL, R2 + + /* set data address. */ + MOV R9, R1 + + /* run app, only Thumb-mode. */ + ORR R0, R0, #0x01 + BX R0 + +/* + * void SVC_Handler(void); + */ +.global SVC_Handler +.type SVC_Handler, % function +SVC_Handler: + + PUSH {LR} + + /* get user SP. */ + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} /* push app SP. */ + MOV R2, R1 + + STMFD R2!, {R4 - R11} /* push app R4-R11 to app stack , and R1 not change. */ + + /* get SVC number. */ + LDR R0, [R1, #24] /* get the app LR. */ + LDRB R0, [R0, #-2] /* get the SVC No. from instruction. */ + + /* get kernel system API */ + BL lwp_get_sys_api + + /* if(api == NULL) return; */ + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + /* push api */ + PUSH {R0} + + /* get kernel SP to R0. */ + BL lwp_get_kernel_sp + + POP {R2} /* pop api to R2. */ + POP {R1} /* pop app SP to R1. */ + + /* copy R1(app SP) to R0(server SP). */ + LDMFD R1, {R4 - R11} /* pop exception_stack_frame to r4 - r11 register */ + STMFD R0!, {R4 - R11} /* push exception_stack_frame to server SP. */ + + POP {LR} + PUSH {LR} + + /* save app SP. */ + PUSH {R0 - R3} + SUB R0, R1, #0x20 /* keep {R4 - R11} */ + BL lwp_set_kernel_sp + POP {R0 - R3} + + /* set to thread-privilege mode. */ + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + /* call api. */ + LDR R3, = svc_exit + STR R3, [R0, #20] /* update LR */ + STR R2, [R0, #24] /* update api to PC */ + MSR PSP, R0 /* update stack pointer */ + POP {LR} /* 0xFFFFFFED */ + + ORR LR, LR, #0x10 + + BX LR + +/* +* void svc_exit(void); +*/ +.global svc_exit +.type svc_exit, % function +svc_exit: + + /* get user SP. */ + PUSH {R0} /* push result to SP. */ + BL lwp_get_kernel_sp + + LDMFD R0!, {R4 - R11} /* pop app {R4 - R11} */ + + ADD R0, R0, #16 /* skip R0-R3 */ + LDMFD R0!, {R12, LR} + LDMFD R0!, {R1} /* pop PC to R1 */ + LDMFD R0!, {R2} /* pop PSR to R2 */ + + /* align to 2 words */ + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} /* push user-SP to SP */ + + /* save server SP. */ + ADD R0, SP, #0x08 /* [user-SP, result] */ + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} /* pop user-SP to R3 */ + POP {R0} /* restore API result. */ + + MSR APSR, R2 /* restore PSR */ + MSR PSP, R3 /* restore app stack pointer */ + + /* restore to PSP & thread-unprivilege mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + /* return to lwp. */ + ORR R1, R1, #0x01 /* only Thumb-mode. */ + BX R1 /* return to user app. */ diff --git a/components/lwp/arch/arm/cortex-m3/lwp_iar.S b/components/lwp/arch/arm/cortex-m3/lwp_iar.S new file mode 100644 index 000000000..e00424cbe --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_iar.S @@ -0,0 +1,176 @@ +;/* +; * File : lwp_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + SECTION .text:CODE(2) + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ + EXPORT lwp_user_entry +lwp_user_entry: + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + +;/* +; * void SVC_Handler(void); +; */ + EXPORT SVC_Handler +SVC_Handler: + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + ITTT EQ + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} + SUB R0, R1, #0x20 ; keep {R4 - R11} + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + +;/* +; * void svc_exit(void); +; */ + EXPORT svc_exit +svc_exit: + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + END diff --git a/components/lwp/arch/arm/cortex-m3/lwp_rvds.S b/components/lwp/arch/arm/cortex-m3/lwp_rvds.S new file mode 100644 index 000000000..ff79cfda4 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_rvds.S @@ -0,0 +1,184 @@ +;/* +; * File : lwp_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + AREA |.text|, CODE, READONLY, ALIGN=2 + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ +lwp_user_entry PROC + EXPORT lwp_user_entry + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + + ; never reach here! + ENDP + +;/* +; * void SVC_Handler(void); +; */ +SVC_Handler PROC + EXPORT SVC_Handler + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} + SUB R0, R1, #0x20 ; keep {R4 - R11} + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + + ENDP + +;/* +; * void svc_exit(void); +; */ +svc_exit PROC + EXPORT svc_exit + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + ENDP + + ALIGN + + END diff --git a/components/lwp/arch/arm/cortex-m4/lwp_gcc.S b/components/lwp/arch/arm/cortex-m4/lwp_gcc.S new file mode 100644 index 000000000..fd46d6142 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_gcc.S @@ -0,0 +1,210 @@ +/* + * File : lwp_gcc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +.cpu cortex-m4 +.syntax unified +.thumb +.text + +/* + * void* lwp_get_sys_api(rt_uint32_t number); + */ +.global lwp_get_sys_api +.global lwp_get_kernel_sp +.global lwp_set_kernel_sp + + +/* + * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); + */ +.global lwp_user_entry +.type lwp_user_entry, % function +lwp_user_entry: + PUSH {R0 - R1} /* push text&data addr. */ + + MOV R0, SP /* v1 = SP */ + BL lwp_set_kernel_sp /* lwp_set_kernel_sp(v1) */ + + POP {R0 - R1} /* pop app address to R1. */ + + /* set CPU to user-thread mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 /* use PSP, user-thread mode. */ + MSR CONTROL, R2 + + /* set data address. */ + MOV R9, R1 + + /* run app, only Thumb-mode. */ + ORR R0, R0, #0x01 + BX R0 + +/* + * void SVC_Handler(void); + */ +.global SVC_Handler +.type SVC_Handler, % function +SVC_Handler: + + PUSH {LR} + + /* get user SP. */ + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} /* push app SP. */ + MOV R2, R1 + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST LR, #0x10 + VSTMDBEQ R2!, {D8 - D15} +#endif + + STMFD R2!, {R4 - R11} /* push app R4-R11 to app stack , and R1 not change. */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + MOV R4, #0x00 /* flag = 0 */ + TST LR, #0x10 /* if(!EXC_RETURN[4]) */ + MOVEQ R4, #0x01 /* flag = 1 */ + STMFD R2!, {R4} /* push flag */ +#endif + + /* get SVC number. */ + LDR R0, [R1, #24] /* get the app LR. */ + LDRB R0, [R0, #-2] /* get the SVC No. from instruction. */ + + /* get kernel system API */ + BL lwp_get_sys_api + + /* if(api == NULL) return; */ + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + /* push api */ + PUSH {R0} + + /* get kernel SP to R0. */ + BL lwp_get_kernel_sp + + POP {R2} /* pop api to R2. */ + POP {R1} /* pop app SP to R1. */ + + /* copy R1(app SP) to R0(server SP). */ + LDMFD R1, {R4 - R11} /* pop exception_stack_frame to r4 - r11 register */ + STMFD R0!, {R4 - R11} /* push exception_stack_frame to server SP. */ + + POP {LR} + PUSH {LR} + + /* save app SP. */ + PUSH {R0 - R3} +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST LR, #0x10 + SUBEQ R0, R1, #0x64 /* keep {R4 - R11}, {D8-D15}, FLAG */ + SUBNE R0, R1, #0x24 /* keep {R4 - R11}, FLAG */ +#else + SUB R0, R1, #0x20 /* keep {R4 - R11} */ +#endif + BL lwp_set_kernel_sp + POP {R0 - R3} + + /* set to thread-privilege mode. */ + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + /* call api. */ + LDR R3, = svc_exit + STR R3, [R0, #20] /* update LR */ + STR R2, [R0, #24] /* update api to PC */ + MSR PSP, R0 /* update stack pointer */ + POP {LR} /* 0xFFFFFFED */ + + ORR LR, LR, #0x10 + + BX LR + +/* +* void svc_exit(void); +*/ +.global svc_exit +.type svc_exit, % function +svc_exit: + + /* get user SP. */ + PUSH {R0} /* push result to SP. */ + BL lwp_get_kernel_sp + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + LDMFD R0!, {R3} /* pop flag */ +#endif + + LDMFD R0!, {R4 - R11} /* pop app {R4 - R11} */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP R3, #0 /* if(flag_r3 != 0) */ + VLDMIANE R0!, {D8 - D15} /* pop FPU register s16~s31 */ +#endif + + ADD R0, R0, #16 /* skip R0-R3 */ + LDMFD R0!, {R12, LR} + LDMFD R0!, {R1} /* pop PC to R1 */ + LDMFD R0!, {R2} /* pop PSR to R2 */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP R3, #0 /* if(flag_r3 != 0) */ + VLDMIANE R0!, {D0 - D7} /* pop FPU register s16~s31 */ + LDMIANE R0!, {R3} + VMSRNE FPSCR, R3 +#endif + + /* align to 2 words */ + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} /* push user-SP to SP */ + + /* save server SP. */ + ADD R0, SP, #0x08 /* [user-SP, result] */ + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} /* pop user-SP to R3 */ + POP {R0} /* restore API result. */ + + MSR APSR, R2 /* restore PSR */ + MSR PSP, R3 /* restore app stack pointer */ + + /* restore to PSP & thread-unprivilege mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + /* return to lwp. */ + ORR R1, R1, #0x01 /* only Thumb-mode. */ + BX R1 /* return to user app. */ diff --git a/components/lwp/arch/arm/cortex-m4/lwp_iar.S b/components/lwp/arch/arm/cortex-m4/lwp_iar.S new file mode 100644 index 000000000..27ca8778e --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_iar.S @@ -0,0 +1,215 @@ +;/* +; * File : lwp_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + SECTION .text:CODE(2) + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ + EXPORT lwp_user_entry +lwp_user_entry: + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + +;/* +; * void SVC_Handler(void); +; */ + EXPORT SVC_Handler +SVC_Handler: + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + +#if defined ( __ARMVFP__ ) + TST LR, #0x10 + IT EQ + VSTMDBEQ R2!, {D8 - D15} +#endif + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + +#if defined ( __ARMVFP__ ) + MOV R4, #0x00 ; flag = 0 + TST LR, #0x10 ; if(!EXC_RETURN[4]) + IT EQ + MOVEQ R4, #0x01 ; flag = 1 + STMFD R2!, {R4} ; push flag +#endif + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + ITTT EQ + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} +#if defined ( __ARMVFP__ ) + TST LR, #0x10 + ITE EQ + SUBEQ R0, R1, #0x64 ; keep {R4 - R11}, {D8-D15}, FLAG + SUBNE R0, R1, #0x24 ; keep {R4 - R11}, FLAG +#else + SUB R0, R1, #0x20 ; keep {R4 - R11} +#endif + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + +;/* +; * void svc_exit(void); +; */ + EXPORT svc_exit +svc_exit: + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + +#if defined ( __ARMVFP__ ) + LDMFD R0!, {R3} ; pop flag +#endif + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + +#if defined ( __ARMVFP__ ) + CMP R3, #0 ; if(flag_r3 != 0) + IT NE + VLDMIANE R0!, {D8 - D15} ; pop FPU register s16~s31 +#endif + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + +#if defined ( __ARMVFP__ ) + CMP R3, #0 ; if(flag_r3 != 0) + ITTT NE + VLDMIANE R0!, {D0 - D7} ; pop FPU register s16~s31 + LDMIANE R0!, {R3} + VMSRNE FPSCR, R3 +#endif + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + END diff --git a/components/lwp/arch/arm/cortex-m4/lwp_rvds.S b/components/lwp/arch/arm/cortex-m4/lwp_rvds.S new file mode 100644 index 000000000..16e81710c --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_rvds.S @@ -0,0 +1,219 @@ +;/* +; * File : lwp_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + AREA |.text|, CODE, READONLY, ALIGN=2 + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ +lwp_user_entry PROC + EXPORT lwp_user_entry + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + + ; never reach here! + ENDP + +;/* +; * void SVC_Handler(void); +; */ +SVC_Handler PROC + EXPORT SVC_Handler + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + + IF {FPU} != "SoftVFP" + TST LR, #0x10 + VSTMFDEQ R2!, {D8 - D15} + ENDIF + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + + IF {FPU} != "SoftVFP" + MOV R4, #0x00 ; flag = 0 + TST LR, #0x10 ; if(!EXC_RETURN[4]) + MOVEQ R4, #0x01 ; flag = 1 + STMFD R2!, {R4} ; push flag + ENDIF + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} + IF {FPU} != "SoftVFP" + TST LR, #0x10 + SUBEQ R0, R1, #0x64 ; keep {R4 - R11}, {D8-D15}, FLAG + SUBNE R0, R1, #0x24 ; keep {R4 - R11}, FLAG + ELSE + SUB R0, R1, #0x20 ; keep {R4 - R11} + ENDIF + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + + ENDP + +;/* +; * void svc_exit(void); +; */ +svc_exit PROC + EXPORT svc_exit + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + + IF {FPU} != "SoftVFP" + LDMFD R0!, {R3} ; pop flag + ENDIF + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + + IF {FPU} != "SoftVFP" + CMP R3, #0 ; if(flag_r3 != 0) + VLDMFDNE R0!, {D8 - D15} ; pop FPU register s16~s31 + ENDIF + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + + IF {FPU} != "SoftVFP" + CMP R3, #0 ; if(flag_r3 != 0) + VLDMFDNE R0!, {D0 - D7} ; pop FPU register s16~s31 + LDMFDNE R0!, {R3} + VMSRNE FPSCR, R3 + + ENDIF + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + ENDP + + ALIGN + + END diff --git a/components/lwp/arch/arm/cortex-m7/lwp_gcc.S b/components/lwp/arch/arm/cortex-m7/lwp_gcc.S new file mode 100644 index 000000000..fd46d6142 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_gcc.S @@ -0,0 +1,210 @@ +/* + * File : lwp_gcc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +.cpu cortex-m4 +.syntax unified +.thumb +.text + +/* + * void* lwp_get_sys_api(rt_uint32_t number); + */ +.global lwp_get_sys_api +.global lwp_get_kernel_sp +.global lwp_set_kernel_sp + + +/* + * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); + */ +.global lwp_user_entry +.type lwp_user_entry, % function +lwp_user_entry: + PUSH {R0 - R1} /* push text&data addr. */ + + MOV R0, SP /* v1 = SP */ + BL lwp_set_kernel_sp /* lwp_set_kernel_sp(v1) */ + + POP {R0 - R1} /* pop app address to R1. */ + + /* set CPU to user-thread mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 /* use PSP, user-thread mode. */ + MSR CONTROL, R2 + + /* set data address. */ + MOV R9, R1 + + /* run app, only Thumb-mode. */ + ORR R0, R0, #0x01 + BX R0 + +/* + * void SVC_Handler(void); + */ +.global SVC_Handler +.type SVC_Handler, % function +SVC_Handler: + + PUSH {LR} + + /* get user SP. */ + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} /* push app SP. */ + MOV R2, R1 + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST LR, #0x10 + VSTMDBEQ R2!, {D8 - D15} +#endif + + STMFD R2!, {R4 - R11} /* push app R4-R11 to app stack , and R1 not change. */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + MOV R4, #0x00 /* flag = 0 */ + TST LR, #0x10 /* if(!EXC_RETURN[4]) */ + MOVEQ R4, #0x01 /* flag = 1 */ + STMFD R2!, {R4} /* push flag */ +#endif + + /* get SVC number. */ + LDR R0, [R1, #24] /* get the app LR. */ + LDRB R0, [R0, #-2] /* get the SVC No. from instruction. */ + + /* get kernel system API */ + BL lwp_get_sys_api + + /* if(api == NULL) return; */ + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + /* push api */ + PUSH {R0} + + /* get kernel SP to R0. */ + BL lwp_get_kernel_sp + + POP {R2} /* pop api to R2. */ + POP {R1} /* pop app SP to R1. */ + + /* copy R1(app SP) to R0(server SP). */ + LDMFD R1, {R4 - R11} /* pop exception_stack_frame to r4 - r11 register */ + STMFD R0!, {R4 - R11} /* push exception_stack_frame to server SP. */ + + POP {LR} + PUSH {LR} + + /* save app SP. */ + PUSH {R0 - R3} +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST LR, #0x10 + SUBEQ R0, R1, #0x64 /* keep {R4 - R11}, {D8-D15}, FLAG */ + SUBNE R0, R1, #0x24 /* keep {R4 - R11}, FLAG */ +#else + SUB R0, R1, #0x20 /* keep {R4 - R11} */ +#endif + BL lwp_set_kernel_sp + POP {R0 - R3} + + /* set to thread-privilege mode. */ + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + /* call api. */ + LDR R3, = svc_exit + STR R3, [R0, #20] /* update LR */ + STR R2, [R0, #24] /* update api to PC */ + MSR PSP, R0 /* update stack pointer */ + POP {LR} /* 0xFFFFFFED */ + + ORR LR, LR, #0x10 + + BX LR + +/* +* void svc_exit(void); +*/ +.global svc_exit +.type svc_exit, % function +svc_exit: + + /* get user SP. */ + PUSH {R0} /* push result to SP. */ + BL lwp_get_kernel_sp + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + LDMFD R0!, {R3} /* pop flag */ +#endif + + LDMFD R0!, {R4 - R11} /* pop app {R4 - R11} */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP R3, #0 /* if(flag_r3 != 0) */ + VLDMIANE R0!, {D8 - D15} /* pop FPU register s16~s31 */ +#endif + + ADD R0, R0, #16 /* skip R0-R3 */ + LDMFD R0!, {R12, LR} + LDMFD R0!, {R1} /* pop PC to R1 */ + LDMFD R0!, {R2} /* pop PSR to R2 */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP R3, #0 /* if(flag_r3 != 0) */ + VLDMIANE R0!, {D0 - D7} /* pop FPU register s16~s31 */ + LDMIANE R0!, {R3} + VMSRNE FPSCR, R3 +#endif + + /* align to 2 words */ + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} /* push user-SP to SP */ + + /* save server SP. */ + ADD R0, SP, #0x08 /* [user-SP, result] */ + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} /* pop user-SP to R3 */ + POP {R0} /* restore API result. */ + + MSR APSR, R2 /* restore PSR */ + MSR PSP, R3 /* restore app stack pointer */ + + /* restore to PSP & thread-unprivilege mode. */ + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + /* return to lwp. */ + ORR R1, R1, #0x01 /* only Thumb-mode. */ + BX R1 /* return to user app. */ diff --git a/components/lwp/arch/arm/cortex-m7/lwp_iar.S b/components/lwp/arch/arm/cortex-m7/lwp_iar.S new file mode 100644 index 000000000..27ca8778e --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_iar.S @@ -0,0 +1,215 @@ +;/* +; * File : lwp_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + SECTION .text:CODE(2) + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ + EXPORT lwp_user_entry +lwp_user_entry: + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + +;/* +; * void SVC_Handler(void); +; */ + EXPORT SVC_Handler +SVC_Handler: + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + +#if defined ( __ARMVFP__ ) + TST LR, #0x10 + IT EQ + VSTMDBEQ R2!, {D8 - D15} +#endif + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + +#if defined ( __ARMVFP__ ) + MOV R4, #0x00 ; flag = 0 + TST LR, #0x10 ; if(!EXC_RETURN[4]) + IT EQ + MOVEQ R4, #0x01 ; flag = 1 + STMFD R2!, {R4} ; push flag +#endif + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + ITTT EQ + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} +#if defined ( __ARMVFP__ ) + TST LR, #0x10 + ITE EQ + SUBEQ R0, R1, #0x64 ; keep {R4 - R11}, {D8-D15}, FLAG + SUBNE R0, R1, #0x24 ; keep {R4 - R11}, FLAG +#else + SUB R0, R1, #0x20 ; keep {R4 - R11} +#endif + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + +;/* +; * void svc_exit(void); +; */ + EXPORT svc_exit +svc_exit: + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + +#if defined ( __ARMVFP__ ) + LDMFD R0!, {R3} ; pop flag +#endif + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + +#if defined ( __ARMVFP__ ) + CMP R3, #0 ; if(flag_r3 != 0) + IT NE + VLDMIANE R0!, {D8 - D15} ; pop FPU register s16~s31 +#endif + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + +#if defined ( __ARMVFP__ ) + CMP R3, #0 ; if(flag_r3 != 0) + ITTT NE + VLDMIANE R0!, {D0 - D7} ; pop FPU register s16~s31 + LDMIANE R0!, {R3} + VMSRNE FPSCR, R3 +#endif + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + END diff --git a/components/lwp/arch/arm/cortex-m7/lwp_rvds.S b/components/lwp/arch/arm/cortex-m7/lwp_rvds.S new file mode 100644 index 000000000..16e81710c --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_rvds.S @@ -0,0 +1,219 @@ +;/* +; * File : lwp_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; */ + + AREA |.text|, CODE, READONLY, ALIGN=2 + THUMB + REQUIRE8 + PRESERVE8 + +;/* +; * void* lwp_get_sys_api(rt_uint32_t number); +; */ + IMPORT lwp_get_sys_api + IMPORT lwp_get_kernel_sp + IMPORT lwp_set_kernel_sp + +;/* +; * void lwp_user_entry(u32 R0_text_addr, u32 R1_data_addr); +; */ +lwp_user_entry PROC + EXPORT lwp_user_entry + + PUSH {R0-R1} ; push text&data addr. + + MOV R0, SP ; v1 = SP + BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1) + + POP {R0-R1} ; pop app address to R1. + + ; set CPU to user-thread mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 ; use PSP, user-thread mode. + MSR CONTROL, R2 + + ; set data address. + MOV R9, R1 + + ; run app, only Thumb-mode. + ORR R0, R0, #0x01 + BX R0 + + ; never reach here! + ENDP + +;/* +; * void SVC_Handler(void); +; */ +SVC_Handler PROC + EXPORT SVC_Handler + + PUSH {LR} + + ; get user SP. + TST LR, #0x4 + ITE EQ + MRSEQ R1, MSP + MRSNE R1, PSP + + PUSH {R1} ; push app SP. + MOV R2, R1 + + IF {FPU} != "SoftVFP" + TST LR, #0x10 + VSTMFDEQ R2!, {D8 - D15} + ENDIF + + STMFD R2!, {R4 - R11} ; push app R4-R11 to app stack , and R1 not change. + + IF {FPU} != "SoftVFP" + MOV R4, #0x00 ; flag = 0 + TST LR, #0x10 ; if(!EXC_RETURN[4]) + MOVEQ R4, #0x01 ; flag = 1 + STMFD R2!, {R4} ; push flag + ENDIF + + ; get SVC number. + LDR R0, [R1, #24] ; get the app LR. + LDRB R0, [R0, #-2] ; get the SVC No. from instruction. + + ; get kernel system API + BL lwp_get_sys_api + + ; if(api == NULL) return; + CMP R0, #0 + POPEQ {R1} + POPEQ {LR} + BXEQ LR + + ; push api + PUSH {R0} + + ; get kernel SP to R0. + BL lwp_get_kernel_sp + + POP {R2} ; pop api to R2. + POP {R1} ; pop app SP to R1. + + ; copy R1(app SP) to R0(server SP). + LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register + STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP. + + POP {LR} + PUSH {LR} + + ; save app SP. + PUSH {R0 - R3} + IF {FPU} != "SoftVFP" + TST LR, #0x10 + SUBEQ R0, R1, #0x64 ; keep {R4 - R11}, {D8-D15}, FLAG + SUBNE R0, R1, #0x24 ; keep {R4 - R11}, FLAG + ELSE + SUB R0, R1, #0x20 ; keep {R4 - R11} + ENDIF + BL lwp_set_kernel_sp + POP {R0 - R3} + + ; set to thread-privilege mode. + MRS R3, CONTROL + BIC R3, R3, #0x01 + ORR R3, R3, #0x02 + MSR CONTROL, R3 + + ; call api. + LDR R3, =svc_exit + STR R3, [R0, #20] ; update LR + STR R2, [R0, #24] ; update api to PC + MSR PSP, R0 ; update stack pointer + POP {LR} ; 0xFFFFFFED + + ORR LR, LR, #0x10 + + BX LR + + ENDP + +;/* +; * void svc_exit(void); +; */ +svc_exit PROC + EXPORT svc_exit + + ; get user SP. + PUSH {R0} ; push result to SP. + BL lwp_get_kernel_sp + + IF {FPU} != "SoftVFP" + LDMFD R0!, {R3} ; pop flag + ENDIF + + LDMFD R0!, {R4 - R11} ; pop app {R4 - R11} + + IF {FPU} != "SoftVFP" + CMP R3, #0 ; if(flag_r3 != 0) + VLDMFDNE R0!, {D8 - D15} ; pop FPU register s16~s31 + ENDIF + + ADD R0, R0, #16 ; skip R0-R3 + LDMFD R0!, {R12, LR} ; + LDMFD R0!, {R1} ; pop PC to R1 + LDMFD R0!, {R2} ; pop PSR to R2 + + IF {FPU} != "SoftVFP" + CMP R3, #0 ; if(flag_r3 != 0) + VLDMFDNE R0!, {D0 - D7} ; pop FPU register s16~s31 + LDMFDNE R0!, {R3} + VMSRNE FPSCR, R3 + + ENDIF + + ; align to 2 words + ADD R0, R0, #0x07 + BIC R0, R0, #0x07 + PUSH {R0} ; push user-SP to SP + + ; save server SP. + ADD R0, SP, #0x08 ; [user-SP, result] + PUSH {R1 - R2, LR} + BL lwp_set_kernel_sp + POP {R1 - R2, LR} + + POP {R3} ; pop user-SP to R3 + POP {R0} ; restore API result. + + MSR APSR, R2 ; restore PSR + MSR PSP, R3 ; restore app stack pointer + + ; restore to PSP & thread-unprivilege mode. + MRS R2, CONTROL + ORR R2, R2, #0x03 + MSR CONTROL, R2 + + ; return to lwp. + ORR R1, R1, #0x01 ; only Thumb-mode. + BX R1 ; return to user app. + + ENDP + + ALIGN + + END diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c new file mode 100644 index 000000000..6837e30b5 --- /dev/null +++ b/components/lwp/lwp.c @@ -0,0 +1,364 @@ +/* + * File : clock.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#include +#include +#include + +#ifdef RT_USING_FINSH + #include +#endif + +#ifndef RT_USING_DFS + #error "lwp need file system(RT_USING_DFS)" +#endif + +#include "lwp.h" + +#define DBG_ENABLE +#define DBG_SECTION_NAME "[LWP]" +#define DBG_COLOR +#define DBG_LEVEL DBG_LOG +#include + +extern rt_thread_t rt_current_thread; +extern void lwp_user_entry(const void *text, void *data); + +/** + * RT-Thread light-weight process + */ +void lwp_set_kernel_sp(uint32_t *sp) +{ + struct rt_lwp *user_data; + user_data = (struct rt_lwp *)rt_current_thread->user_data; + user_data->kernel_sp = sp; +} + +uint32_t *lwp_get_kernel_sp(void) +{ + struct rt_lwp *user_data; + user_data = (struct rt_lwp *)rt_current_thread->user_data; + + return user_data->kernel_sp; +} + +static int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size) +{ + int fd; + uint8_t *ptr; + int result = RT_EOK; + int nbytes; + struct lwp_header header; + struct lwp_chunk chunk; + + /* check file name */ + RT_ASSERT(filename != RT_NULL); + /* check lwp control block */ + RT_ASSERT(lwp != RT_NULL); + + memset(lwp, 0x00, sizeof(struct rt_lwp)); + + if (load_addr != RT_NULL) + { + lwp->lwp_type = LWP_TYPE_FIX_ADDR; + ptr = load_addr; + } + else + { + lwp->lwp_type = LWP_TYPE_DYN_ADDR; + ptr = RT_NULL; + } + + /* open lwp */ + fd = open(filename, 0, O_RDONLY); + if (fd < 0) + { + dbg_log(DBG_ERROR, "open file:%s failed!\n", filename); + result = -RT_ENOSYS; + goto _exit; + } + + /* read lwp header */ + nbytes = read(fd, &header, sizeof(struct lwp_header)); + if (nbytes != sizeof(struct lwp_header)) + { + dbg_log(DBG_ERROR, "read lwp header return error size: %d!\n", nbytes); + result = -RT_EIO; + goto _exit; + } + + /* check file header */ + if (header.magic != LWP_MAGIC) + { + dbg_log(DBG_ERROR, "erro header magic number: 0x%02X\n", header.magic); + result = -RT_EINVAL; + goto _exit; + } + + /* read text chunk info */ + nbytes = read(fd, &chunk, sizeof(struct lwp_chunk)); + if (nbytes != sizeof(struct lwp_chunk)) + { + dbg_log(DBG_ERROR, "read text chunk info failed!\n"); + result = -RT_EIO; + goto _exit; + } + + dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n", + "text", /*chunk.name*/ chunk.total_len, chunk.data_len, chunk.data_len_space); + + /* load text */ + { + lwp->text_size = RT_ALIGN(chunk.data_len_space, 4); + if (load_addr) + lwp->text_entry = ptr; + else + { +#ifdef RT_USING_CACHE + lwp->text_entry = (rt_uint8_t *)rt_malloc_align(lwp->text_size, RT_CPU_CACHE_LINE_SZ); +#else + lwp->text_entry = (rt_uint8_t *)rt_malloc(lwp->text_size); +#endif + + if (lwp->text_entry == RT_NULL) + { + dbg_log(DBG_ERROR, "alloc text memory faild!\n"); + result = -RT_ENOMEM; + goto _exit; + } + else + { + dbg_log(DBG_LOG, "lwp text malloc : %p, size: %d!\n", lwp->text_entry, lwp->text_size); + } + } + 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); + + nbytes = read(fd, lwp->text_entry, chunk.data_len); + if (nbytes != chunk.data_len) + { + dbg_log(DBG_ERROR, "read text region from file failed!\n"); + result = -RT_EIO; + goto _exit; + } +#ifdef RT_USING_CACHE + else + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size); + rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size); + } +#endif + + if (ptr != RT_NULL) ptr += nbytes; + + /* skip text hole */ + if ((chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len)) + { + dbg_log(DBG_LOG, "skip text hole %d!\n", (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len)); + lseek(fd, (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len), SEEK_CUR); + } + } + + /* load data */ + nbytes = read(fd, &chunk, sizeof(struct lwp_chunk)); + if (nbytes != sizeof(struct lwp_chunk)) + { + dbg_log(DBG_ERROR, "read data chunk info failed!\n"); + result = -RT_EIO; + goto _exit; + } + + dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n", + chunk.name, chunk.total_len, chunk.data_len, chunk.data_len_space); + + { + lwp->data_size = RT_ALIGN(chunk.data_len_space, 4); + if (load_addr) + lwp->data = ptr; + else + { + lwp->data = rt_malloc(lwp->data_size); + if (lwp->data == RT_NULL) + { + dbg_log(DBG_ERROR, "alloc data memory faild!\n"); + result = -RT_ENOMEM; + goto _exit; + } + else + { + dbg_log(DBG_LOG, "lwp data malloc : %p, size: %d!\n", lwp->data, lwp->data_size); + rt_memset(lwp->data, 0, lwp->data_size); + } + } + + 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); + nbytes = read(fd, lwp->data, chunk.data_len); + if (nbytes != chunk.data_len) + { + dbg_log(DBG_ERROR, "read data region from file failed!\n"); + result = -RT_ERROR; + goto _exit; + } + } + +_exit: + if (fd >= 0) + close(fd); + + if (result != RT_EOK) + { + if (lwp->lwp_type == LWP_TYPE_DYN_ADDR) + { + dbg_log(DBG_ERROR, "lwp dynamic load faild, %d\n", result); + if (lwp->text_entry) + { + dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry); +#ifdef RT_USING_CACHE + rt_free_align(lwp->text_entry); +#else + rt_free(lwp->text_entry); +#endif + } + if (lwp->data) + { + dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data); + rt_free(lwp->data); + } + } + } + + return result; +} + +static void lwp_cleanup(struct rt_thread *tid) +{ + struct rt_lwp *lwp; + + dbg_log(DBG_INFO, "thread: %s, stack_addr: %08X\n", tid->name, tid->stack_addr); + + lwp = (struct rt_lwp *)tid->user_data; + + if (lwp->lwp_type == LWP_TYPE_DYN_ADDR) + { + dbg_log(DBG_INFO, "dynamic lwp\n"); + if (lwp->text_entry) + { + dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry); +#ifdef RT_USING_CACHE + rt_free_align(lwp->text_entry); +#else + rt_free(lwp->text_entry); +#endif + } + if (lwp->data) + { + dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data); + rt_free(lwp->data); + } + } + + dbg_log(DBG_LOG, "lwp free memory pages\n"); + rt_lwp_mem_deinit(lwp); + + dbg_log(DBG_LOG, "lwp free: %p\n", lwp); + rt_free(lwp); + + /* TODO: cleanup fd table */ +} + +static void lwp_thread(void *parameter) +{ + volatile uint32_t tmp; + rt_thread_t tid; + struct rt_lwp *lwp; + + rt_kprintf("%08x %08x\n", &tmp, tmp); + + lwp = (struct rt_lwp *)parameter; + rt_lwp_mem_init(lwp); + tid = rt_thread_self(); + tid->user_data = (rt_uint32_t)lwp; + tid->cleanup = lwp_cleanup; + + lwp_user_entry(lwp->text_entry, lwp->data); +} + +struct rt_lwp *rt_lwp_self(void) +{ + return (struct rt_lwp *)rt_thread_self()->user_data; +} + +int exec(char *filename) +{ + struct rt_lwp *lwp; + int result; + + if (filename == RT_NULL) + return -RT_ERROR; + + lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp)); + if (lwp == RT_NULL) + { + dbg_log(DBG_ERROR, "lwp struct out of memory!\n"); + return -RT_ENOMEM; + } + dbg_log(DBG_INFO, "lwp malloc : %p, size: %d!\n", lwp, sizeof(struct rt_lwp)); + + rt_memset(lwp, 0, sizeof(*lwp)); + result = lwp_load(filename, lwp, RT_NULL, 0); + if (result == RT_EOK) + { + rt_thread_t tid; + + tid = rt_thread_create("user", lwp_thread, (void *)lwp, + 1024 * 4, 2, 200); + if (tid != RT_NULL) + { + 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); + rt_thread_startup(tid); + return RT_EOK; + } + else + { +#ifdef RT_USING_CACHE + rt_free_align(lwp->text_entry); +#else + rt_free(lwp->text_entry); +#endif + rt_free(lwp->data); + } + } + + rt_free(lwp); + + return -RT_ERROR; +} +FINSH_FUNCTION_EXPORT(exec, loader a user app &run); + +int _exec(int argc, char **argv) +{ + if (argc != 2) + return -RT_ERROR; + + return exec(argv[1]); +} +MSH_CMD_EXPORT_ALIAS(_exec, exec, loader a user app &run); diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h new file mode 100644 index 000000000..b1ce96455 --- /dev/null +++ b/components/lwp/lwp.h @@ -0,0 +1,83 @@ +/* + * File : lwp.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __LWP_H__ +#define __LWP_H__ + +#define LWP_MAGIC 0x5A + +#define LWP_TYPE_FIX_ADDR 0x01 +#define LWP_TYPE_DYN_ADDR 0x02 + +#define LWP_ARG_MAX 8 + +#include +#include +#include +#include + +struct rt_lwp +{ + uint8_t lwp_type; + uint8_t heap_cnt; + uint8_t reserv[2]; + + rt_list_t hlist; /**< headp list */ + + uint8_t *text_entry; + uint32_t text_size; + + uint8_t *data; + uint32_t data_size; + + uint32_t *kernel_sp; /**< kernel stack point */ + struct dfs_fdtable fdt; +}; + +struct lwp_header +{ + uint8_t magic; + uint8_t compress_encrypt_algo; + uint16_t reserved; + + uint32_t crc32; +}; + +struct lwp_chunk +{ + uint32_t total_len; + + char name[4]; + uint32_t data_len; + uint32_t data_len_space; +}; + +extern struct rt_lwp *rt_lwp_self(void); + +extern void rt_lwp_mem_init(struct rt_lwp *lwp); +extern void rt_lwp_mem_deinit(struct rt_lwp *lwp); +extern void *rt_lwp_mem_malloc(rt_uint32_t size); +extern void rt_lwp_mem_free(void *addr); +extern void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize); + +#endif diff --git a/components/lwp/lwp_mem.c b/components/lwp/lwp_mem.c new file mode 100644 index 000000000..95c95441b --- /dev/null +++ b/components/lwp/lwp_mem.c @@ -0,0 +1,232 @@ +/* + * File : lwp_mem.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-03-24 Tanek the first version + */ + +#include +#include +#include + +#define DBG_ENABLE +#define DBG_SECTION_NAME "[LWPMEM]" +#define DBG_COLOR +#define DBG_LEVEL DBG_LOG +#include + +// todo: remove repleat code +#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_lwp_memheap_item), RT_ALIGN_SIZE) +#define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE) + +#ifndef LWP_MEM_PAGE_SIZE + #define LWP_MEM_PAGE_SIZE (4 * 1024) +#endif + +#ifndef LWP_MEM_MAX_PAGE_COUNT + #define LWP_MEM_MAX_PAGE_COUNT (256 * 4) +#endif + +static void *rt_lwp_malloc_page(struct rt_lwp *lwp, rt_size_t npages) +{ + void *chunk; + char name[6]; + struct rt_lwp_memheap *lwp_heap; + rt_size_t page_cnt; + + RT_ASSERT(lwp != RT_NULL); + + page_cnt = lwp->heap_cnt + npages; + if (page_cnt > LWP_MEM_MAX_PAGE_COUNT) + { + dbg_log(DBG_ERROR, "alloc new page failed, lwp memory size out of limited: %d\n", page_cnt); + return RT_NULL; + } + + lwp_heap = rt_malloc(sizeof(struct rt_lwp_memheap)); + if (lwp_heap == RT_NULL) + { + dbg_log(DBG_ERROR, "alloc new page head failed, out of memory : %d\n", page_cnt); + return RT_NULL; + } + + chunk = rt_malloc(npages * LWP_MEM_PAGE_SIZE); + if (chunk == RT_NULL) + { + dbg_log(DBG_ERROR, "alloc new page buffer failed, out of memory : %d\n", page_cnt); + rt_free(lwp_heap); + return RT_NULL; + } + + dbg_log(DBG_LOG, "lwp alloc page: %d\n", npages); + + sprintf(name, "lwp%02x", lwp->heap_cnt); + rt_lwp_memheap_init(lwp_heap, name, chunk, npages * LWP_MEM_PAGE_SIZE); + + rt_list_insert_before(&lwp->hlist, &lwp_heap->mlist); + + lwp->heap_cnt += npages; + + return chunk; +} + +static void rt_lwp_free_page(struct rt_lwp *lwp, struct rt_lwp_memheap *lwp_heap) +{ + rt_size_t npages; + + RT_ASSERT(lwp != RT_NULL); + RT_ASSERT(lwp_heap != RT_NULL); + RT_ASSERT(lwp_heap->start_addr != RT_NULL); + + npages = lwp_heap->pool_size / LWP_MEM_PAGE_SIZE; + lwp->heap_cnt -= npages; + + dbg_log(DBG_LOG, "lwp free page: %d\n", npages); + + rt_list_remove(&lwp_heap->mlist); + + rt_free(lwp_heap->start_addr); + rt_free(lwp_heap); +} + +void rt_lwp_mem_init(struct rt_lwp *lwp) +{ + RT_ASSERT(lwp != RT_NULL); + rt_list_init(&lwp->hlist); +} + +void rt_lwp_mem_deinit(struct rt_lwp *lwp) +{ + struct rt_list_node *node; + + RT_ASSERT(lwp != RT_NULL); + + for (node = lwp->hlist.next; node != &(lwp->hlist); node = node->next) + { + struct rt_lwp_memheap *lwp_heap; + lwp_heap = rt_list_entry(node, struct rt_lwp_memheap, mlist); + + RT_ASSERT(lwp_heap != RT_NULL); + + rt_lwp_free_page(lwp, lwp_heap); + } +} + +void *rt_lwp_mem_malloc(rt_uint32_t size) +{ + struct rt_lwp *lwp; + struct rt_list_node *node; + void *addr = RT_NULL; + rt_uint32_t npages; + + if (size == 0) + return RT_NULL; + + lwp = rt_lwp_self(); + RT_ASSERT(lwp != RT_NULL); + + for (node = lwp->hlist.next; node != &(lwp->hlist); node = node->next) + { + struct rt_lwp_memheap *lwp_heap; + lwp_heap = rt_list_entry(node, struct rt_lwp_memheap, mlist); + + addr = rt_lwp_memheap_alloc(lwp_heap, size); + if (addr != RT_NULL) + { + dbg_log(DBG_LOG, "lwp alloc 0x%x/%d\n", addr, size); + return addr; + } + } + + npages = (size + rt_lwp_memheap_unavailable_size_get() + LWP_MEM_PAGE_SIZE) / LWP_MEM_PAGE_SIZE; + if (RT_NULL != rt_lwp_malloc_page(lwp, npages)) + return rt_lwp_mem_malloc(size); + else + return RT_NULL; +} + +void rt_lwp_mem_free(void *addr) +{ + struct rt_lwp_memheap_item *header_ptr; + struct rt_lwp_memheap *lwp_heap; + + if (addr == RT_NULL) + return ; + + /* get memory item */ + header_ptr = (struct rt_lwp_memheap_item *)((rt_uint8_t *)addr - RT_MEMHEAP_SIZE); + RT_ASSERT(header_ptr); + + lwp_heap = header_ptr->pool_ptr; + RT_ASSERT(lwp_heap); + + dbg_log(DBG_LOG, "lwp free 0x%x\n", addr); + rt_lwp_memheap_free((void *)addr); + + if (rt_lwp_memheap_is_empty(lwp_heap)) + { + rt_lwp_free_page(rt_lwp_self(), lwp_heap); + } +} + +void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize) +{ + void *new_ptr; + struct rt_lwp_memheap_item *header_ptr; + + if (rmem == RT_NULL) + return rt_lwp_mem_malloc(newsize); + + if (newsize == 0) + { + rt_lwp_mem_free(rmem); + return RT_NULL; + } + + /* get old memory item */ + header_ptr = (struct rt_lwp_memheap_item *) + ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE); + + new_ptr = rt_lwp_memheap_realloc(header_ptr->pool_ptr, rmem, newsize); + if (new_ptr == RT_NULL) + { + /* allocate memory block from other memheap */ + new_ptr = rt_lwp_mem_malloc(newsize); + if (new_ptr != RT_NULL && rmem != RT_NULL) + { + rt_size_t oldsize; + + /* get the size of old memory block */ + oldsize = MEMITEM_SIZE(header_ptr); + if (newsize > oldsize) + rt_memcpy(new_ptr, rmem, oldsize); + else + rt_memcpy(new_ptr, rmem, newsize); + + dbg_log(DBG_LOG, "lwp realloc with memcpy 0x%x -> 0x%x/%d\n", rmem, new_ptr, newsize); + rt_lwp_mem_free(rmem); + + } + } + + dbg_log(DBG_LOG, "lwp realloc in same address 0x%x/%d\n", rmem, newsize); + + return new_ptr; +} diff --git a/components/lwp/lwp_mem.h b/components/lwp/lwp_mem.h new file mode 100644 index 000000000..117a18f67 --- /dev/null +++ b/components/lwp/lwp_mem.h @@ -0,0 +1,34 @@ +/* + * File : lwp_mem.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __LWP_MEM_H__ +#define __LWP_MEM_H__ + +extern void rt_lwp_mem_init(struct rt_lwp *lwp); +extern void rt_lwp_mem_deinit(struct rt_lwp *lwp); + +extern void *rt_lwp_mem_malloc(rt_uint32_t size); +extern void rt_lwp_mem_free(void *addr); +extern void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize); + +#endif diff --git a/components/lwp/lwp_memheap.c b/components/lwp/lwp_memheap.c new file mode 100644 index 000000000..46ba66769 --- /dev/null +++ b/components/lwp/lwp_memheap.c @@ -0,0 +1,590 @@ +/* + * File : lwp_memheap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-04-10 Bernard first implementation + * 2012-10-16 Bernard add the mutex lock for heap object. + * 2012-12-29 Bernard memheap can be used as system heap. + * change mutex lock to semaphore lock. + * 2013-04-10 Bernard add rt_lwp_memheap_realloc function. + * 2013-05-24 Bernard fix the rt_lwp_memheap_realloc issue. + * 2013-07-11 Grissiom fix the memory block splitting issue. + * 2013-07-15 Grissiom optimize rt_lwp_memheap_realloc + */ + +#include +#include +#include + +/* dynamic pool magic and mask */ +#define RT_MEMHEAP_MAGIC 0x1ea01ea0 +#define RT_MEMHEAP_MASK 0xfffffffe +#define RT_MEMHEAP_USED 0x01 +#define RT_MEMHEAP_FREED 0x00 + +#define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED) +#define RT_MEMHEAP_MINIALLOC 12 + +#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_lwp_memheap_item), RT_ALIGN_SIZE) +#define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE) + +/* + * The initialized memory pool will be: + * +-----------------------------------+--------------------------+ + * | whole freed memory block | Used Memory Block Tailer | + * +-----------------------------------+--------------------------+ + * + * block_list --> whole freed memory block + * + * The length of Used Memory Block Tailer is 0, + * which is prevents block merging across list + */ +rt_err_t rt_lwp_memheap_init(struct rt_lwp_memheap *memheap, + const char *name, + void *start_addr, + rt_uint32_t size) +{ + struct rt_lwp_memheap_item *item; + + RT_ASSERT(memheap != RT_NULL); + + /* initialize pool object */ + memheap->start_addr = start_addr; + memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); + memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE); + memheap->max_used_size = memheap->pool_size - memheap->available_size; + + /* initialize the free list header */ + item = &(memheap->free_header); + item->magic = RT_MEMHEAP_MAGIC; + item->pool_ptr = memheap; + item->next = RT_NULL; + item->prev = RT_NULL; + item->next_free = item; + item->prev_free = item; + + /* set the free list to free list header */ + memheap->free_list = item; + + /* initialize the first big memory block */ + item = (struct rt_lwp_memheap_item *)start_addr; + item->magic = RT_MEMHEAP_MAGIC; + item->pool_ptr = memheap; + item->next = RT_NULL; + item->prev = RT_NULL; + item->next_free = item; + item->prev_free = item; + + item->next = (struct rt_lwp_memheap_item *) + ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE); + item->prev = item->next; + + /* block list header */ + memheap->block_list = item; + + /* place the big memory block to free list */ + item->next_free = memheap->free_list->next_free; + item->prev_free = memheap->free_list; + memheap->free_list->next_free->prev_free = item; + memheap->free_list->next_free = item; + + /* move to the end of memory pool to build a small tailer block, + * which prevents block merging + */ + item = item->next; + /* it's a used memory block */ + item->magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED; + item->pool_ptr = memheap; + item->next = (struct rt_lwp_memheap_item *)start_addr; + item->prev = (struct rt_lwp_memheap_item *)start_addr; + /* not in free list */ + item->next_free = item->prev_free = RT_NULL; + + /* initialize semaphore lock */ + rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n", + start_addr, size, &(memheap->free_header))); + + return RT_EOK; +} + +void *rt_lwp_memheap_alloc(struct rt_lwp_memheap *heap, rt_uint32_t size) +{ + rt_err_t result; + rt_uint32_t free_size; + struct rt_lwp_memheap_item *header_ptr; + + RT_ASSERT(heap != RT_NULL); + + /* align allocated size */ + size = RT_ALIGN(size, RT_ALIGN_SIZE); + if (size < RT_MEMHEAP_MINIALLOC) + size = RT_MEMHEAP_MINIALLOC; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s", + size, RT_NAME_MAX, heap->parent.name)); + + if (size < heap->available_size) + { + /* search on free list */ + free_size = 0; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return RT_NULL; + } + + /* get the first free memory block */ + header_ptr = heap->free_list->next_free; + while (header_ptr != heap->free_list && free_size < size) + { + /* get current freed memory block size */ + free_size = MEMITEM_SIZE(header_ptr); + if (free_size < size) + { + /* move to next free memory block */ + header_ptr = header_ptr->next_free; + } + } + + /* determine if the memory is available. */ + if (free_size >= size) + { + /* a block that satisfies the request has been found. */ + + /* determine if the block needs to be split. */ + if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC)) + { + struct rt_lwp_memheap_item *new_ptr; + + /* split the block. */ + new_ptr = (struct rt_lwp_memheap_item *) + (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n", + header_ptr, + header_ptr->next, + header_ptr->prev, + new_ptr)); + + /* mark the new block as a memory block and freed. */ + new_ptr->magic = RT_MEMHEAP_MAGIC; + + /* put the pool pointer into the new block. */ + new_ptr->pool_ptr = heap; + + /* break down the block list */ + new_ptr->prev = header_ptr; + new_ptr->next = header_ptr->next; + header_ptr->next->prev = new_ptr; + header_ptr->next = new_ptr; + + /* remove header ptr from free list */ + header_ptr->next_free->prev_free = header_ptr->prev_free; + header_ptr->prev_free->next_free = header_ptr->next_free; + header_ptr->next_free = RT_NULL; + header_ptr->prev_free = RT_NULL; + + /* insert new_ptr to free list */ + new_ptr->next_free = heap->free_list->next_free; + new_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = new_ptr; + heap->free_list->next_free = new_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n", + new_ptr->next_free, + new_ptr->prev_free)); + + /* decrement the available byte count. */ + heap->available_size = heap->available_size - + size - + RT_MEMHEAP_SIZE; + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + } + else + { + /* decrement the entire free size from the available bytes count. */ + heap->available_size = heap->available_size - free_size; + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + + /* remove header_ptr from free list */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n", + header_ptr, + header_ptr->next_free, + header_ptr->prev_free)); + + header_ptr->next_free->prev_free = header_ptr->prev_free; + header_ptr->prev_free->next_free = header_ptr->next_free; + header_ptr->next_free = RT_NULL; + header_ptr->prev_free = RT_NULL; + } + + /* Mark the allocated block as not available. */ + header_ptr->magic |= RT_MEMHEAP_USED; + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* Return a memory address to the caller. */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n", + (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE), + header_ptr, + size)); + + return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE); + } + + /* release lock */ + rt_sem_release(&(heap->lock)); + } + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n")); + + /* Return the completion status. */ + return RT_NULL; +} + +void *rt_lwp_memheap_realloc(struct rt_lwp_memheap *heap, void *ptr, rt_size_t newsize) +{ + rt_err_t result; + rt_size_t oldsize; + struct rt_lwp_memheap_item *header_ptr; + struct rt_lwp_memheap_item *new_ptr; + + if (newsize == 0) + { + rt_lwp_memheap_free(ptr); + + return RT_NULL; + } + /* align allocated size */ + newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); + if (newsize < RT_MEMHEAP_MINIALLOC) + newsize = RT_MEMHEAP_MINIALLOC; + + if (ptr == RT_NULL) + { + return rt_lwp_memheap_alloc(heap, newsize); + } + + /* get memory block header and get the size of memory block */ + header_ptr = (struct rt_lwp_memheap_item *) + ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE); + oldsize = MEMITEM_SIZE(header_ptr); + /* re-allocate memory */ + if (newsize > oldsize) + { + void *new_ptr; + struct rt_lwp_memheap_item *next_ptr; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + return RT_NULL; + } + + next_ptr = header_ptr->next; + + /* header_ptr should not be the tail */ + RT_ASSERT(next_ptr > header_ptr); + + /* check whether the following free space is enough to expand */ + if (!RT_MEMHEAP_IS_USED(next_ptr)) + { + rt_int32_t nextsize; + + nextsize = MEMITEM_SIZE(next_ptr); + RT_ASSERT(next_ptr > 0); + + /* Here is the ASCII art of the situation that we can make use of + * the next free node without alloc/memcpy, |*| is the control + * block: + * + * oldsize free node + * |*|-----------|*|----------------------|*| + * newsize >= minialloc + * |*|----------------|*|-----------------|*| + */ + if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC) + { + /* decrement the entire free size from the available bytes count. */ + heap->available_size = heap->available_size - (newsize - oldsize); + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + + /* remove next_ptr from free list */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x", + next_ptr, + next_ptr->next_free, + next_ptr->prev_free)); + + next_ptr->next_free->prev_free = next_ptr->prev_free; + next_ptr->prev_free->next_free = next_ptr->next_free; + next_ptr->next->prev = next_ptr->prev; + next_ptr->prev->next = next_ptr->next; + + /* build a new one on the right place */ + next_ptr = (struct rt_lwp_memheap_item *)((char *)ptr + newsize); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]", + next_ptr, + next_ptr->next, + next_ptr->prev)); + + /* mark the new block as a memory block and freed. */ + next_ptr->magic = RT_MEMHEAP_MAGIC; + + /* put the pool pointer into the new block. */ + next_ptr->pool_ptr = heap; + + next_ptr->prev = header_ptr; + next_ptr->next = header_ptr->next; + header_ptr->next->prev = next_ptr; + header_ptr->next = next_ptr; + + /* insert next_ptr to free list */ + next_ptr->next_free = heap->free_list->next_free; + next_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = next_ptr; + heap->free_list->next_free = next_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x", + next_ptr->next_free, + next_ptr->prev_free)); + + /* release lock */ + rt_sem_release(&(heap->lock)); + + return ptr; + } + } + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* re-allocate a memory block */ + new_ptr = (void *)rt_lwp_memheap_alloc(heap, newsize); + if (new_ptr != RT_NULL) + { + rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize); + rt_lwp_memheap_free(ptr); + } + + return new_ptr; + } + + /* don't split when there is less than one node space left */ + if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize) + return ptr; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return RT_NULL; + } + + /* split the block. */ + new_ptr = (struct rt_lwp_memheap_item *) + (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n", + header_ptr, + header_ptr->next, + header_ptr->prev, + new_ptr)); + + /* mark the new block as a memory block and freed. */ + new_ptr->magic = RT_MEMHEAP_MAGIC; + /* put the pool pointer into the new block. */ + new_ptr->pool_ptr = heap; + + /* break down the block list */ + new_ptr->prev = header_ptr; + new_ptr->next = header_ptr->next; + header_ptr->next->prev = new_ptr; + header_ptr->next = new_ptr; + + /* determine if the block can be merged with the next neighbor. */ + if (!RT_MEMHEAP_IS_USED(new_ptr->next)) + { + struct rt_lwp_memheap_item *free_ptr; + + /* merge block with next neighbor. */ + free_ptr = new_ptr->next; + heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n", + header_ptr, header_ptr->next_free, header_ptr->prev_free)); + + free_ptr->next->prev = new_ptr; + new_ptr->next = free_ptr->next; + + /* remove free ptr from free list */ + free_ptr->next_free->prev_free = free_ptr->prev_free; + free_ptr->prev_free->next_free = free_ptr->next_free; + } + + /* insert the split block to free list */ + new_ptr->next_free = heap->free_list->next_free; + new_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = new_ptr; + heap->free_list->next_free = new_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n", + new_ptr->next_free, + new_ptr->prev_free)); + + /* increment the available byte count. */ + heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr); + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* return the old memory block */ + return ptr; +} + +void rt_lwp_memheap_free(void *ptr) +{ + rt_err_t result; + struct rt_lwp_memheap *heap; + struct rt_lwp_memheap_item *header_ptr, *new_ptr; + rt_uint32_t insert_header; + + /* NULL check */ + if (ptr == RT_NULL) return; + + /* set initial status as OK */ + insert_header = 1; + new_ptr = RT_NULL; + header_ptr = (struct rt_lwp_memheap_item *) + ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n", + ptr, header_ptr)); + + /* check magic */ + RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC); + RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED); + /* check whether this block of memory has been over-written. */ + RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC); + + /* get pool ptr */ + heap = header_ptr->pool_ptr; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return ; + } + + /* Mark the memory as available. */ + header_ptr->magic &= ~RT_MEMHEAP_USED; + /* Adjust the available number of bytes. */ + heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr); + + /* Determine if the block can be merged with the previous neighbor. */ + if (!RT_MEMHEAP_IS_USED(header_ptr->prev)) + { + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n", + header_ptr->prev)); + + /* adjust the available number of bytes. */ + heap->available_size = heap->available_size + RT_MEMHEAP_SIZE; + + /* yes, merge block with previous neighbor. */ + (header_ptr->prev)->next = header_ptr->next; + (header_ptr->next)->prev = header_ptr->prev; + + /* move header pointer to previous. */ + header_ptr = header_ptr->prev; + /* don't insert header to free list */ + insert_header = 0; + } + + /* determine if the block can be merged with the next neighbor. */ + if (!RT_MEMHEAP_IS_USED(header_ptr->next)) + { + /* adjust the available number of bytes. */ + heap->available_size = heap->available_size + RT_MEMHEAP_SIZE; + + /* merge block with next neighbor. */ + new_ptr = header_ptr->next; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n", + new_ptr, new_ptr->next_free, new_ptr->prev_free)); + + new_ptr->next->prev = header_ptr; + header_ptr->next = new_ptr->next; + + /* remove new ptr from free list */ + new_ptr->next_free->prev_free = new_ptr->prev_free; + new_ptr->prev_free->next_free = new_ptr->next_free; + } + + if (insert_header) + { + /* no left merge, insert to free list */ + header_ptr->next_free = heap->free_list->next_free; + header_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = header_ptr; + heap->free_list->next_free = header_ptr; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n", + header_ptr->next_free, header_ptr->prev_free)); + } + + /* release lock */ + rt_sem_release(&(heap->lock)); +} + +rt_bool_t rt_lwp_memheap_is_empty(struct rt_lwp_memheap *memheap) +{ + RT_ASSERT(memheap != RT_NULL); + + return (memheap->available_size + 2 * sizeof(struct rt_lwp_memheap_item)) == memheap->pool_size; +} + +rt_bool_t rt_lwp_memheap_unavailable_size_get(void) +{ + return 2 * RT_MEMHEAP_SIZE + 3; +} diff --git a/components/lwp/lwp_memheap.h b/components/lwp/lwp_memheap.h new file mode 100644 index 000000000..064238585 --- /dev/null +++ b/components/lwp/lwp_memheap.h @@ -0,0 +1,74 @@ +/* + * File : lwp_memheap.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __LWP_MEMHEAP_H__ +#define __LWP_MEMHEAP_H__ + +#include +#include + +/** + * memory item on the heap + */ +struct rt_lwp_memheap_item +{ + rt_uint32_t magic; /**< magic number for memheap */ + struct rt_lwp_memheap *pool_ptr; /**< point of pool */ + + struct rt_lwp_memheap_item *next; /**< next memheap item */ + struct rt_lwp_memheap_item *prev; /**< prev memheap item */ + + struct rt_lwp_memheap_item *next_free; /**< next free memheap item */ + struct rt_lwp_memheap_item *prev_free; /**< prev free memheap item */ +}; + +/** + * Base structure of memory heap object + */ +struct rt_lwp_memheap +{ + struct rt_object parent; /**< inherit from rt_object */ + + void *start_addr; /**< pool start address and size */ + + rt_uint32_t pool_size; /**< pool size */ + rt_uint32_t available_size; /**< available size */ + rt_uint32_t max_used_size; /**< maximum allocated size */ + + struct rt_lwp_memheap_item *block_list; /**< used block list */ + struct rt_lwp_memheap_item *free_list; /**< free block list */ + struct rt_lwp_memheap_item free_header; /**< free block list header */ + + struct rt_semaphore lock; /**< semaphore lock */ + + rt_list_t mlist; +}; + +extern rt_err_t rt_lwp_memheap_init(struct rt_lwp_memheap *memheap, const char *name, void *start_addr, rt_uint32_t size); +extern void *rt_lwp_memheap_alloc(struct rt_lwp_memheap *heap, rt_uint32_t size); +extern void rt_lwp_memheap_free(void *ptr); +extern void *rt_lwp_memheap_realloc(struct rt_lwp_memheap *heap, void *ptr, rt_size_t newsize); +extern rt_bool_t rt_lwp_memheap_is_empty(struct rt_lwp_memheap *memheap); +extern rt_bool_t rt_lwp_memheap_unavailable_size_get(void); + +#endif diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c new file mode 100644 index 000000000..be5e15dcb --- /dev/null +++ b/components/lwp/lwp_syscall.c @@ -0,0 +1,242 @@ +/* + * File : lwp_syscall.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +/* RT-Thread System call */ +#include +#include +#include + +#define DBG_ENABLE +#define DBG_SECTION_NAME "[LWP_CALL]" +#define DBG_COLOR +#define DBG_LEVEL DBG_WARNING +#include + +/* thread/process */ +void sys_exit(int value) +{ + /* TODO: handle the return_value */ + + dbg_log(DBG_LOG, "enter sys_exit\n"); + + rt_thread_delete(rt_thread_self()); + + rt_schedule(); + + return; +} + +/* syscall: "read" ret: "ssize_t" args: "int" "void *" "size_t" */ +ssize_t sys_read(int fd, void *buf, size_t nbyte) +{ + return read(fd, buf, nbyte); +} + +/* syscall: "write" ret: "ssize_t" args: "int" "const void *" "size_t" */ +ssize_t sys_write(int fd, const void *buf, size_t nbyte) +{ + return write(fd, buf, nbyte); +} + +/* syscall: "lseek" ret: "off_t" args: "int" "off_t" "int" */ +off_t sys_lseek(int fd, off_t offset, int whence) +{ + return lseek(fd, offset, whence); +} + +/* syscall: "open" ret: "int" args: "const char *" "int" "..." */ +int sys_open(const char *name, int mode, ...) +{ + return open(name, mode, 0); +} + +/* syscall: "close" ret: "int" args: "int" */ +int sys_close(int fd) +{ + return close(fd); +} + +/* syscall: "ioctl" ret: "int" args: "int" "u_long" "..." */ +int sys_ioctl(int fd, unsigned long cmd, void* data) +{ + return ioctl(fd, cmd, data); +} + +/* syscall: "nanosleep" ret: "int" args: "const struct timespec *" "struct timespec *" */ +int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + rt_tick_t tick; + + dbg_log(DBG_LOG, "sys_nanosleep\n"); + + tick = rqtp->tv_sec * RT_TICK_PER_SECOND + (rqtp->tv_nsec * RT_TICK_PER_SECOND)/ 1000000000; + rt_thread_delay(tick); + + if (rmtp) + { + tick = rt_tick_get() - tick; + /* get the passed time */ + rmtp->tv_sec = tick/RT_TICK_PER_SECOND; + rmtp->tv_nsec = (tick%RT_TICK_PER_SECOND) * (1000000000/RT_TICK_PER_SECOND); + } + + return 0; +} + +/* syscall: "getpriority" ret: "int" args: "int" "id_t" */ +int sys_getpriority(int which, id_t who) +{ + if (which == PRIO_PROCESS) + { + rt_thread_t tid; + + tid = rt_thread_self(); + if (who == (id_t)tid || who == 0xff) + { + return tid->current_priority; + } + } + + return 0xff; +} + +/* syscall: "setpriority" ret: "int" args: "int" "id_t" "int" */ +int sys_setpriority(int which, id_t who, int prio) +{ + if (which == PRIO_PROCESS) + { + rt_thread_t tid; + + tid = rt_thread_self(); + if ((who == (id_t)tid || who == 0xff) && (prio >= 0 && prio < RT_THREAD_PRIORITY_MAX)) + { + rt_thread_control(tid, RT_THREAD_CTRL_CHANGE_PRIORITY, &prio); + return 0; + } + } + + return -1; +} + +/* syscall: "gettimeofday" ret: "int" args: "struct timeval *" "struct timezone *" */ +int sys_gettimeofday(struct timeval *tp, struct timezone *tzp) +{ + if (tp) + { + tp->tv_sec = rt_tick_get() / RT_TICK_PER_SECOND; + tp->tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND); + } + + return 0; +} + +/* syscall: "settimeofday" ret: "int" args: "const struct timeval *" "const struct timezone *" */ +int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp) +{ + return 0; +} + +/* syscall: "msgget" ret: "int" args: "key_t" "int" */ +int sys_msgget(key_t key, int msgflg) +{ + return -1; +} + +/* syscall: "msgsnd" ret: "int" args: "int" "const void *" "size_t" "int" */ +int sys_msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg) +{ + return -1; +} + +/* syscall: "msgrcv" ret: "int" args: "int" "void *" "size_t" "long" "int" */ +int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) +{ + return -1; +} + +/* syscall: "sys_log" ret: "int" args: "const char*" "size" */ +int sys_log(const char* log, int size) +{ + rt_device_t console = rt_console_get_device(); + + if (console) rt_device_write(console, -1, log, size); + + return 0; +} + +void *sys_malloc(size_t size) +{ + return rt_lwp_mem_malloc(size); +} + +void sys_free(void *addr) +{ + rt_lwp_mem_free(addr); +} + +void *sys_realloc(void *rmem, size_t newsize) +{ + return rt_lwp_mem_realloc(rmem, newsize); +} + +const static void* func_table[] = +{ + (void *)sys_exit, // 0x01 + (void *)sys_read, // 0x02 + (void *)sys_write, // 0x03 + (void *)sys_lseek, // 0x04 + (void *)sys_open, // 0x05 + (void *)sys_close, // 0x06 + (void *)sys_ioctl, // 0x07 + + (void *)sys_nanosleep, // 0x08 + + (void *)sys_getpriority, // 0x09 + (void *)sys_setpriority, // 0x0a + + (void *)sys_gettimeofday, // 0x0b + (void *)sys_settimeofday, // 0x0c + + (void *)sys_malloc, // 0x0d + (void *)sys_free, // 0x0e +}; + +const void *lwp_get_sys_api(rt_uint32_t number) +{ + const void *func = RT_NULL; + + if (number == 0xff) + { + func = (void *)sys_log; + } + else + { + number -= 1; + if (number < sizeof(func_table)/sizeof(func_table[0])) + { + func = func_table[number]; + } + } + + return func; +} diff --git a/components/lwp/lwp_syscall.h b/components/lwp/lwp_syscall.h new file mode 100644 index 000000000..eba25c40e --- /dev/null +++ b/components/lwp/lwp_syscall.h @@ -0,0 +1,78 @@ +/* + * File : lwp_syscall.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2006-03-18 Bernard the first version + * 2006-04-25 Bernard add rt_hw_context_switch_interrupt declaration + * 2006-09-24 Bernard add rt_hw_context_switch_to declaration + * 2012-12-29 Bernard add rt_hw_exception_install declaration + * 2017-10-17 Hichard add some micros + */ + +#ifndef __LWP_SYSCALL_H__ +#define __LWP_SYSCALL_H__ + +#include +#include +#include +#include +#include + +typedef long suseconds_t; /* microseconds (signed) */ +typedef long key_t; /* IPC key (for Sys V IPC) */ +typedef uint32_t id_t; /* may contain pid, uid or gid */ + +/* + * Process priority specifications to get/setpriority. + */ +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define PRIO_PROCESS 0 /* only support lwp process */ +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} + +void sys_exit(int value); +ssize_t sys_read(int fd, void *buf, size_t nbyte); +ssize_t sys_write(int fd, const void *buf, size_t nbyte); +off_t sys_lseek(int fd, off_t offset, int whence); +int sys_open(const char *name, int mode, ...); +int sys_close(int fd); +int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp); +int sys_getpriority(int which, id_t who); +int sys_setpriority(int which, id_t who, int prio); +int sys_gettimeofday(struct timeval *tp, struct timezone *tzp); +int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp); +int sys_msgget(key_t key, int msgflg); +int sys_msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg); +int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); + +int sys_log(const char* log, int size); + +#endif -- GitLab