Ver Fonte

add sys_execve support

shaojinchun há 4 anos atrás
pai
commit
e33e50b103

+ 12 - 6
components/lwp/arch/arm/cortex-a/lwp_gcc.S

@@ -98,6 +98,18 @@ lwp_get_user_sp:
     cps #Mode_SVC
     mov pc, lr
 
+/*
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+*/
+.global lwp_exec_user
+lwp_exec_user:
+    mov sp, r1
+    mov lr, r2
+    mov r2, #Mode_USR
+    msr spsr_cxsf, r2
+    ldr r3, =0x80000000
+    b ret_to_user
+
 /*
  * void SVC_Handler(void);
  */
@@ -107,10 +119,7 @@ vector_swi:
     push {lr}
     mrs lr, spsr
     push {r4, r5, lr}
-    tst lr, #(1 << 7)   /* mask irq ? */
-    bne 1f
     cpsie i
-1:
     push {r0 - r3, r12}
     and r0, r7, #0xff
     cmp r0, #0xfe
@@ -127,11 +136,8 @@ vector_swi:
     blx lr
 
 svc_exit:
-    mrs r4, cpsr
     cpsid i
-    tst r4, #(1 << 7)   /* mask irq ? */
     pop {r4, r5, lr}
-    orrne lr, #(1 << 7)
     msr spsr_cxsf, lr
     pop {lr}
 

+ 76 - 70
components/lwp/lwp.c

@@ -27,49 +27,6 @@
 #define DBG_LVL DBG_WARNING
 #include <rtdbg.h>
 
-#define AUX_ARRAY_ITEMS_NR 6
-
-/* aux key */
-#define AT_NULL 0
-#define AT_IGNORE 1
-#define AT_EXECFD 2
-#define AT_PHDR 3
-#define AT_PHENT 4
-#define AT_PHNUM 5
-#define AT_PAGESZ 6
-#define AT_BASE 7
-#define AT_FLAGS 8
-#define AT_ENTRY 9
-#define AT_NOTELF 10
-#define AT_UID 11
-#define AT_EUID 12
-#define AT_GID 13
-#define AT_EGID 14
-#define AT_CLKTCK 17
-#define AT_PLATFORM 15
-#define AT_HWCAP 16
-#define AT_FPUCW 18
-#define AT_DCACHEBSIZE 19
-#define AT_ICACHEBSIZE 20
-#define AT_UCACHEBSIZE 21
-#define AT_IGNOREPPC 22
-#define AT_SECURE 23
-#define AT_BASE_PLATFORM 24
-#define AT_RANDOM 25
-#define AT_HWCAP2 26
-#define AT_EXECFN 31
-
-struct process_aux_item
-{
-    uint32_t key;
-    uint32_t value;
-};
-
-struct process_aux
-{
-    struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
-};
-
 #ifdef RT_USING_USERSPACE
 #ifdef RT_USING_GDBSERVER
 #include <hw_breakpoint.h>
@@ -109,7 +66,7 @@ uint32_t *lwp_get_kernel_sp(void)
 }
 
 #ifdef RT_USING_USERSPACE
-static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
+struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
 {
     int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
     int *args;
@@ -142,12 +99,16 @@ static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **arg
     size += sizeof(struct process_aux);
 
     if (size > ARCH_PAGE_SIZE)
+    {
         return RT_NULL;
+    }
 
     /* args = (int *)lwp_map_user(lwp, 0, size); */
     args = (int *)lwp_map_user(lwp, (void *)(KERNEL_VADDR_START - ARCH_PAGE_SIZE), size, 0);
     if (args == RT_NULL)
+    {
         return RT_NULL;
+    }
 
     args_k = (int *)rt_hw_mmu_v2p(&lwp->mmu_info, args);
     args_k = (int *)((size_t)args_k - PV_OFFSET);
@@ -234,7 +195,9 @@ static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **arg
 
     args = (int *)rt_malloc(size);
     if (args == RT_NULL)
+    {
         return RT_NULL;
+    }
 
     /* argc, argv[], 0, envp[], 0 */
     str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
@@ -355,6 +318,36 @@ void lwp_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, s
 void lwp_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf_sym *dynsym);
 #endif
 
