summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2018-12-10 20:00:25 +0800
committerGitHub <[email protected]>2018-12-10 20:00:25 +0800
commitb628ac0e7e85ec634de305b3563c4ccb3674c5e8 (patch)
tree01ae9f214f4d5a34952c8ad6346749806ad0d1fe /components
parent92338d50c48f844c1193238051ca775d650e96e4 (diff)
parent2b21d2316aaac2e04fce72a5ffb64cc7c511c9b6 (diff)
Merge pull request #2052 from jesven/lwp_ok
add lwp support
Diffstat (limited to 'components')
-rw-r--r--components/Kconfig2
-rw-r--r--components/lwp/Kconfig8
-rw-r--r--components/lwp/SConscript20
-rw-r--r--components/lwp/arch/arm/arm9/lwp_gcc.S81
-rw-r--r--components/lwp/arch/arm/cortex-a9/lwp_gcc.S70
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_rvds.S135
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_rvds.S135
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_rvds.S135
-rw-r--r--components/lwp/lwp.c380
-rw-r--r--components/lwp/lwp.h71
-rw-r--r--components/lwp/lwp_mem.c222
-rw-r--r--components/lwp/lwp_mem.h21
-rw-r--r--components/lwp/lwp_memheap.c576
-rw-r--r--components/lwp/lwp_memheap.h61
-rw-r--r--components/lwp/lwp_syscall.c284
-rw-r--r--components/lwp/lwp_syscall.h64
22 files changed, 3006 insertions, 0 deletions
diff --git a/components/Kconfig b/components/Kconfig
index 327489910b..8766c49e0f 100644
--- a/components/Kconfig
+++ b/components/Kconfig
@@ -39,4 +39,6 @@ source "$RTT_DIR/components/utilities/Kconfig"
source "$RTT_DIR/components/CMSIS/Kconfig"
+source "$RTT_DIR/components/lwp/Kconfig"
+
endmenu
diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig
new file mode 100644
index 0000000000..1b37829935
--- /dev/null
+++ b/components/lwp/Kconfig
@@ -0,0 +1,8 @@
+config RT_USING_LWP
+ bool "Using light-weight process"
+ select RT_USING_DFS
+ select RT_USING_LIBC
+ depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A
+ 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 0000000000..75dd25e84a
--- /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", "arm9", "cortex-a9"]}
+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/arm9/lwp_gcc.S b/components/lwp/arch/arm/arm9/lwp_gcc.S
new file mode 100644
index 0000000000..2a8ce492eb
--- /dev/null
+++ b/components/lwp/arch/arm/arm9/lwp_gcc.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-12-10 Jesven first version
+ */
+
+#define Mode_USR 0x10
+#define Mode_FIQ 0x11
+#define Mode_IRQ 0x12
+#define Mode_SVC 0x13
+#define Mode_MON 0x16
+#define Mode_ABT 0x17
+#define Mode_UDF 0x1B
+#define Mode_SYS 0x1F
+
+#define A_Bit 0x100
+#define I_Bit 0x80 @; when I bit is set, IRQ is disabled
+#define F_Bit 0x40 @; when F bit is set, FIQ is disabled
+#define T_Bit 0x20
+
+.cpu arm9
+.syntax unified
+.text
+
+/*
+ * void lwp_user_entry(args, text, data);
+ */
+.global lwp_user_entry
+.type lwp_user_entry, % function
+lwp_user_entry:
+ mrs r9, cpsr
+ mov r8, r9
+ bic r9, #0x1f
+ orr r9, #Mode_USR
+
+ orr r8, #I_Bit
+ msr cpsr_c, r8
+
+ msr spsr, r9
+
+ /* set data address. */
+ mov r9, r2
+ movs pc, r1
+
+/*
+ * void SVC_Handler(void);
+ */
+.global SVC_Handler
+.type SVC_Handler, % function
+SVC_Handler:
+ push {lr}
+ mrs lr, spsr
+ push {r4, r5, lr}
+
+ mrs r4, cpsr
+ bic r4, #I_Bit
+ msr cpsr_c, r4
+
+ push {r0 - r3, r12}
+ and r0, r7, #0xff
+ bl lwp_get_sys_api
+ cmp r0, #0 /* r0 = api */
+ mov r4, r0
+ pop {r0 - r3, r12}
+ beq svc_exit
+ ldr lr, = svc_exit
+ bx r4
+
+svc_exit:
+ mrs r4, cpsr
+ orr r4, #I_Bit
+ msr cpsr_c, r4
+
+ pop {r4, r5, lr}
+ msr spsr_cxsf, lr
+ pop {lr}
+ movs pc, lr
diff --git a/components/lwp/arch/arm/cortex-a9/lwp_gcc.S b/components/lwp/arch/arm/cortex-a9/lwp_gcc.S
new file mode 100644
index 0000000000..6c89152b0c
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-a9/lwp_gcc.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-12-10 Jesven first version
+ */
+
+#define Mode_USR 0x10
+#define Mode_FIQ 0x11
+#define Mode_IRQ 0x12
+#define Mode_SVC 0x13
+#define Mode_MON 0x16
+#define Mode_ABT 0x17
+#define Mode_UDF 0x1B
+#define Mode_SYS 0x1F
+
+#define A_Bit 0x100
+#define I_Bit 0x80 @; when I bit is set, IRQ is disabled
+#define F_Bit 0x40 @; when F bit is set, FIQ is disabled
+#define T_Bit 0x20
+
+.cpu cortex-a9
+.syntax unified
+.text
+
+/*
+ * void lwp_user_entry(args, text, data);
+ */
+.global lwp_user_entry
+.type lwp_user_entry, % function
+lwp_user_entry:
+ mrs r9, cpsr
+ bic r9, #0x1f
+ orr r9, #Mode_USR
+ cpsid i
+ msr spsr, r9
+
+ /* set data address. */
+ mov r9, r2
+ movs pc, r1
+
+/*
+ * void SVC_Handler(void);
+ */
+.global SVC_Handler
+.type SVC_Handler, % function
+SVC_Handler:
+ push {lr}
+ mrs lr, spsr
+ push {r4, r5, lr}
+ cpsie i
+
+ push {r0 - r3, r12}
+ and r0, r7, #0xff
+ bl lwp_get_sys_api
+ cmp r0, #0 /* r0 = api */
+ mov lr, r0
+ pop {r0 - r3, r12}
+ beq svc_exit
+ blx lr
+
+svc_exit:
+ cpsid i
+ pop {r4, r5, lr}
+ msr spsr_cxsf, lr
+ pop {lr}
+ movs pc, lr
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 0000000000..846b06bb26
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-10-30 heyuanjie first version
+ */
+
+.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(args, text, data);
+ */
+.global lwp_user_entry
+.type lwp_user_entry, % function
+lwp_user_entry:
+ PUSH {R0-R3} @; push text&data addr.
+
+ MOV R0, SP @; v1 = SP
+ BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
+
+ @; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 @; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} @; pop app address to R1.
+ @; set data address.
+ MOV R9, R2
+
+ @; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+/*
+ * 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.
+
+ @; get SVC number.
+ mov R0, R7
+
+ @; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} @; push api
+
+ @; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} @; pop api to R2.
+ POP {R1} @; pop app SP to R1.
+
+ stmfd r0!, {r1} @; save app SP to kernel SP
+
+ @;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ @; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] @; update LR
+ STR R2, [R0, #24] @; update api to PC
+ MSR PSP, R0 @; update SP, API is executed with kernel SP
+
+ @; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] @; load pc
+ add r3, #32 @; exception_stack_frame size
+ 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 0000000000..a218569375
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m3/lwp_iar.S
@@ -0,0 +1,123 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+ EXPORT lwp_user_entry
+lwp_user_entry:
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+;/*
+; * 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, r3, #32 ; exception_stack_frame size
+ 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 0000000000..246751a847
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m3/lwp_rvds.S
@@ -0,0 +1,135 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+lwp_user_entry PROC
+ EXPORT lwp_user_entry
+
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+ ; 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, #32 ; exception_stack_frame size
+ 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 0000000000..e71dbb82c9
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m4/lwp_gcc.S
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-10-30 heyuanjie first version
+ */
+
+.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(args, text, data);
+ */
+.global lwp_user_entry
+.type lwp_user_entry, % function
+lwp_user_entry:
+ PUSH {R0-R3} @; push text&data addr.
+
+ MOV R0, SP @; v1 = SP
+ BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
+
+ @; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 @; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} @; pop app address to R1.
+ @; set data address.
+ MOV R9, R2
+
+ @; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+/*
+ * 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.
+
+ @; get SVC number.
+ mov R0, R7
+
+ @; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} @; push api
+
+ @; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} @; pop api to R2.
+ POP {R1} @; pop app SP to R1.
+
+ stmfd r0!, {r1} @; save app SP to kernel SP
+
+ @;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ @; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] @; update LR
+ STR R2, [R0, #24] @; update api to PC
+ MSR PSP, R0 @; update SP, API is executed with kernel SP
+
+ @; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] @; load pc
+ add r3, #32 @; exception_stack_frame size
+ 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 0000000000..a218569375
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m4/lwp_iar.S
@@ -0,0 +1,123 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+ EXPORT lwp_user_entry
+lwp_user_entry:
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+;/*
+; * 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, r3, #32 ; exception_stack_frame size
+ 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 0000000000..246751a847
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m4/lwp_rvds.S
@@ -0,0 +1,135 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+lwp_user_entry PROC
+ EXPORT lwp_user_entry
+
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+ ; 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, #32 ; exception_stack_frame size
+ 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 0000000000..848c592919
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m7/lwp_gcc.S
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-10-30 heyuanjie first version
+ */
+
+.cpu cortex-m7
+.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(args, text, data);
+ */
+.global lwp_user_entry
+.type lwp_user_entry, % function
+lwp_user_entry:
+ PUSH {R0-R3} @; push text&data addr.
+
+ MOV R0, SP @; v1 = SP
+ BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
+
+ @; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 @; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} @; pop app address to R1.
+ @; set data address.
+ MOV R9, R2
+
+ @; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+/*
+ * 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.
+
+ @; get SVC number.
+ mov R0, R7
+
+ @; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} @; push api
+
+ @; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} @; pop api to R2.
+ POP {R1} @; pop app SP to R1.
+
+ stmfd r0!, {r1} @; save app SP to kernel SP
+
+ @;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ @; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] @; update LR
+ STR R2, [R0, #24] @; update api to PC
+ MSR PSP, R0 @; update SP, API is executed with kernel SP
+
+ @; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] @; load pc
+ add r3, #32 @; exception_stack_frame size
+ 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 0000000000..a218569375
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m7/lwp_iar.S
@@ -0,0 +1,123 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+ EXPORT lwp_user_entry
+lwp_user_entry:
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+;/*
+; * 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, r3, #32 ; exception_stack_frame size
+ 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 0000000000..246751a847
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-m7/lwp_rvds.S
@@ -0,0 +1,135 @@
+;/*
+; * Copyright (c) 2006-2018, RT-Thread Development Team
+; *
+; * SPDX-License-Identifier: Apache-2.0
+; *
+; * Change Logs:
+; * Date Author Notes
+; * 2018-10-30 heyuanjie first version
+; */
+
+ 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(args, text, data);
+; */
+lwp_user_entry PROC
+ EXPORT lwp_user_entry
+
+ PUSH {R0-R3} ; push text&data addr.
+
+ MOV R0, SP ; v1 = SP
+ BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
+
+ ; set CPU to user-thread mode.
+ MRS R2, CONTROL
+ ORR R2, R2, #0x03 ; use PSP, user-thread mode.
+ MSR CONTROL, R2
+
+ POP {R0-R3} ; pop app address to R1.
+ ; set data address.
+ MOV R9, R2
+
+ ; run app, only Thumb-mode.
+ ORR R1, R1, #0x01
+ BX R1
+
+ ; 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.
+
+ ; get SVC number.
+ mov R0, R7
+
+ ; get kernel system API
+ BL lwp_get_sys_api
+
+ PUSH {R0} ; push api
+
+ ; get kernel SP to R0.
+ BL lwp_get_kernel_sp
+
+ POP {R2} ; pop api to R2.
+ POP {R1} ; pop app SP to R1.
+
+ stmfd r0!, {r1} ; save app SP to kernel SP
+
+ ;push app parm5~6 to kernel SP
+ STMFD R0!, {R4 - R5}
+ ; copy R1(app SP) to R0(kernel SP).
+ push {r8-r11}
+ LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
+ STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
+ pop {r8-r11}
+
+ LDR R3, =svc_exit
+ STR R3, [R0, #20] ; update LR
+ STR R2, [R0, #24] ; update api to PC
+ MSR PSP, R0 ; update SP, API is executed with kernel SP
+
+ ; set to thread-privilege mode.
+ MRS R3, CONTROL
+ BIC R3, R3, #0x01
+ ORR R3, R3, #0x02
+ MSR CONTROL, R3
+
+ 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
+ ldr r3, [r0, #-4]
+ pop {r0}
+
+ ldr lr, [r3, #20]
+ ldr r1, [r3, #24] ; load pc
+ add r3, #32 ; exception_stack_frame size
+ 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 0000000000..84d6515ac6
--- /dev/null
+++ b/components/lwp/lwp.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2006-03-12 Bernard first version
+ * 2018-11-02 heyuanjie fix complie error in iar
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <dfs_posix.h>
+
+#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_WARNING
+#include <rtdbg.h>
+
+extern void lwp_user_entry(void *args, 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_thread_self()->lwp;
+ user_data->kernel_sp = sp;
+}
+
+uint32_t *lwp_get_kernel_sp(void)
+{
+ struct rt_lwp *user_data;
+ user_data = (struct rt_lwp *)rt_thread_self()->lwp;
+
+ return user_data->kernel_sp;
+}
+
+static int lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv)
+{
+ int size = sizeof(int)*3; /* store argc, argv, NULL */
+ int *args;
+ char *str;
+ char **new_argv;
+ int i;
+ int len;
+
+ for (i = 0; i < argc; i ++)
+ {
+ size += (rt_strlen(argv[i]) + 1);
+ }
+ size += (sizeof(int) * argc);
+
+ args = (int*)rt_malloc(size);
+ if (args == RT_NULL)
+ return -1;
+
+ str = (char*)((int)args + (argc + 3) * sizeof(int));
+ new_argv = (char**)&args[2];
+ args[0] = argc;
+ args[1] = (int)new_argv;
+
+ for (i = 0; i < argc; i ++)
+ {
+ len = rt_strlen(argv[i]) + 1;
+ new_argv[i] = str;
+ rt_memcpy(str, argv[i], len);
+ str += len;
+ }
+ new_argv[i] = 0;
+ lwp->args = args;
+
+ return 0;
+}
+
+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);
+
+ 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->lwp;
+
+ 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);
+
+ /* cleanup fd table */
+ rt_free(lwp->fdt.fds);
+ rt_free(lwp->args);
+
+ dbg_log(DBG_LOG, "lwp free: %p\n", lwp);
+ rt_free(lwp);
+
+ /* TODO: cleanup fd table */
+}
+
+static void lwp_thread(void *parameter)
+{
+ rt_thread_t tid;
+ struct rt_lwp *lwp;
+
+ lwp = (struct rt_lwp *)parameter;
+ rt_lwp_mem_init(lwp);
+ tid = rt_thread_self();
+ tid->lwp = lwp;
+ tid->cleanup = lwp_cleanup;
+
+ lwp_user_entry(lwp->args, lwp->text_entry, lwp->data);
+}
+
+struct rt_lwp *rt_lwp_self(void)
+{
+ return (struct rt_lwp *)rt_thread_self()->lwp;
+}
+
+int exec(char *filename, int argc, char **argv)
+{
+ 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));
+ if (lwp_argscopy(lwp, argc, argv) != 0)
+ {
+ rt_free(lwp);
+ return -ENOMEM;
+ }
+
+ 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->args);
+ rt_free(lwp);
+
+ return -RT_ERROR;
+}
diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h
new file mode 100644
index 0000000000..f013f36768
--- /dev/null
+++ b/components/lwp/lwp.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-06-29 heyuanjie first version
+ */
+
+#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 <stdint.h>
+#include <rtthread.h>
+#include <dfs.h>
+#include <lwp_memheap.h>
+
+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;
+ void *args;
+};
+
+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 0000000000..ebc878494a
--- /dev/null
+++ b/components/lwp/lwp_mem.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-06-10 Bernard first version
+ */
+
+#include <rtthread.h>
+#include <lwp.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "LWPMEM"
+#define DBG_COLOR
+#define DBG_LEVEL DBG_WARNING
+#include <rtdbg.h>
+
+// 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);
+
+ rt_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);
+
+ node = lwp->hlist.next;
+
+ while (node != &(lwp->hlist))
+ {
+ struct rt_lwp_memheap *lwp_heap;
+
+ lwp_heap = rt_list_entry(node, struct rt_lwp_memheap, mlist);
+ RT_ASSERT(lwp_heap != RT_NULL);
+
+ /* update note before free page*/
+ node = node->next;
+
+ 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 0000000000..8d333cfe4f
--- /dev/null
+++ b/components/lwp/lwp_mem.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-06-10 Bernard first version
+ */
+
+#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 0000000000..7d512a503f
--- /dev/null
+++ b/components/lwp/lwp_memheap.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <rthw.h>
+#include <rtthread.h>
+#include <lwp.h>
+
+/* 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 0000000000..d0c09dfd01
--- /dev/null
+++ b/components/lwp/lwp_memheap.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-06-10 Bernard first version
+ */
+
+#ifndef __LWP_MEMHEAP_H__
+#define __LWP_MEMHEAP_H__
+
+#include <stdint.h>
+#include <rtthread.h>
+
+/**
+ * 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 0000000000..5d4bbf6d91
--- /dev/null
+++ b/components/lwp/lwp_syscall.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-06-10 Bernard first version
+ */
+
+/* RT-Thread System call */
+#include <lwp.h>
+#include <lwp_mem.h>
+#include <lwp_syscall.h>
+
+#include <dfs_poll.h>
+#include <dfs_select.h>
+
+#if (defined(RT_USING_SAL) && defined(SAL_USING_POSIX))
+#include <sys/socket.h>
+
+#define SYSCALL_NET(f) ((void*)(f))
+#else
+#define SYSCALL_NET(f) ((void*)sys_notimpl)
+#endif
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "LWP_CALL"
+#define DBG_COLOR
+#define DBG_LEVEL DBG_WARNING
+#include <rtdbg.h>
+
+static void __exit_files(rt_thread_t tid)
+{
+ struct rt_lwp *lwp;
+
+ lwp = (struct rt_lwp *)tid->lwp;
+ while (lwp->fdt.maxfd > 0)
+ {
+ lwp->fdt.maxfd --;
+ close(lwp->fdt.maxfd);
+ }
+}
+
+/* thread/process */
+void sys_exit(int value)
+{
+ rt_thread_t tid;
+
+ /* TODO: handle the return_value */
+ dbg_log(DBG_LOG, "enter sys_exit\n");
+ tid = rt_thread_self();
+ __exit_files(tid);
+ rt_thread_delete(tid);
+
+ 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);
+}
+
+int sys_fstat(int file, struct stat *buf)
+{
+ return fstat(file, buf);
+}
+
+int sys_notimpl(void)
+{
+ return -ENOSYS;
+}
+
+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
+ (void *)sys_realloc, //0x0f
+ (void *)sys_fstat, // 0x10
+ (void *)poll, // 0x11
+
+ SYSCALL_NET(accept), // 0x12
+ SYSCALL_NET(bind), // 0x13
+ SYSCALL_NET(shutdown), // 0x14
+ SYSCALL_NET(getpeername),// 0x15
+ SYSCALL_NET(getsockname),// 0x16
+ SYSCALL_NET(getsockopt), // 0x17
+ SYSCALL_NET(setsockopt), // 0x18
+ SYSCALL_NET(connect), // 0x19
+ SYSCALL_NET(listen), // 0x1a
+ SYSCALL_NET(recv), // 0x1b
+ SYSCALL_NET(recvfrom), // 0x1c
+ SYSCALL_NET(send), // 0x1d
+ SYSCALL_NET(sendto), // 0x1e
+ SYSCALL_NET(socket), // 0x1f
+
+ (void *)select, // 0x20
+};
+
+const void *lwp_get_sys_api(rt_uint32_t number)
+{
+ const void *func = (const void*)sys_notimpl;
+
+ 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 0000000000..286a0a8852
--- /dev/null
+++ b/components/lwp/lwp_syscall.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ * 2018-12-10 Jesven fix complie error in iar and keil
+ */
+
+#ifndef __LWP_SYSCALL_H__
+#define __LWP_SYSCALL_H__
+
+#include <stdint.h>
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+typedef long suseconds_t; /* microseconds (signed) */
+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