diff --git a/bsp/allwinner_tina/libcpu/start_gcc.S b/bsp/allwinner_tina/libcpu/start_gcc.S index 94c985a37067ebeaa6dd5403892891cf03c7074a..8ef36826df740b26ff00e913ea214c2b5c1155a9 100644 --- a/bsp/allwinner_tina/libcpu/start_gcc.S +++ b/bsp/allwinner_tina/libcpu/start_gcc.S @@ -48,7 +48,7 @@ _vector_reset: _vector_undef: .word vector_undef _vector_swi: - .word vector_swi + .word SVC_Handler _vector_pabt: .word vector_pabt _vector_dabt: @@ -314,7 +314,9 @@ rt_hw_context_switch_interrupt_do: str lr, [r0, #14*4] .endm - .align 5 + .align 5 +.weak SVC_Handler +SVC_Handler: vector_swi: push_svc_reg bl rt_hw_trap_swi diff --git a/bsp/qemu-vexpress-a9/.config b/bsp/qemu-vexpress-a9/.config index 7c6c2dc1df2c7a790d23e5c2a9414bd71dc3218d..450ccad12e66bdc6dfcffea9f6ff763f53f445b4 100644 --- a/bsp/qemu-vexpress-a9/.config +++ b/bsp/qemu-vexpress-a9/.config @@ -66,6 +66,7 @@ CONFIG_RT_USING_INTERRUPT_INFO=y CONFIG_RT_USING_CONSOLE=y CONFIG_RT_CONSOLEBUF_SIZE=128 CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" +CONFIG_RT_VER_NUM=0x40000 CONFIG_ARCH_ARM=y CONFIG_ARCH_ARM_CORTEX_A=y CONFIG_ARCH_ARM_CORTEX_A9=y @@ -109,7 +110,7 @@ CONFIG_FINSH_ARG_MAX=10 CONFIG_RT_USING_DFS=y CONFIG_DFS_USING_WORKDIR=y CONFIG_DFS_FILESYSTEMS_MAX=2 -CONFIG_DFS_FILESYSTEM_TYPES_MAX=2 +CONFIG_DFS_FILESYSTEM_TYPES_MAX=8 CONFIG_DFS_FD_MAX=16 # CONFIG_RT_USING_DFS_MNTTABLE is not set CONFIG_RT_USING_DFS_ELMFAT=y @@ -165,10 +166,12 @@ CONFIG_RT_MMCSD_THREAD_PREORITY=22 CONFIG_RT_MMCSD_MAX_PARTITION=16 # CONFIG_RT_SDIO_DEBUG is not set CONFIG_RT_USING_SPI=y +# CONFIG_RT_USING_QSPI is not set CONFIG_RT_USING_SPI_MSD=y CONFIG_RT_USING_SFUD=y CONFIG_RT_SFUD_USING_SFDP=y CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y +# CONFIG_RT_SFUD_USING_QSPI is not set # CONFIG_RT_DEBUG_SFUD is not set # CONFIG_RT_USING_W25QXX is not set # CONFIG_RT_USING_GD is not set @@ -298,6 +301,7 @@ CONFIG_LOG_TRACE_USING_LEVEL_INFO=y # CONFIG_LOG_TRACE_USING_MEMLOG is not set # CONFIG_RT_USING_RYM is not set # CONFIG_RT_USING_ULOG is not set +CONFIG_RT_USING_LWP=y # # RT-Thread online packages @@ -383,6 +387,7 @@ CONFIG_LOG_TRACE_USING_LEVEL_INFO=y # CONFIG_PKG_USING_SQLITE is not set # CONFIG_PKG_USING_RTI is not set # CONFIG_PKG_USING_LITTLEVGL2RTT is not set +# CONFIG_PKG_USING_CMSIS is not set # # peripheral libraries and drivers @@ -392,6 +397,9 @@ CONFIG_LOG_TRACE_USING_LEVEL_INFO=y # CONFIG_PKG_USING_REALTEK_AMEBA is not set # CONFIG_PKG_USING_SHT2X is not set # CONFIG_PKG_USING_AHT10 is not set +# CONFIG_PKG_USING_AP3216C is not set +# CONFIG_PKG_USING_STM32_SDIO is not set +# CONFIG_PKG_USING_ICM20608 is not set # # miscellaneous packages @@ -409,7 +417,14 @@ CONFIG_LOG_TRACE_USING_LEVEL_INFO=y # # sample package # -# CONFIG_PKG_USING_SAMPLES is not set + +# +# samples: kernel and components samples +# +# CONFIG_PKG_USING_KERNEL_SAMPLES is not set +# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set +# CONFIG_PKG_USING_NETWORK_SAMPLES is not set +# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set # # example package: hello diff --git a/bsp/qemu-vexpress-a9/cpu/context_gcc.S b/bsp/qemu-vexpress-a9/cpu/context_gcc.S index d19a0406a6e7ba8c3cf0426210b2f62dbfc2fb73..694fb96e720202ffc57864f5dd9da34ad903fce7 100644 --- a/bsp/qemu-vexpress-a9/cpu/context_gcc.S +++ b/bsp/qemu-vexpress-a9/cpu/context_gcc.S @@ -63,6 +63,11 @@ rt_hw_context_switch_to: bl rt_cpus_lock_status_restore #endif /*RT_USING_SMP*/ +#ifdef RT_USING_LWP + ldmfd sp, {r13, r14}^ @ pop usr_sp usr_lr + add sp, #8 +#endif + ldmfd sp!, {r4} @ pop new task spsr msr spsr_cxsf, r4 @@ -89,6 +94,11 @@ rt_hw_context_switch: stmfd sp!, {r4} @ push cpsr +#ifdef RT_USING_LWP + stmfd sp, {r13, r14}^ @ push usr_sp usr_lr + sub sp, #8 +#endif + str sp, [r0] @ store sp in preempted tasks TCB ldr sp, [r1] @ get new task stack pointer @@ -97,6 +107,11 @@ rt_hw_context_switch: bl rt_cpus_lock_status_restore #endif /*RT_USING_SMP*/ +#ifdef RT_USING_LWP + ldmfd sp, {r13, r14}^ @ pop usr_sp usr_lr + add sp, #8 +#endif + ldmfd sp!, {r4} @ pop new task cpsr to spsr msr spsr_cxsf, r4 ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr @@ -142,6 +157,11 @@ rt_hw_context_switch_interrupt: stmfd sp!, {r4-r7} @ push old task's r0-r3 stmfd sp!, {r3} @ push old task's cpsr +#ifdef RT_USING_LWP + stmfd sp, {r13,r14}^ @push usr_sp usr_lr + sub sp, #8 +#endif + msr cpsr_c, #I_Bit|F_Bit|Mode_IRQ pop {r1 - r3} mov sp, r0 @@ -152,6 +172,11 @@ rt_hw_context_switch_interrupt: mov r0, r3 bl rt_cpus_lock_status_restore +#ifdef RT_USING_LWP + ldmfd sp, {r13,r14}^ @pop usr_sp usr_lr + add sp, #8 +#endif + ldmfd sp!, {r4} @ pop new task's cpsr to spsr msr spsr_cxsf, r4 diff --git a/bsp/qemu-vexpress-a9/cpu/stack.c b/bsp/qemu-vexpress-a9/cpu/stack.c index 4ae1536a20192055a73c2a7b92993789271fb2d1..dfcc6ea8df1029b7a75b5c4f811146f9a646790e 100644 --- a/bsp/qemu-vexpress-a9/cpu/stack.c +++ b/bsp/qemu-vexpress-a9/cpu/stack.c @@ -51,13 +51,17 @@ rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, *(--stk) = 0; /* r2 */ *(--stk) = 0; /* r1 */ *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ - /* cpsr */ if ((rt_uint32_t)tentry & 0x01) *(--stk) = SVCMODE | 0x20; /* thumb mode */ else *(--stk) = SVCMODE; /* arm mode */ +#ifdef RT_USING_LWP + *(--stk) = 0; /* user lr */ + *(--stk) = 0; /* user sp*/ +#endif + /* return task's current stack address */ return (rt_uint8_t *)stk; } diff --git a/bsp/qemu-vexpress-a9/cpu/start_gcc.S b/bsp/qemu-vexpress-a9/cpu/start_gcc.S index d380d02d08ec1be1bd14183a7602cf13f8f628fb..b71d8a15683999a582432b87ca4588422d4a1e84 100644 --- a/bsp/qemu-vexpress-a9/cpu/start_gcc.S +++ b/bsp/qemu-vexpress-a9/cpu/start_gcc.S @@ -288,6 +288,11 @@ rt_hw_context_switch_interrupt_do: stmfd sp!, {r1-r4} @ push old task's r0-r3 stmfd sp!, {r0} @ push old task's cpsr +#ifdef RT_USING_LWP + stmfd sp, {r13, r14}^ @push usr_sp, usr_lr + sub sp, #8 +#endif + ldr r4, =rt_interrupt_from_thread ldr r5, [r4] str sp, [r5] @ store sp in preempted tasks's TCB @@ -296,6 +301,11 @@ rt_hw_context_switch_interrupt_do: ldr r6, [r6] ldr sp, [r6] @ get new task's stack pointer +#ifdef RT_USING_LWP + ldmfd sp, {r13, r14}^ @pop usr_sp, usr_lr + add sp, #8 +#endif + ldmfd sp!, {r4} @ pop new task's cpsr to spsr msr spsr_cxsf, r4 @@ -317,6 +327,8 @@ rt_hw_context_switch_interrupt_do: .align 5 .globl vector_swi +.weak SVC_Handler +SVC_Handler: vector_swi: push_svc_reg bl rt_hw_trap_swi @@ -400,8 +412,8 @@ irq_stack_2: irq_stack_2_limit: .data -#define DEVICE_MEM 0x10406 -#define NORMAL_MEM 0x1140e +#define DEVICE_MEM 0x10c06 +#define NORMAL_MEM 0x11c0e .align 14 mtbl: diff --git a/bsp/qemu-vexpress-a9/cpu/vector_gcc.S b/bsp/qemu-vexpress-a9/cpu/vector_gcc.S index cbe9bc687bc8ff7f4c3af2220bccd8c323e943b6..2473e1f850464649e9fcfc9a1e267f50f8ce60d5 100644 --- a/bsp/qemu-vexpress-a9/cpu/vector_gcc.S +++ b/bsp/qemu-vexpress-a9/cpu/vector_gcc.S @@ -21,6 +21,7 @@ * Date Author Notes * 2013-07-05 Bernard the first version */ + .section .vectors, "ax" .code 32 @@ -49,7 +50,7 @@ _vector_reset: _vector_undef: .word vector_undef _vector_swi: - .word vector_swi + .word SVC_Handler _vector_pabt: .word vector_pabt _vector_dabt: diff --git a/bsp/qemu-vexpress-a9/rtconfig.h b/bsp/qemu-vexpress-a9/rtconfig.h index 2ac692c6920359a409247dfced9bad2daf9f22ca..fadda61173054ec3717bfc8a85212a43d265665b 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.h +++ b/bsp/qemu-vexpress-a9/rtconfig.h @@ -63,6 +63,7 @@ #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 128 #define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_VER_NUM 0x40000 #define ARCH_ARM #define ARCH_ARM_CORTEX_A #define ARCH_ARM_CORTEX_A9 @@ -102,7 +103,7 @@ #define RT_USING_DFS #define DFS_USING_WORKDIR #define DFS_FILESYSTEMS_MAX 2 -#define DFS_FILESYSTEM_TYPES_MAX 2 +#define DFS_FILESYSTEM_TYPES_MAX 8 #define DFS_FD_MAX 16 /* RT_USING_DFS_MNTTABLE is not set */ #define RT_USING_DFS_ELMFAT @@ -156,10 +157,12 @@ #define RT_MMCSD_MAX_PARTITION 16 /* RT_SDIO_DEBUG is not set */ #define RT_USING_SPI +/* RT_USING_QSPI is not set */ #define RT_USING_SPI_MSD #define RT_USING_SFUD #define RT_SFUD_USING_SFDP #define RT_SFUD_USING_FLASH_INFO_TABLE +/* RT_SFUD_USING_QSPI is not set */ /* RT_DEBUG_SFUD is not set */ /* RT_USING_W25QXX is not set */ /* RT_USING_GD is not set */ @@ -276,6 +279,7 @@ /* LOG_TRACE_USING_MEMLOG is not set */ /* RT_USING_RYM is not set */ /* RT_USING_ULOG is not set */ +#define RT_USING_LWP /* RT-Thread online packages */ @@ -348,6 +352,7 @@ /* PKG_USING_SQLITE is not set */ /* PKG_USING_RTI is not set */ /* PKG_USING_LITTLEVGL2RTT is not set */ +/* PKG_USING_CMSIS is not set */ /* peripheral libraries and drivers */ @@ -356,6 +361,9 @@ /* PKG_USING_REALTEK_AMEBA is not set */ /* PKG_USING_SHT2X is not set */ /* PKG_USING_AHT10 is not set */ +/* PKG_USING_AP3216C is not set */ +/* PKG_USING_STM32_SDIO is not set */ +/* PKG_USING_ICM20608 is not set */ /* miscellaneous packages */ @@ -371,7 +379,12 @@ /* sample package */ -/* PKG_USING_SAMPLES is not set */ +/* samples: kernel and components samples */ + +/* PKG_USING_KERNEL_SAMPLES is not set */ +/* PKG_USING_FILESYSTEM_SAMPLES is not set */ +/* PKG_USING_NETWORK_SAMPLES is not set */ +/* PKG_USING_PERIPHERAL_SAMPLES is not set */ /* example package: hello */ diff --git a/components/Kconfig b/components/Kconfig index 327489910b119cd0c6d3715325a6818eb6368aa0..8766c49e0fa11617bea1a492909092f1d59f8808 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 0000000000000000000000000000000000000000..1b37829935e70a2d6e3f9ed2019eccefdf7b4a3f --- /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 0000000000000000000000000000000000000000..53e445f8cc603c7c336ce914cc5de7b09966ffae --- /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", "R6", "vexpress-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/R6/lwp_gcc.S b/components/lwp/arch/arm/R6/lwp_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..bc684a939cfe5c8d0a4363255fef87f4eb8b1579 --- /dev/null +++ b/components/lwp/arch/arm/R6/lwp_gcc.S @@ -0,0 +1,94 @@ +/* + * 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 + */ + +#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-m3/lwp_gcc.S b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..54d045d4d2628e244bb3275f8b3cccbbb22458ac --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S @@ -0,0 +1,137 @@ +/* + * 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(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 0000000000000000000000000000000000000000..f8ac4a2052815eda3c09d7f5e0ca39f5cc5d8498 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_iar.S @@ -0,0 +1,136 @@ +;/* +; * 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(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 0000000000000000000000000000000000000000..b57dd11580292e9ec343ebc9fd180a04751f71bc --- /dev/null +++ b/components/lwp/arch/arm/cortex-m3/lwp_rvds.S @@ -0,0 +1,148 @@ +;/* +; * 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(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 0000000000000000000000000000000000000000..776df568100167fc3fb7bf7ee8d512d4bb610463 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_gcc.S @@ -0,0 +1,137 @@ +/* + * 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(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 0000000000000000000000000000000000000000..f8ac4a2052815eda3c09d7f5e0ca39f5cc5d8498 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_iar.S @@ -0,0 +1,136 @@ +;/* +; * 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(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 0000000000000000000000000000000000000000..b57dd11580292e9ec343ebc9fd180a04751f71bc --- /dev/null +++ b/components/lwp/arch/arm/cortex-m4/lwp_rvds.S @@ -0,0 +1,148 @@ +;/* +; * 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(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 0000000000000000000000000000000000000000..57b4cdfb60971977907272086a97963ccfda2109 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_gcc.S @@ -0,0 +1,137 @@ +/* + * 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-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 0000000000000000000000000000000000000000..f8ac4a2052815eda3c09d7f5e0ca39f5cc5d8498 --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_iar.S @@ -0,0 +1,136 @@ +;/* +; * 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(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 0000000000000000000000000000000000000000..b57dd11580292e9ec343ebc9fd180a04751f71bc --- /dev/null +++ b/components/lwp/arch/arm/cortex-m7/lwp_rvds.S @@ -0,0 +1,148 @@ +;/* +; * 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(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/vexpress-a9/lwp_gcc.S b/components/lwp/arch/arm/vexpress-a9/lwp_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..0337952fbbde554fe855fed8984f1e47c19bbfb6 --- /dev/null +++ b/components/lwp/arch/arm/vexpress-a9/lwp_gcc.S @@ -0,0 +1,83 @@ +/* + * 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 + */ + +#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/lwp.c b/components/lwp/lwp.c new file mode 100644 index 0000000000000000000000000000000000000000..62e10f8ed302b2a873a93bbe800e06040459a7cb --- /dev/null +++ b/components/lwp/lwp.c @@ -0,0 +1,392 @@ +/* + * 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 + +#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 + +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 0000000000000000000000000000000000000000..0b25cf69175b701e8ce317a85e83b7ab782c6d9c --- /dev/null +++ b/components/lwp/lwp.h @@ -0,0 +1,84 @@ +/* + * 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; + 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 0000000000000000000000000000000000000000..9b3dcf45a6feb00369d512b9e10c09cc8ea8b1e5 --- /dev/null +++ b/components/lwp/lwp_mem.c @@ -0,0 +1,236 @@ +/* + * 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 + +#define DBG_ENABLE +#define DBG_SECTION_NAME "LWPMEM" +#define DBG_COLOR +#define DBG_LEVEL DBG_WARNING +#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); + + 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 0000000000000000000000000000000000000000..117a18f677f0c925eb747cb12dc2307ad69203c2 --- /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 0000000000000000000000000000000000000000..46ba667695da8309121c1cb575454ffba2f86f1e --- /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 0000000000000000000000000000000000000000..064238585c5c0495b30c56b4c89d43e40ad4aa47 --- /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 0000000000000000000000000000000000000000..700444d6d6eda1f33fd7f2dfc6b067ecc2df4463 --- /dev/null +++ b/components/lwp/lwp_syscall.c @@ -0,0 +1,297 @@ +/* + * 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 + +#include +#include + +#if (defined(RT_USING_SAL) && defined(SAL_USING_POSIX)) +#include + +#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 + +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 0000000000000000000000000000000000000000..eb5d6313574747c0f6e462f0991b7db53f41b492 --- /dev/null +++ b/components/lwp/lwp_syscall.h @@ -0,0 +1,77 @@ +/* + * 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 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