提交 bca65f30 编写于 作者: B Bernard Xiong

[lwP] Add light weight process component.

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