+struct map_range
+{
+    void *start;
+    size_t size;
+};
+
+static void expand_map_range(struct map_range *m, void *start, size_t size)
+{
+    if (!m->start)
+    {
+        m->start = start;
+        m->size = size;
+    }
+    else
+    {
+        void *end = (void *)((char*)start + size);
+        void *mend = (void *)((char*)m->start + m->size);
+
+        if (m->start > start)
+        {
+            m->start = start;
+        }
+        if (mend < end)
+        {
+            mend = end;
+        }
+        m->size = (char *)mend - (char *)m->start;
+    }
+}
+
 static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, struct process_aux *aux)
 {
     uint32_t i;
@@ -373,6 +366,8 @@ static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, str
     size_t rel_dyn_size = 0;
     size_t dynsym_off = 0;
     size_t dynsym_size = 0;
+    struct map_range text_area = {NULL, 0};
+    struct map_range data_area = {NULL, 0};
 #ifdef RT_USING_USERSPACE
     void *pa, *va;
 #endif
@@ -399,17 +394,17 @@ static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, str
     read_len = load_fread(&eheader, 1, sizeof eheader, fd);
     check_read(read_len, sizeof eheader);
 
-    #ifndef ARCH_CPU_64BIT
-        if (eheader.e_ident[4] != 1)
-        { /* not 32bit */
-            return -RT_ERROR;
-        }
-    #else
-        if (eheader.e_ident[4] != 2)
-        { /* not 64bit */
-            return -RT_ERROR;
-        }
-    #endif
+#ifndef ARCH_CPU_64BIT
+    if (eheader.e_ident[4] != 1)
+    { /* not 32bit */
+        return -RT_ERROR;
+    }
+#else
+    if (eheader.e_ident[4] != 2)
+    { /* not 64bit */
+        return -RT_ERROR;
+    }
+#endif
 
     if (eheader.e_ident[6] != 1)
     { /* ver not 1 */
@@ -483,9 +478,6 @@ static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, str
     off = eheader.e_shoff;
     for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
     {
-        int need_map = 0;
-        int text = 0;
-
         check_off(off, len);
         lseek(fd, off, SEEK_SET);
         read_len = load_fread(&sheader, 1, sizeof sheader, fd);
@@ -499,25 +491,38 @@ static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, str
         switch (sheader.sh_type)
         {
             case SHT_PROGBITS:
-                if ((sheader.sh_flags & SHF_EXECINSTR) != 0)
+                if ((sheader.sh_flags & SHF_WRITE) == 0)
                 {
-                    text = 1;
+                    expand_map_range(&text_area, (void *)sheader.sh_addr, sheader.sh_size);
                 }
+                else
+                {
+                    expand_map_range(&data_area, (void *)sheader.sh_addr, sheader.sh_size);
+                }
+                break;
             case SHT_NOBITS:
-                need_map = 1;
+                expand_map_range(&data_area, (void *)sheader.sh_addr, sheader.sh_size);
                 break;
             default:
                 break;
         }
-        if (need_map)
+    }
+    if (text_area.start)
+    {
+        va = lwp_map_user(lwp, text_area.start, text_area.size, 1);
+        if (!va || (va != text_area.start))
         {
-            /* map user */
-            va = lwp_map_user(lwp, (void *)sheader.sh_addr, sheader.sh_size, text);
-            if (!va || (va != (void *)(size_t)sheader.sh_addr))
-            {
-                result = -RT_ERROR;
-                goto _exit;
-            }
+            result = -RT_ERROR;
+            goto _exit;
+        }
+    }
+    if (data_area.start)
+    {
+        va = lwp_map_user(lwp, data_area.start, data_area.size, 0);
+        if (!va || (va != data_area.start))
+        {
+            result = -RT_ERROR;
+            goto _exit;
         }
     }
 #endif
@@ -733,7 +738,6 @@ _exit:
     if (result != RT_EOK)
     {
         LOG_E("lwp dynamic load faild, %d", result);
-        lwp_ref_dec(lwp);
     }
     return result;
 }
@@ -896,7 +900,9 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
     int tid = 0;
 
     if (filename == RT_NULL)
+    {
         return -RT_ERROR;
+    }
 
     lwp = lwp_new();
 

+ 48 - 1
components/lwp/lwp.h

@@ -71,7 +71,7 @@ struct rt_lwp
     void *text_entry;
     uint32_t text_size;
     void *data_entry;
-    uint32_t *data_size;
+    uint32_t data_size;
 
     int ref;
     void *args;
@@ -116,6 +116,10 @@ void lwp_set_thread_area(void *p);
 void* rt_cpu_get_thread_idr(void);
 void rt_cpu_set_thread_idr(void *p);
 
+pid_t lwp_pid_get(void);
+void lwp_pid_put(pid_t pid);
+void lwp_pid_set_lwp(pid_t pid, struct rt_lwp *lwp);
+
 int lwp_tid_get(void);
 void lwp_tid_put(int tid);
 rt_thread_t lwp_tid_get_thread(int tid);
@@ -183,4 +187,47 @@ struct __pthread {
 }
 #endif
 
+#define AUX_ARRAY_ITEMS_NR 6
+
+/* aux key */
+#define AT_NULL 0
+#define AT_IGNORE 1
+#define AT_EXECFD 2
+#define AT_PHDR 3
+#define AT_PHENT 4
+#define AT_PHNUM 5
+#define AT_PAGESZ 6
+#define AT_BASE 7
+#define AT_FLAGS 8
+#define AT_ENTRY 9
+#define AT_NOTELF 10
+#define AT_UID 11
+#define AT_EUID 12
+#define AT_GID 13
+#define AT_EGID 14
+#define AT_CLKTCK 17
+#define AT_PLATFORM 15
+#define AT_HWCAP 16
+#define AT_FPUCW 18
+#define AT_DCACHEBSIZE 19
+#define AT_ICACHEBSIZE 20
+#define AT_UCACHEBSIZE 21
+#define AT_IGNOREPPC 22
+#define AT_SECURE 23
+#define AT_BASE_PLATFORM 24
+#define AT_RANDOM 25
+#define AT_HWCAP2 26
+#define AT_EXECFN 31
+
+struct process_aux_item
+{
+    uint32_t key;
+    uint32_t value;
+};
+
+struct process_aux
+{
+    struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
+};
+
 #endif

+ 69 - 55
components/lwp/lwp_pid.c

@@ -36,12 +36,55 @@
 
 PID_CT_ASSERT(pid_max_nr, RT_LWP_MAX_NR > 1);
 
-struct rt_pid_struct
+static struct rt_lwp *lwp_pid_ary[RT_LWP_MAX_NR];
+static struct rt_lwp **lwp_pid_free_head = RT_NULL;
+static pid_t lwp_pid_ary_alloced = 1; /* 0 is reserved */
+
+pid_t lwp_pid_get(void)
 {
-    struct rt_lwp* pidmap[RT_LWP_MAX_NR];
-    pid_t last_pid;
-};
-static struct rt_pid_struct pid_struct = {{0}, 1};
+    pid_t ret = 0;
+    rt_base_t level = rt_hw_interrupt_disable();
+    struct rt_lwp **p = lwp_pid_free_head;
+
+    if (p)
+    {
+        lwp_pid_free_head = (struct rt_lwp **)*p;
+    }
+    else if (lwp_pid_ary_alloced < RT_LWP_MAX_NR)
+    {
+        p = lwp_pid_ary + lwp_pid_ary_alloced;
+        lwp_pid_ary_alloced++;
+    }
+    if (p)
+    {
+        *p = RT_NULL;
+        ret = p - lwp_pid_ary;
+    }
+    rt_hw_interrupt_enable(level);
+    return ret;
+}
+
+void lwp_pid_put(pid_t pid)
+{
+    struct rt_lwp **p = RT_NULL;
+    rt_base_t level = rt_hw_interrupt_disable();
+
+    if (pid > 0 && pid < RT_LWP_MAX_NR)
+    {
+        p = lwp_pid_ary + pid;
+        *p = (struct rt_lwp *)lwp_pid_free_head;
+        lwp_pid_free_head = p;
+    }
+    rt_hw_interrupt_enable(level);
+}
+
+void lwp_pid_set_lwp(pid_t pid, struct rt_lwp *lwp)
+{
+    if (pid > 0 && pid < RT_LWP_MAX_NR)
+    {
+        lwp_pid_ary[pid] = lwp;
+    }
+}
 
 int libc_stdio_get_console(void);
 
@@ -65,47 +108,18 @@ static void __exit_files(struct rt_lwp *lwp)
 
 struct rt_lwp* lwp_new(void)
 {
-    uint32_t i;
+    pid_t pid;
     rt_base_t level;
     struct rt_lwp* lwp = RT_NULL;
 
     level = rt_hw_interrupt_disable();
 
-    /* first scan */
-    for (i = pid_struct.last_pid; i < RT_LWP_MAX_NR; i++)
+    pid = lwp_pid_get();
+    if (pid == 0)
     {
-        if (!pid_struct.pidmap[i])
-        {
-            break;
-        }
-    }
-
-    /* if first scan failed, scan the pidmap start with 0 */
-    if (i >= RT_LWP_MAX_NR)
-    {
-        /* 0 is reserved */
-        for (i = 1; i < pid_struct.last_pid; i++)
-        {
-            if (!pid_struct.pidmap[i])
-            {
-                break;
-            }
-        }
-    }
-
-    if (i >= RT_LWP_MAX_NR)
-    {
-        /* if second scan also failed */
-        LOG_W("pidmap fulled\n");
-        pid_struct.last_pid = 0;
+        LOG_E("pid slot fulled!\n");
         goto out;
     }
-    pid_struct.last_pid = (i + 1) % RT_LWP_MAX_NR;
-    if (pid_struct.last_pid == 0)
-    {
-        /* 0 is reserved */
-        pid_struct.last_pid++;
-    }
     lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
     if (lwp == RT_NULL)
     {
@@ -114,8 +128,8 @@ struct rt_lwp* lwp_new(void)
     }
     rt_memset(lwp, 0, sizeof(*lwp));
     rt_list_init(&lwp->wait_list);
-    lwp->pid = i;
-    pid_struct.pidmap[i] = lwp;
+    lwp->pid = pid;
+    lwp_pid_set_lwp(pid, lwp);
     rt_list_init(&lwp->t_grp);
     rt_list_init(&lwp->object_list);
     lwp->address_search_head = RT_NULL;
@@ -127,7 +141,7 @@ out:
     return lwp;
 }
 
-static void lwp_user_obj_free(struct rt_lwp *lwp)
+void lwp_user_obj_free(struct rt_lwp *lwp)
 {
     rt_base_t level = 0;
     struct rt_list_node *list = RT_NULL, *node = RT_NULL;
@@ -250,7 +264,7 @@ void lwp_free(struct rt_lwp* lwp)
         lwp->first_child = child->sibling;
         if (child->finish)
         {
-            pid_struct.pidmap[lwp_to_pid(child)] = RT_NULL;
+            lwp_pid_put(lwp_to_pid(child));
             rt_free(child);
         }
         else
@@ -283,7 +297,7 @@ void lwp_free(struct rt_lwp* lwp)
         }
         else
         {
-            pid_struct.pidmap[lwp_to_pid(lwp)] = RT_NULL;
+            lwp_pid_put(lwp_to_pid(lwp));
             rt_free(lwp);
         }
     }
@@ -333,21 +347,21 @@ struct rt_lwp* lwp_from_pid(pid_t pid)
     {
         return NULL;
     }
-    return pid_struct.pidmap[pid];
+    return lwp_pid_ary[pid];
 }
 
 pid_t lwp_to_pid(struct rt_lwp* lwp)
 {
     if (!lwp)
     {
-        return -1;
+        return 0;
     }
     return lwp->pid;
 }
 
 char* lwp_pid2name(int32_t pid)
 {
-    struct rt_lwp* lwp;
+    struct rt_lwp *lwp;
     char* process_name = RT_NULL;
 
     lwp = lwp_from_pid(pid);
@@ -359,19 +373,19 @@ char* lwp_pid2name(int32_t pid)
     return process_name;
 }
 
-int32_t lwp_name2pid(const char* name)
+int32_t lwp_name2pid(const char *name)
 {
-    uint32_t pid;
+    pid_t pid;
     rt_thread_t main_thread;
     char* process_name = RT_NULL;
-    struct rt_lwp* lwp = RT_NULL;
 
     for (pid = 1; pid < RT_LWP_MAX_NR; pid++)
     {
         /* 0 is reserved */
-        if (pid_struct.pidmap[pid])
+        struct rt_lwp *lwp = lwp_pid_ary[pid];
+
+        if (lwp && (lwp < (struct rt_lwp *)&lwp_pid_ary[0] || lwp >= (struct rt_lwp *)&lwp_pid_ary[RT_LWP_MAX_NR]))
         {
-            lwp = pid_struct.pidmap[pid];
             process_name = strrchr(lwp->cmd, '/');
             process_name = process_name? process_name + 1: lwp->cmd;
             if (!rt_strncmp(name, process_name, RT_NAME_MAX))
@@ -450,7 +464,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
         }
         (*lwp_node) = lwp->sibling;
 
-        pid_struct.pidmap[pid] = RT_NULL;
+        lwp_pid_put(pid);
         rt_free(lwp);
     }
 
@@ -516,7 +530,6 @@ long list_process(void)
     int index;
     int maxlen;
     rt_ubase_t level;
-    struct rt_lwp* lwp = RT_NULL;
     struct rt_thread *thread;
     struct rt_list_node *node, *list;
     const char *item_title = "thread";
@@ -575,9 +588,10 @@ long list_process(void)
 
     for (index = 0; index < RT_LWP_MAX_NR; index++)
     {
-        if (pid_struct.pidmap[index])
+        struct rt_lwp *lwp = lwp_pid_ary[index];
+
+        if (lwp && (lwp < (struct rt_lwp *)&lwp_pid_ary[0] || lwp >= (struct rt_lwp *)&lwp_pid_ary[RT_LWP_MAX_NR]))
         {
-            lwp = pid_struct.pidmap[index];
             list = &lwp->t_grp;
             for (node = list->next; node != list; node = node->next)
             {

+ 278 - 34
components/lwp/lwp_syscall.c

@@ -19,6 +19,7 @@
 #include <lwp.h>
 #ifdef RT_USING_USERSPACE
 #include <lwp_user_mm.h>
+#include <lwp_arch.h>
 #endif
 
 #ifdef RT_USING_DFS
@@ -413,7 +414,7 @@ ssize_t sys_read(int fd, void *buf, size_t nbyte)
 
     if (!lwp_user_accessable((void *)buf, nbyte))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -452,7 +453,7 @@ ssize_t sys_write(int fd, const void *buf, size_t nbyte)
 
     if (!lwp_user_accessable((void *)buf, nbyte))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -489,7 +490,7 @@ int sys_open(const char *name, int flag, ...)
 
     if (!lwp_user_accessable((void *)name, 1))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -644,7 +645,7 @@ int sys_poll(struct pollfd *fds, nfds_t nfds, int timeout)
 
     if (!lwp_user_accessable((void *)fds, nfds * sizeof *fds))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -701,7 +702,7 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void *)readfds, sizeof *readfds))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             goto quit;
         }
         kreadfds = (fd_set *)kmem_get(sizeof *kreadfds);
@@ -716,7 +717,7 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void *)writefds, sizeof *writefds))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             goto quit;
         }
         kwritefds = (fd_set *)kmem_get(sizeof *kwritefds);
@@ -731,7 +732,7 @@ int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, s
     {
         if (!lwp_user_accessable((void *)exceptfds, sizeof *exceptfds))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             goto quit;
         }
         kexceptfds = (fd_set *)kmem_get(sizeof *kexceptfds);
@@ -784,7 +785,7 @@ int sys_unlink(const char *pathname)
 
     if (!lwp_user_accessable((void *)pathname, 1))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -824,7 +825,7 @@ int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
 
     if (!lwp_user_accessable((void *)rqtp, sizeof *rqtp))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -837,7 +838,7 @@ int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
     {
         if (!lwp_user_accessable((void *)rmtp, sizeof *rmtp))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return -1;
         }
 
@@ -876,7 +877,7 @@ int sys_gettimeofday(struct timeval *tp, struct timezone *tzp)
     {
         if (!lwp_user_accessable((void *)tp, sizeof *tp))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return -1;
         }
 
@@ -1261,7 +1262,7 @@ long sys_clone(void *arg[])
     /* check args */
     if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR])))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -1281,7 +1282,7 @@ long sys_clone(void *arg[])
     {
         if (!lwp_user_accessable(new_tid, sizeof(int)))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return -1;
         }
     }
@@ -1559,6 +1560,248 @@ fail:
     return -1;
 }
 
+size_t lwp_user_strlen(const char *s, int *err)
+{
+    size_t len = 0;
+
+    while (1)
+    {
+        if (!lwp_user_accessable((void *)(s + len), sizeof(char)))
+        {
+            if (err)
+            {
+                *err = 1;
+            }
+            return 0;
+        }
+        if (s[len] == '\0')
+        {
+            if (err)
+            {
+                *err = 0;
+            }
+            return len;
+        }
+        len++;
+    }
+}
+
+struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp);
+int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux);
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry);
+void lwp_user_obj_free(struct rt_lwp *lwp);
+
+#define _swap_lwp_data(lwp_used, lwp_new, type, member) \
+    do {\
+        type tmp;\
+        tmp = lwp_used->member;\
+        lwp_used->member = lwp_new->member;\
+        lwp_new->member = tmp;\
+    } while (0)
+
+int sys_execve(const char *path, char *const argv[], char *const envp[])
+{
+    int ret = -1;
+    int argc = 0;
+    int envc = 0;
+    void *page = NULL;
+    int size = 0;
+    size_t len;
+    int access_err;
+    char **kargv;
+    char **kenvp;
+    char *p;
+    struct rt_lwp *new_lwp = NULL;
+    struct rt_lwp *lwp;
+    rt_base_t level;
+    int uni_thread;
+    rt_thread_t thread;
+    struct process_aux *aux;
+    int i;
+
+    lwp = lwp_self();
+    thread = rt_thread_self();
+    uni_thread = 1;
+    level = rt_hw_interrupt_disable();
+    if (lwp->t_grp.prev != &thread->sibling)
+    {
+        uni_thread = 0;
+    }
+    if (lwp->t_grp.next != &thread->sibling)
+    {
+        uni_thread = 0;
+    }
+    rt_hw_interrupt_enable(level);
+    if (!uni_thread)
+    {
+        rt_set_errno(EINVAL);
+        goto quit;
+    }
+
+    if (argv)
+    {
+        while (1)
+        {
+            if (!lwp_user_accessable((void *)(argv + argc), sizeof(char *)))
+            {
+                rt_set_errno(EFAULT);
+                goto quit;
+            }
+            size += sizeof(char *);
+            if (!argv[argc])
+            {
+                break;
+            }
+            len = lwp_user_strlen((const char *)argv[argc], &access_err);
+            if (access_err)
+            {
+                rt_set_errno(EFAULT);
+                goto quit;
+            }
+            size += len + 1;
+            argc++;
+        }
+        size += sizeof(char *);
+    }
+    if (envp)
+    {
+        while (1)
+        {
+            if (!lwp_user_accessable((void *)(envp + envc), sizeof(char *)))
+            {
+                rt_set_errno(EFAULT);
+                goto quit;
+            }
+            size += sizeof(char *);
+            if (!envp[envc])
+            {
+                break;
+            }
+            len = lwp_user_strlen((const char *)envp[envc], &access_err);
+            if (access_err)
+            {
+                rt_set_errno(EFAULT);
+                goto quit;
+            }
+            size += len + 1;
+            envc++;
+        }
+        size += sizeof(char *);
+    }
+    if (size > ARCH_PAGE_SIZE)
+    {
+        rt_set_errno(EINVAL);
+        goto quit;
+    }
+    page = rt_pages_alloc(0); /* 1 page */
+    if (!page)
+    {
+        rt_set_errno(ENOMEM);
+        goto quit;
+    }
+
+    kargv = (char **)page;
+    kenvp = kargv + argc + 1;
+    p = (char *)(kenvp + envc + 1);
+    /* copy argv */
+    if (argv)
+    {
+        for (i = 0; i < argc; i++)
+        {
+            if (argv[i])
+            {
+                kargv[i] = p;
+                len = rt_strlen(argv[i]) + 1;
+                rt_memcpy(p, argv[i], len);
+                p += len;
+            }
+        }
+        kargv[i] = NULL;
+    }
+    /* copy envp */
+    if (envp)
+    {
+        for (i = 0; i < envc; i++)
+        {
+            if (envp[i])
+            {
+                kenvp[i] = p;
+                len = rt_strlen(envp[i]) + 1;
+                rt_memcpy(p, envp[i], len);
+                p += len;
+            }
+        }
+        kenvp[i] = NULL;
+    }
+
+    /* alloc new lwp to operation */
+    new_lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
+    if (!new_lwp)
+    {
+        rt_set_errno(ENOMEM);
+        goto quit;
+    }
+    rt_memset(new_lwp, 0, sizeof(struct rt_lwp));
+    new_lwp->ref = 1;
+    ret = arch_user_space_init(new_lwp);
+    if (ret != 0)
+    {
+        rt_set_errno(ENOMEM);
+        goto quit;
+    }
+    if ((aux = lwp_argscopy(new_lwp, argc, kargv, kenvp)) == NULL)
+    {
+        rt_set_errno(ENOMEM);
+        goto quit;
+    }
+    rt_pages_free(page, 0);
+    page = NULL;
+
+    ret = lwp_load(path, new_lwp, RT_NULL, 0, aux);
+    if (ret == RT_EOK)
+    {
+        /* load ok, now swap the data of lwp and new_lwp */
+        rt_hw_interrupt_disable();
+
+#ifdef RT_USING_USERSPACE
+        _swap_lwp_data(lwp, new_lwp, rt_mmu_info, mmu_info);
+        _swap_lwp_data(lwp, new_lwp, struct lwp_avl_struct *, map_area);
+        _swap_lwp_data(lwp, new_lwp, size_t, end_heap);
+#endif
+        _swap_lwp_data(lwp, new_lwp, uint8_t, lwp_type);
+        _swap_lwp_data(lwp, new_lwp, void *, text_entry);
+        _swap_lwp_data(lwp, new_lwp, uint32_t, text_size);
+        _swap_lwp_data(lwp, new_lwp, void *, data_entry);
+        _swap_lwp_data(lwp, new_lwp, uint32_t, data_size);
+
+        _swap_lwp_data(lwp, new_lwp, void *, args);
+
+        rt_memset(&lwp->signal_mask, 0, sizeof(lwp->signal_mask));
+        rt_memset(&lwp->signal_mask_bak, 0, sizeof(lwp->signal_mask_bak));
+        rt_memset(lwp->signal_handler, 0, sizeof(lwp->signal_handler));
+
+        /* to do: clsoe files with flag CLOEXEC */
+
+        lwp_mmu_switch(thread);
+        lwp_ref_dec(new_lwp);
+        lwp_exec_user(lwp->args,
+                thread->stack_addr + thread->stack_size,
+                lwp->text_entry);
+        /* never reach here, so rt_hw_interrupt_enable is not needed */
+    }
+    rt_set_errno(EINVAL);
+quit:
+    if (page)
+    {
+        rt_pages_free(page, 0);
+    }
+    if (new_lwp)
+    {
+        lwp_ref_dec(new_lwp);
+    }
+    return -1;
+}
+
 rt_err_t sys_thread_delete(rt_thread_t thread)
 {
     return rt_thread_delete(thread);
@@ -1755,7 +1998,7 @@ int sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
     {
         if (!lwp_user_accessable(addrlen, sizeof (socklen_t *)))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return -1;
         }
         lwp_get_from_user(&uaddrlen, addrlen, sizeof (socklen_t *));
@@ -1767,7 +2010,7 @@ int sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
 
         if (!lwp_user_accessable(addr, uaddrlen))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return -1;
         }
     }
@@ -1797,7 +2040,7 @@ int sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen)
 
     if (!lwp_user_accessable((void *)name, namelen))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
     lwp_get_from_user(&kname, (void *)name, namelen);
@@ -1822,7 +2065,7 @@ int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
     lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
@@ -1834,7 +2077,7 @@ int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(name, unamelen))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -1865,7 +2108,7 @@ int sys_getsockname (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
     lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
@@ -1877,7 +2120,7 @@ int sys_getsockname (int socket, struct musl_sockaddr *name, socklen_t *namelen)
 
     if (!lwp_user_accessable(name, unamelen))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -1915,7 +2158,7 @@ int sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen)
 
     if (!lwp_user_accessable((void *)name, namelen))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
     lwp_get_from_user(&kname, (void *)name, namelen);
@@ -1982,7 +2225,7 @@ int sys_recvfrom(int socket, void *mem, size_t len, int flags,
 
     if (!lwp_user_accessable((void *)mem, len))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -2059,7 +2302,7 @@ int sys_sendto(int socket, const void *dataptr, size_t size, int flags,
 
     if (!lwp_user_accessable((void *)dataptr, size))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -2182,7 +2425,7 @@ int sys_sigaction(int sig, const struct sigaction *act,
     {
         if (!lwp_user_accessable((void *)oact, sigsetsize))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             goto out;
         }
         pkoact = &koact;
@@ -2191,7 +2434,7 @@ int sys_sigaction(int sig, const struct sigaction *act,
     {
         if (!lwp_user_accessable((void *)act, sigsetsize))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             goto out;
         }
         kact.__sa_handler._sa_handler = act->sa_handler;
@@ -2235,7 +2478,7 @@ int sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size
     {
         if (!lwp_user_accessable((void *)oset, size))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return ret;
         }
         poldset = &oldset;
@@ -2244,7 +2487,7 @@ int sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size
     {
         if (!lwp_user_accessable((void *)sigset, size))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return ret;
         }
         lwp_get_from_user(&newset, (void *)sigset, size);
@@ -2300,7 +2543,7 @@ int sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *os
     {
         if (!lwp_user_accessable((void *)oset, size))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return ret;
         }
         poldset = &oldset;
@@ -2309,7 +2552,7 @@ int sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *os
     {
         if (!lwp_user_accessable((void *)sigset, size))
         {
-            rt_set_errno(EINVAL);
+            rt_set_errno(EFAULT);
             return ret;
         }
         lwp_get_from_user(&newset, (void *)sigset, sizeof(lwp_sigset_t));
@@ -2632,7 +2875,7 @@ int sys_access(const char *filename, int mode)
 
     if (!lwp_user_accessable((void *)filename, 1))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
 
@@ -2664,7 +2907,7 @@ int sys_pipe(int fd[2])
 {
     if (!lwp_user_accessable((void *)fd, sizeof(int[2])))
     {
-        rt_set_errno(EINVAL);
+        rt_set_errno(EFAULT);
         return -1;
     }
     return pipe(fd);
@@ -2687,7 +2930,7 @@ int sys_clock_settime(clockid_t clk, const struct timespec *ts)
 
     if (!lwp_user_accessable((void *)ts, size))
     {
-        return -EINVAL;
+        return -EFAULT;
     }
 
     kts = kmem_get(size);
@@ -2725,7 +2968,7 @@ int sys_clock_gettime(clockid_t clk, struct timespec *ts)
 
     if (!lwp_user_accessable((void *)ts, size))
     {
-        return -EINVAL;
+        return -EFAULT;
     }
 
     kts = kmem_get(size);
@@ -2754,7 +2997,7 @@ int sys_clock_getres(clockid_t clk, struct timespec *ts)
 
     if (!lwp_user_accessable((void *)ts, size))
     {
-        return -EINVAL;
+        return -EFAULT;
     }
 
     kts.tv_sec = 1;
@@ -2932,6 +3175,7 @@ const static void* func_table[] =
     (void *)sys_dup2,
     (void *)sys_rename,			/* 135 */
     (void *)sys_fork,
+    (void *)sys_execve,
 };
 
 const void *lwp_get_sys_api(rt_uint32_t number)

+ 6 - 1
components/lwp/lwp_tid.c

@@ -27,6 +27,11 @@
 #define DBG_LVL    DBG_INFO
 #include <rtdbg.h>
 
+#define TID_CT_ASSERT(name, x) \
+    struct assert_##name {char ary[2 * (x) - 1];}
+
+TID_CT_ASSERT(tid_max_nr, LWP_TID_MAX_NR > 1);
+
 static rt_thread_t lwp_tid_ary[LWP_TID_MAX_NR];
 static rt_thread_t *lwp_tid_free_head = RT_NULL;
 static int lwp_tid_ary_alloced = 1; /* 0 is reserved */
@@ -39,7 +44,7 @@ int lwp_tid_get(void)
 
     if (p)
     {
-        lwp_tid_free_head = (rt_thread_t*)*p;
+        lwp_tid_free_head = (rt_thread_t *)*p;
     }
     else if (lwp_tid_ary_alloced < LWP_TID_MAX_NR)
     {

+ 23 - 23
components/lwp/lwp_user_mm.c

@@ -136,12 +136,12 @@ void lwp_unmap_user_space(struct rt_lwp *lwp)
         unmap_range(lwp, (void *)ma->addr, ma->size, pa_need_free);
         lwp_map_area_remove(&lwp->map_area, ma->addr);
     }
-    
-    #ifdef ARCH_RISCV
-        rt_pages_free(m_info->vtable, 0);
-    #else
-        rt_pages_free(m_info->vtable, 2);
-    #endif
+
+#ifdef ARCH_RISCV
+    rt_pages_free(m_info->vtable, 0);
+#else
+    rt_pages_free(m_info->vtable, 2);
+#endif
 }
 
 static void *_lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, int text)
@@ -434,21 +434,21 @@ size_t lwp_get_from_user(void *dst, void *src, size_t size)
     rt_mmu_info *m_info = RT_NULL;
 
     /* check src */
-    #ifdef ARCH_RISCV64
-        if(src < (void *)USER_VADDR_START)
-        {
-            return 0;
-        }
-    #else
-        if (src >= (void*)KERNEL_VADDR_START)
-        {
-            return 0;
-        }
-        if ((void*)((char*)src + size) > (void*)KERNEL_VADDR_START)
-        {
-            return 0;
-        }
-    #endif
+#ifdef ARCH_RISCV64
+    if(src < (void *)USER_VADDR_START)
+    {
+        return 0;
+    }
+#else
+    if (src >= (void *)KERNEL_VADDR_START)
+    {
+        return 0;
+    }
+    if ((void *)((char *)src + size) > (void *)KERNEL_VADDR_START)
+    {
+        return 0;
+    }
+#endif
 
     lwp = lwp_self();
     if (!lwp)
@@ -500,7 +500,7 @@ int lwp_user_accessable(void *addr, size_t size)
         return 0;
     }
     addr_start = addr;
-    addr_end = (void*)((char*)addr + size);
+    addr_end = (void *)((char *)addr + size);
 
 #ifdef ARCH_RISCV64
     if(addr_start < (void *)USER_VADDR_START)
@@ -508,7 +508,7 @@ int lwp_user_accessable(void *addr, size_t size)
         return 0;
     }
 #else
-    if (addr_start >= (void*)KERNEL_VADDR_START)
+    if (addr_start >= (void *)KERNEL_VADDR_START)
     {
         return 0;
     }

+ 12 - 0
libcpu/arm/cortex-a/backtrace.c

@@ -17,6 +17,12 @@
 #define DBG_LVL    DBG_INFO
 #include <rtdbg.h>
 
+#ifdef RT_USING_USERSPACE
+#include <lwp.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+#endif
+
 rt_inline void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
 {
     frame->fp = frame_pointer(regs);
@@ -516,6 +522,12 @@ void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj)
     e_regs.ARM_sp = regs->sp;
     e_regs.ARM_lr = regs->lr;
     e_regs.ARM_pc = regs->pc - pc_adj;
+#ifdef RT_USING_USERSPACE
+    if (!lwp_user_accessable((void *)e_regs.ARM_pc, sizeof (void *)))
+    {
+        e_regs.ARM_pc = regs->lr - sizeof(void *);
+    }
+#endif
     rt_kprintf("backtrace:\n");
     unwind_backtrace(&e_regs, __exidx_start, __exidx_end);
 }