summaryrefslogtreecommitdiff
path: root/components/lwp
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp')
-rw-r--r--components/lwp/Kconfig16
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_arch.c24
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_arch.h7
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_gcc.S4
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_arch.c9
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_arch.h2
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_gcc.S7
-rw-r--r--components/lwp/arch/risc-v/rv64/lwp_arch.c8
-rw-r--r--components/lwp/lwp.c42
-rw-r--r--components/lwp/lwp.h4
-rw-r--r--components/lwp/lwp_elf.c811
-rw-r--r--components/lwp/lwp_ipc.c1
-rw-r--r--components/lwp/lwp_pid.c2
-rw-r--r--components/lwp/lwp_shm.c1
-rw-r--r--components/lwp/lwp_syscall.c151
-rw-r--r--components/lwp/lwp_user_mm.c747
-rw-r--r--components/lwp/lwp_user_mm.h59
-rw-r--r--components/lwp/syscall_generic.h35
18 files changed, 1617 insertions, 313 deletions
diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig
index a63c85beef..18505932db 100644
--- a/components/lwp/Kconfig
+++ b/components/lwp/Kconfig
@@ -68,4 +68,20 @@ if RT_USING_LWP
bool "The unix98 PTY debug output"
default n
endif
+
+ menuconfig RT_USING_LDSO
+ bool "LDSO: dynamic load shared objects"
+ default n
+
+ if RT_USING_LDSO
+ config ELF_DEBUG_ENABLE
+ bool "Enable ldso debug"
+ default n
+
+ config ELF_LOAD_RANDOMIZE
+ bool "Enable random load address"
+ default n
+ endif
+
endif
+
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.c b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c
index fbb50bfdca..e46b8ac59a 100644
--- a/components/lwp/arch/aarch64/cortex-a/lwp_arch.c
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c
@@ -31,22 +31,20 @@ int arch_user_space_init(struct rt_lwp *lwp)
{
size_t *mmu_table;
- mmu_table = (size_t *)rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
- if (!mmu_table)
+ mmu_table = rt_hw_mmu_pgtbl_create();
+ if (mmu_table)
{
- return -RT_ENOMEM;
+ lwp->end_heap = USER_HEAP_VADDR;
+ lwp->aspace = rt_aspace_create(
+ (void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table);
+ if (!lwp->aspace)
+ {
+ return -RT_ERROR;
+ }
}
-
- lwp->end_heap = USER_HEAP_VADDR;
-
- memset(mmu_table, 0, ARCH_PAGE_SIZE);
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE);
-
- lwp->aspace = rt_aspace_create(
- (void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table);
- if (!lwp->aspace)
+ else
{
- return -RT_ERROR;
+ return -RT_ENOMEM;
}
return 0;
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.h b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h
index f9faebfc91..c7d9c8d74e 100644
--- a/components/lwp/arch/aarch64/cortex-a/lwp_arch.h
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h
@@ -17,10 +17,11 @@
#ifdef ARCH_MM_MMU
#define USER_VADDR_TOP 0x0001000000000000UL
-#define USER_HEAP_VEND 0x0000ffffB0000000UL
-#define USER_HEAP_VADDR 0x0000ffff80000000UL
+#define USER_HEAP_VADDR (0x0000ffff40000000UL)
+#define USER_HEAP_VEND USER_STACK_VSTART
#define USER_STACK_VSTART 0x0000ffff70000000UL
-#define USER_STACK_VEND USER_HEAP_VADDR
+#define USER_STACK_VEND (USER_STACK_VSTART + 0x10000000)
+#define USER_ARG_VADDR USER_STACK_VEND
#define LDSO_LOAD_VADDR 0x60000000UL
#define USER_VADDR_START 0x00200000UL
#define USER_LOAD_VADDR USER_VADDR_START
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S
index 541c360a55..1806dcf097 100644
--- a/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S
@@ -50,10 +50,12 @@
arch_start_umode:
mov sp, x3
mov x4, #(SPSR_Mode(0) | SPSR_A64)
- mov x3, x2 ;/* user stack top */
msr daifset, #3
dsb sy
mrs x30, sp_el0
+ /* user stack top */
+ msr sp_el0, x2
+ mov x3, x2
msr spsr_el1, x4
msr elr_el1, x1
eret
diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.c b/components/lwp/arch/arm/cortex-a/lwp_arch.c
index d1fcf63d93..0d8f965429 100644
--- a/components/lwp/arch/arm/cortex-a/lwp_arch.c
+++ b/components/lwp/arch/arm/cortex-a/lwp_arch.c
@@ -23,13 +23,11 @@
#include <lwp_arch.h>
#include <lwp_user_mm.h>
-#define KPTE_START (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT)
-
int arch_user_space_init(struct rt_lwp *lwp)
{
size_t *mmu_table;
- mmu_table = (size_t *)rt_pages_alloc(2);
+ mmu_table = rt_hw_mmu_pgtbl_create();
if (!mmu_table)
{
return -RT_ENOMEM;
@@ -37,9 +35,6 @@ int arch_user_space_init(struct rt_lwp *lwp)
lwp->end_heap = USER_HEAP_VADDR;
- rt_memcpy(mmu_table + KPTE_START, (size_t *)rt_kernel_space.page_table + KPTE_START, ARCH_PAGE_SIZE);
- rt_memset(mmu_table, 0, 3 * ARCH_PAGE_SIZE);
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * ARCH_PAGE_SIZE);
lwp->aspace = rt_aspace_create((void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table);
if (!lwp->aspace)
@@ -87,7 +82,7 @@ void arch_user_space_free(struct rt_lwp *lwp)
rt_aspace_delete(lwp->aspace);
/* must be freed after aspace delete, pgtbl is required for unmap */
- rt_pages_free(pgtbl, 2);
+ rt_hw_mmu_pgtbl_delete(pgtbl);
lwp->aspace = RT_NULL;
}
else
diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.h b/components/lwp/arch/arm/cortex-a/lwp_arch.h
index def88bf3b2..7262f446c8 100644
--- a/components/lwp/arch/arm/cortex-a/lwp_arch.h
+++ b/components/lwp/arch/arm/cortex-a/lwp_arch.h
@@ -21,7 +21,7 @@
#define USER_STACK_VSTART 0x70000000UL
#define USER_STACK_VEND USER_HEAP_VADDR
#define LDSO_LOAD_VADDR 0x60000000UL
-#define USER_VADDR_START 0x00100000UL
+#define USER_VADDR_START 0x00010000UL
#define USER_LOAD_VADDR USER_VADDR_START
#ifdef __cplusplus
diff --git a/components/lwp/arch/arm/cortex-a/lwp_gcc.S b/components/lwp/arch/arm/cortex-a/lwp_gcc.S
index 7e27592c6d..65da7c5313 100644
--- a/components/lwp/arch/arm/cortex-a/lwp_gcc.S
+++ b/components/lwp/arch/arm/cortex-a/lwp_gcc.S
@@ -43,7 +43,12 @@ arch_start_umode:
msr spsr, r9
mov sp, r3
- mov r3, r2 ;/* user stack top */
+ /* set user stack top */
+ cps #Mode_SYS
+ mov sp, r2
+ cps #Mode_SVC
+ mov r3, r2
+
/* set data address. */
movs pc, r1
diff --git a/components/lwp/arch/risc-v/rv64/lwp_arch.c b/components/lwp/arch/risc-v/rv64/lwp_arch.c
index 9a88709668..387a54f073 100644
--- a/components/lwp/arch/risc-v/rv64/lwp_arch.c
+++ b/components/lwp/arch/risc-v/rv64/lwp_arch.c
@@ -93,17 +93,13 @@ int arch_user_space_init(struct rt_lwp *lwp)
{
rt_ubase_t *mmu_table;
- mmu_table = (rt_ubase_t *)rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ mmu_table = rt_hw_mmu_pgtbl_create();
if (!mmu_table)
{
return -RT_ENOMEM;
}
lwp->end_heap = USER_HEAP_VADDR;
-
- rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE);
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE);
-
lwp->aspace = rt_aspace_create(
(void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table);
if (!lwp->aspace)
@@ -129,7 +125,7 @@ void arch_user_space_free(struct rt_lwp *lwp)
rt_aspace_delete(lwp->aspace);
/* must be freed after aspace delete, pgtbl is required for unmap */
- rt_pages_free(pgtbl, 0);
+ rt_hw_mmu_pgtbl_delete(pgtbl);
lwp->aspace = RT_NULL;
}
else
diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c
index 9e67c2123e..73847fd856 100644
--- a/components/lwp/lwp.c
+++ b/components/lwp/lwp.c
@@ -153,6 +153,9 @@ struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char
int len;
size_t *args_k;
struct process_aux *aux;
+ size_t prot = PROT_READ | PROT_WRITE;
+ size_t flags = MAP_FIXED | MAP_PRIVATE;
+ size_t zero = 0;
for (i = 0; i < argc; i++)
{
@@ -179,9 +182,8 @@ struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char
return RT_NULL;
}
- /* args = (int *)lwp_map_user(lwp, 0, size); */
- args = (int *)lwp_map_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE), size, 0);
- if (args == RT_NULL)
+ args = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0);
+ if (args == RT_NULL || lwp_data_put(lwp, args, &zero, sizeof(zero)) != sizeof(zero))
{
return RT_NULL;
}
@@ -1417,3 +1419,37 @@ void lwp_uthread_ctx_restore(void)
thread = rt_thread_self();
thread->user_ctx.ctx = RT_NULL;
}
+
+void rt_update_process_times(void)
+{
+ struct rt_thread *thread;
+#ifdef RT_USING_SMP
+ struct rt_cpu* pcpu;
+
+ pcpu = rt_cpu_self();
+#endif
+
+ thread = rt_thread_self();
+
+ if (!IS_USER_MODE(thread))
+ {
+ thread->user_time += 1;
+#ifdef RT_USING_SMP
+ pcpu->cpu_stat.user += 1;
+#endif
+ }
+ else
+ {
+ thread->system_time += 1;
+#ifdef RT_USING_SMP
+ if (thread == pcpu->idle_thread)
+ {
+ pcpu->cpu_stat.idle += 1;
+ }
+ else
+ {
+ pcpu->cpu_stat.system += 1;
+ }
+#endif
+ }
+}
diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h
index 6b137cff8e..2fcd880bc4 100644
--- a/components/lwp/lwp.h
+++ b/components/lwp/lwp.h
@@ -240,7 +240,9 @@ struct __pthread {
}
#endif
-#define AUX_ARRAY_ITEMS_NR 6
+#ifndef AUX_ARRAY_ITEMS_NR
+#define AUX_ARRAY_ITEMS_NR 32
+#endif
/* aux key */
#define AT_NULL 0
diff --git a/components/lwp/lwp_elf.c b/components/lwp/lwp_elf.c
new file mode 100644
index 0000000000..0610769b26
--- /dev/null
+++ b/components/lwp/lwp_elf.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-08-23 zhangsz first version
+ */
+
+#include <rtthread.h>
+
+#ifdef RT_USING_LDSO
+
+#include <dfs_file.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <lwp_elf.h>
+
+#include "lwp.h"
+#include "lwp_arch.h"
+
+#ifdef ARCH_MM_MMU
+#include <lwp_user_mm.h>
+#endif
+
+#define DBG_TAG "load.elf"
+#ifdef ELF_DEBUG_ENABLE
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif
+#include <rtdbg.h>
+
+#define ELF_INVALID_FD -1
+#define ELF_PHDR_NUM_MAX 128
+#define FILE_LENGTH_MAX 0xC0000000
+#define MEM_SIZE_MAX 0xC0000000
+#define ELF_PATH_MAX 256
+#define FLF_PATH_MIN 1
+
+#define ELF_PAGESTART(_v) ((_v) & ~(rt_ubase_t)(ARCH_PAGE_SIZE - 1))
+#define ELF_PAGEOFFSET(_v) ((_v) & (ARCH_PAGE_SIZE - 1))
+#define ELF_PAGEALIGN(_v) (((_v) + ARCH_PAGE_SIZE - 1) & ~(ARCH_PAGE_SIZE - 1))
+
+#define ELF_EXEC_LOAD_ADDR USER_VADDR_START
+#define ELF_INTERP_LOAD_ADDR LDSO_LOAD_VADDR
+
+#define ELF_AUX_ENT(aux, id, val) \
+ do \
+ { \
+ *aux++ = id; \
+ *aux++ = val; \
+ } while (0)
+
+typedef struct
+{
+ int fd;
+ char *filename;
+ rt_size_t file_len;
+ Elf_Ehdr ehdr;
+ Elf_Phdr *phdr;
+ rt_ubase_t map_size;
+} elf_info_t;
+
+typedef struct
+{
+ struct rt_lwp *lwp;
+ struct process_aux *aux;
+ elf_info_t exec_info;
+ elf_info_t interp_info;
+ rt_ubase_t load_addr;
+ rt_ubase_t e_entry;
+ rt_ubase_t interp_base;
+} elf_load_info_t;
+
+static void elf_user_dump(struct rt_lwp *lwp, void *va, size_t len)
+{
+#ifdef ELF_DEBUG_DUMP
+ uint8_t *k_va;
+ int ret;
+
+ if (len < 16)
+ len = 16;
+ rt_kprintf("\r\n");
+ rt_kprintf("%s : user va : %p, len : 0x%x(%d)\n", __func__, va, len, len);
+ k_va = rt_malloc(len);
+ if (k_va == RT_NULL)
+ {
+ rt_kprintf("%s : malloc failed\n", __func__);
+ return;
+ }
+ rt_memset(k_va, 0, len);
+
+ ret = lwp_data_get(lwp, k_va, va, len);
+ if (ret != len)
+ {
+ rt_kprintf("%s : lwp_get_from_user failed, ret = %d\n", __func__, ret);
+ return;
+ }
+
+ rt_kprintf("%s : k_va : %p\n", __func__, k_va);
+
+ for (size_t i = 0; i < len; i += 16)
+ {
+ rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x ", k_va[i], k_va[i+1], k_va[i+2], k_va[i+3],
+ k_va[i+4], k_va[i+5], k_va[i+6], k_va[i+7]);
+ rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x \n", k_va[i+8], k_va[i+9], k_va[i+10], k_va[i+11],
+ k_va[i+12], k_va[i+13], k_va[i+14], k_va[i+15]);
+ }
+ rt_kprintf("\r\n");
+ rt_free(k_va);
+#endif
+}
+
+rt_ubase_t elf_random_offset(void)
+{
+#ifdef ELF_LOAD_RANDOMIZE
+ return (rt_tick_get() % 65535) * ARCH_PAGE_SIZE;
+#else
+ return ELF_PAGEALIGN(0);
+#endif
+}
+
+static void *file_mmap(struct rt_lwp *lwp, int fd, rt_ubase_t load_addr,
+ rt_ubase_t map_size, size_t prot, size_t flags, rt_ubase_t offset)
+{
+ uint8_t *map_va;
+
+ map_va = (uint8_t *)lwp_mmap2(lwp, (void *)load_addr, map_size, prot, flags, fd, offset >> ARCH_PAGE_SHIFT);
+ if (!map_va || (map_va != (uint8_t *)load_addr))
+ {
+ LOG_E("%s : lwp map user failed!", __func__);
+ return RT_NULL;
+ }
+ LOG_D(" %s : map va = %p load_addr : %p size : 0x%x", __func__, map_va, load_addr, map_size);
+
+ return map_va;
+}
+
+static int elf_file_open(const char *filename)
+{
+ int fd = -1;
+
+ fd = open(filename, O_BINARY | O_RDONLY, 0);
+ if (fd < 0)
+ {
+ LOG_E("%s : elf file [%s] open failed!", __func__, filename);
+ }
+
+ return fd;
+}
+
+static int elf_file_close(int fd)
+{
+ return close(fd);
+}
+
+static int elf_file_length(char *filename, rt_size_t *file_len)
+{
+ int ret;
+ struct stat s = { 0 };
+
+ ret = stat(filename, &s);
+ if (ret != 0)
+ {
+ LOG_E("%s : error", __func__);
+ return -RT_ERROR;
+ }
+ *file_len = (rt_size_t)s.st_size;
+
+ return RT_EOK;
+}
+
+static int elf_file_read(rt_int32_t fd, rt_uint8_t *buffer, size_t size, off_t offset)
+{
+ ssize_t read_len;
+ off_t pos;
+
+ if (size > 0)
+ {
+ pos = lseek(fd, offset, SEEK_SET);
+ if (pos != offset)
+ {
+ LOG_E("%s : seek file offset: 0x%x failed", __func__, offset);
+ return -RT_ERROR;
+ }
+
+ read_len = read(fd, buffer, size);
+ if (read_len != size)
+ {
+ LOG_E("%s : read from offset: 0x%x error", __func__, offset);
+ return -RT_ERROR;
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_int32_t elf_check_ehdr(const Elf_Ehdr *ehdr, rt_uint32_t file_len)
+{
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
+ {
+ LOG_E("%s : e_ident error", __func__);
+ return -RT_ERROR;
+ }
+
+ if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN))
+ {
+ LOG_E("%s : e_type error", __func__);
+ return -RT_ERROR;
+ }
+
+ if (ehdr->e_machine == EM_NONE)
+ {
+ LOG_E("%s : e_machine is EM_NONE", __func__);
+ return -RT_ERROR;
+ }
+
+ if (ehdr->e_phnum > ELF_PHDR_NUM_MAX)
+ {
+ LOG_E("%s : e_phnum error", __func__);
+ return -RT_ERROR;
+ }
+
+ if (ehdr->e_phoff > file_len)
+ {
+ LOG_E("%s : e_phoff error", __func__);
+ return -RT_ERROR;
+ }
+
+ LOG_D("%s : e_entry : 0x%x", __func__, ehdr->e_entry);
+
+ return RT_EOK;
+}
+
+static int elf_check_phdr(const Elf_Phdr *phdr)
+{
+ if (phdr->p_filesz > FILE_LENGTH_MAX)
+ {
+ LOG_E("%s : phdr p_filesz 0x%x error", __func__, phdr->p_filesz);
+ return -RT_ERROR;
+ }
+
+ if (phdr->p_offset > FILE_LENGTH_MAX)
+ {
+ LOG_E("%s : phdr p_offset 0x%x error", __func__, phdr->p_offset);
+ return -RT_ERROR;
+ }
+
+ if (phdr->p_memsz > MEM_SIZE_MAX)
+ {
+ LOG_E("%s[%d], phdr p_memsz 0x%x error", __func__, phdr->p_memsz);
+ return -RT_ERROR;
+ }
+
+ LOG_D("%s : phdr p_vaddr : 0x%x", __func__, phdr->p_vaddr);
+
+ return RT_EOK;
+}
+
+static int elf_load_ehdr(elf_info_t *elf_info)
+{
+ int ret;
+
+ ret = elf_file_open(elf_info->filename);
+ if (ret < 0)
+ {
+ LOG_E("%s : elf_file_open %s failed", __func__, elf_info->filename);
+ return ret;
+ }
+
+ elf_info->fd = ret;
+
+ ret = elf_file_length(elf_info->filename, &elf_info->file_len);
+ if (ret != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ ret = elf_file_read(elf_info->fd, (rt_uint8_t *)&elf_info->ehdr, sizeof(Elf_Ehdr), 0);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_file_read failed, ret : %d", __func__, ret);
+ return -RT_ERROR;
+ }
+
+ ret = elf_check_ehdr(&elf_info->ehdr, elf_info->file_len);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_check_ehdr failed, ret : %d", __func__, ret);
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static int elf_load_phdr(elf_info_t *elf_info)
+{
+ Elf_Ehdr *ehdr = &elf_info->ehdr;
+ uint32_t size;
+ int ret;
+
+ if (ehdr->e_phnum < 1)
+ {
+ return -RT_ERROR;
+ }
+
+ if (ehdr->e_phentsize != sizeof(Elf_Phdr))
+ {
+ return -RT_ERROR;
+ }
+
+ size = sizeof(Elf_Phdr) * ehdr->e_phnum;
+ if ((ehdr->e_phoff + size) > elf_info->file_len)
+ {
+ return -RT_ERROR;
+ }
+
+ elf_info->phdr = rt_malloc(size);
+ if (elf_info->phdr == RT_NULL)
+ {
+ LOG_E("%s : alloc phdr failed", __func__);
+ return -RT_ENOMEM;
+ }
+
+ ret = elf_file_read(elf_info->fd, (rt_uint8_t *)elf_info->phdr, size, ehdr->e_phoff);
+ if (ret != RT_EOK)
+ {
+ rt_free(elf_info->phdr);
+ elf_info->phdr = RT_NULL;
+ LOG_E("%s : elf_file_read failed, ret = %d", __func__, ret);
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static int elf_load_interp(elf_load_info_t *load_info)
+{
+ Elf_Phdr *phdr = load_info->exec_info.phdr;
+ int ret;
+ int i;
+
+ for (i = 0; i < load_info->exec_info.ehdr.e_phnum; ++i, ++phdr)
+ {
+ if (phdr->p_type != PT_INTERP)
+ {
+ continue;
+ }
+
+ if (elf_check_phdr(phdr) != RT_EOK)
+ {
+ return -RT_ERROR;
+ }
+
+ if ((phdr->p_filesz > ELF_PATH_MAX) || (phdr->p_filesz < FLF_PATH_MIN))
+ {
+ LOG_E("%s : phdr p_filesz error", __func__, phdr->p_filesz);
+ return -RT_ERROR;
+ }
+
+ if (phdr->p_offset + phdr->p_filesz > load_info->exec_info.file_len)
+ {
+ LOG_E("%s : phdr p_offset error", __func__, phdr->p_offset);
+ return -RT_ERROR;
+ }
+
+ load_info->interp_info.filename = rt_malloc(phdr->p_filesz);
+ if (load_info->interp_info.filename == RT_NULL)
+ {
+ LOG_E("%s : alloc elf interpreter failed", __func__);
+ return -RT_ENOMEM;
+ }
+
+ ret = elf_file_read(load_info->exec_info.fd, (rt_uint8_t *)load_info->interp_info.filename,
+ phdr->p_filesz, phdr->p_offset);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_file_read failed, ret = %d", __func__, ret);
+ ret = -RT_ERROR;
+ goto error_exit;
+ }
+
+ if (load_info->interp_info.filename[phdr->p_filesz - 1] != '\0')
+ {
+ LOG_E("%s : elf interpreter is invalid", __func__);
+ ret = -RT_ERROR;
+ goto error_exit;
+ }
+
+ LOG_D("%s : elf interpreter : %s", __func__, load_info->interp_info.filename);
+
+ ret = elf_load_ehdr(&load_info->interp_info);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_load_ehdr failed, ret = %d", __func__, ret);
+ goto error_exit;
+ }
+
+ ret = elf_load_phdr(&load_info->interp_info);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_load_phdr failed, ret = %d", __func__, ret);
+ goto error_exit;
+ }
+ break;
+ }
+
+ return RT_EOK;
+
+error_exit:
+ return ret;
+}
+
+static int total_mapping_size(elf_info_t *elf_info)
+{
+ int i;
+ int first_idx = -1;
+ int last_idx = -1;
+
+ for (i = 0; i < elf_info->ehdr.e_phnum; i++)
+ {
+ if (elf_info->phdr[i].p_type == PT_LOAD)
+ {
+ last_idx = i;
+ if (first_idx == -1)
+ first_idx = i;
+ }
+ }
+
+ if (first_idx == -1)
+ return -1;
+
+ elf_info->map_size = elf_info->phdr[last_idx].p_vaddr + elf_info->phdr[last_idx].p_memsz -
+ ELF_PAGESTART(elf_info->phdr[first_idx].p_vaddr);
+
+ return 0;
+}
+
+static rt_ubase_t elf_map(struct rt_lwp *lwp, const Elf_Phdr *elf_phdr, int fd, rt_ubase_t addr, size_t prot, size_t flags, rt_ubase_t map_size)
+{
+ rt_ubase_t map_va = 0;
+ rt_ubase_t va_offset;
+ addr = ELF_PAGESTART(addr);
+ va_offset = elf_phdr->p_offset - ELF_PAGEOFFSET(elf_phdr->p_vaddr);
+ rt_ubase_t size;
+
+ if (map_size != 0)
+ {
+ size = map_size;
+ }
+ else
+ {
+ size = elf_phdr->p_memsz + ELF_PAGEOFFSET(elf_phdr->p_vaddr);
+ if (size == 0)
+ {
+ return addr;
+ }
+ }
+ map_va = (rt_ubase_t)file_mmap(lwp, fd, addr, size, prot, flags, va_offset);
+
+ return map_va;
+}
+
+static int elf_zero_bss(struct rt_lwp *lwp, int fd, const Elf_Phdr *phdr, rt_ubase_t bss_start,
+ rt_ubase_t bss_end)
+{
+ lwp_data_set(lwp, (void *)bss_start, 0, bss_end - bss_start);
+
+ return RT_EOK;
+}
+
+static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ubase_t *elfload_addr,
+ rt_uint32_t map_size, rt_ubase_t *load_base)
+{
+ int ret, i;
+ rt_ubase_t map_va, bss_start, bss_end;
+ Elf_Ehdr *ehdr = &elf_info->ehdr;
+ Elf_Phdr *phdr = elf_info->phdr;
+ const Elf_Phdr *tmp_phdr = phdr;
+ int fd = elf_info->fd;
+ rt_ubase_t load_addr;
+ size_t prot = PROT_READ | PROT_WRITE;
+ size_t flags = MAP_FIXED | MAP_PRIVATE;
+
+ for (i = 0; i < ehdr->e_phnum; ++i, ++tmp_phdr)
+ {
+ if (tmp_phdr->p_type != PT_LOAD)
+ {
+ continue;
+ }
+
+ if (ehdr->e_type == ET_EXEC)
+ {
+ if (elf_check_phdr(tmp_phdr) != RT_EOK)
+ {
+ LOG_E("%s : elf_check_phdr failed", __func__);
+ return -RT_ERROR;
+ }
+ }
+
+ load_addr = tmp_phdr->p_vaddr + *load_base;
+ LOG_D("%s : p_vaddr : 0x%x, load_addr : 0x%x", __func__, tmp_phdr->p_vaddr, load_addr);
+ if ((tmp_phdr->p_vaddr == 0) && (*load_base == 0))
+ {
+ flags &= ~MAP_FIXED;
+ }
+
+ map_va = elf_map(load_info->lwp, tmp_phdr, fd, load_addr, prot, flags, map_size);
+ if (!map_va)
+ {
+ LOG_E("%s : elf_map failed", __func__);
+ return -ENOMEM;
+ }
+
+ map_size = 0;
+
+ elf_user_dump(load_info->lwp, (void *)load_addr, 64);
+ if ((tmp_phdr->p_memsz > tmp_phdr->p_filesz) && (tmp_phdr->p_flags & PF_W))
+ {
+ bss_start = load_addr + tmp_phdr->p_filesz;
+ bss_end = load_addr + tmp_phdr->p_memsz;
+ ret = elf_zero_bss(load_info->lwp, fd, tmp_phdr, bss_start, bss_end);
+ if (ret)
+ {
+ LOG_E("%s : elf_zero_bss error", __func__);
+ return ret;
+ }
+ }
+
+ if (*elfload_addr == 0)
+ {
+ *elfload_addr = map_va + ELF_PAGEOFFSET(tmp_phdr->p_vaddr);
+ LOG_D("%s elf_load_addr : %p, vAddr : %p, load_base : %p, map_va : %p", __func__,
+ *elfload_addr, tmp_phdr->p_vaddr, *load_base, map_va);
+ }
+
+ if ((*load_base == 0) && (ehdr->e_type == ET_DYN))
+ {
+ *load_base = map_va;
+ }
+ }
+
+ return RT_EOK;
+}
+
+static int load_elf_interp(elf_load_info_t *load_info, rt_ubase_t *interp_base)
+{
+ int ret;
+ rt_ubase_t load_base = ELF_INTERP_LOAD_ADDR + elf_random_offset();
+
+ ret = total_mapping_size(&load_info->interp_info);
+ if (ret)
+ {
+ LOG_E("%s : total_mapping_size failed", __func__);
+ return -RT_ERROR;
+ }
+ LOG_D("%s : total_mapping_size 0x%x", __func__, load_info->interp_info.map_size);
+
+ return elf_file_mmap(load_info, &load_info->interp_info, interp_base,
+ load_info->interp_info.map_size, &load_base);
+}
+
+static int elf_aux_fill(elf_load_info_t *load_info)
+{
+ uint8_t *random;
+ struct process_aux *aux = load_info->aux;
+ elf_addr_t *aux_info;
+ uint32_t random_value = rt_tick_get();
+ size_t prot = PROT_READ | PROT_WRITE;
+ size_t flags = MAP_PRIVATE;
+ void *va;
+
+ if (!aux)
+ {
+ LOG_E("%s : aux is null", __func__);
+ return -1;
+ }
+ aux_info = (elf_addr_t *)aux->item;
+ ELF_AUX_ENT(aux_info, AT_PAGESZ, ARCH_PAGE_SIZE);
+
+ va = lwp_mmap2(load_info->lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0);
+ if (!va)
+ {
+ LOG_E("lwp map user failed!");
+ return -RT_ERROR;
+ }
+ random = (uint8_t *)(USER_VADDR_TOP - ARCH_PAGE_SIZE - sizeof(char[16]));
+ lwp_data_put(load_info->lwp, random, &random_value, sizeof(random_value));
+ ELF_AUX_ENT(aux_info, AT_RANDOM, (size_t)random);
+ ELF_AUX_ENT(aux_info, AT_PHDR, (size_t)load_info->load_addr + load_info->exec_info.ehdr.e_phoff);
+ ELF_AUX_ENT(aux_info, AT_PHNUM, (size_t)load_info->exec_info.ehdr.e_phnum);
+ ELF_AUX_ENT(aux_info, AT_PHENT, sizeof(Elf_Phdr));
+ ELF_AUX_ENT(aux_info, AT_BASE, load_info->interp_base);
+ ELF_AUX_ENT(aux_info, AT_FLAGS, 0);
+ ELF_AUX_ENT(aux_info, AT_ENTRY, load_info->exec_info.ehdr.e_entry);
+ ELF_AUX_ENT(aux_info, AT_UID, 0);
+ ELF_AUX_ENT(aux_info, AT_EUID, 0);
+ ELF_AUX_ENT(aux_info, AT_GID, 0);
+ ELF_AUX_ENT(aux_info, AT_EGID, 0);
+ ELF_AUX_ENT(aux_info, AT_HWCAP, 0);
+ ELF_AUX_ENT(aux_info, AT_CLKTCK, 0);
+ ELF_AUX_ENT(aux_info, AT_SECURE, 0);
+
+#ifdef ARCH_MM_MMU
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof(*aux));
+#endif
+
+ return 0;
+}
+
+static int elf_load_segment(elf_load_info_t *load_info)
+{
+ int ret;
+ rt_ubase_t app_load_base = 0;
+ load_info->load_addr = 0;
+ load_info->interp_base = 0;
+ load_info->exec_info.map_size = 0;
+
+ if (load_info->exec_info.ehdr.e_type == ET_DYN)
+ {
+ ret = total_mapping_size(&load_info->exec_info);
+ if (ret)
+ {
+ LOG_E("%s : total_mapping_size failed", __func__);
+ return -RT_ERROR;
+ }
+ LOG_D("%s : map_size : 0x%x", __func__, load_info->exec_info.map_size);
+ app_load_base = ELF_EXEC_LOAD_ADDR + elf_random_offset();
+ }
+
+ ret = elf_file_mmap(load_info, &load_info->exec_info, &load_info->load_addr,
+ load_info->exec_info.map_size, &app_load_base);
+ elf_file_close(load_info->exec_info.fd);
+ if (ret != RT_EOK)
+ {
+ LOG_W("%s : elf_file_close exec failed", __func__);
+ }
+ load_info->exec_info.fd = ELF_INVALID_FD;
+
+ if (load_info->interp_info.fd != ELF_INVALID_FD)
+ {
+ ret = load_elf_interp(load_info, &load_info->interp_base);
+ if (ret)
+ {
+ LOG_E("%s : load_elf_interp failed, ret = %d", __func__, ret);
+ return ret;
+ }
+ elf_file_close(load_info->interp_info.fd);
+ if (ret != RT_EOK)
+ {
+ LOG_W("%s : elf_file_close interp failed, ret = %d", __func__, ret);
+ }
+ load_info->interp_info.fd = ELF_INVALID_FD;
+ load_info->e_entry = load_info->interp_info.ehdr.e_entry + load_info->interp_base;
+ load_info->exec_info.ehdr.e_entry = load_info->exec_info.ehdr.e_entry + app_load_base;
+ }
+ else
+ {
+ load_info->e_entry = load_info->exec_info.ehdr.e_entry;
+ }
+
+ load_info->lwp->text_entry = (void *)load_info->e_entry;
+ LOG_D("%s : lwp->text_entry : %p loadaddr : %p", __func__, load_info->lwp->text_entry, app_load_base);
+
+ elf_user_dump(load_info->lwp, load_info->lwp->text_entry, 64);
+
+ ret = elf_aux_fill(load_info);
+ if (ret)
+ {
+ LOG_E("%s : elf_aux_fill failed", __func__);
+ return ret;
+ }
+
+ return RT_EOK;
+}
+
+static void elf_load_deinit(elf_load_info_t *load_info)
+{
+ if (load_info->exec_info.fd != ELF_INVALID_FD)
+ {
+ elf_file_close(load_info->exec_info.fd);
+ }
+
+ if (load_info->interp_info.fd != ELF_INVALID_FD)
+ {
+ elf_file_close(load_info->interp_info.fd);
+ }
+
+ if (load_info->exec_info.phdr != RT_NULL)
+ {
+ rt_free(load_info->exec_info.phdr);
+ }
+
+ if (load_info->exec_info.filename != RT_NULL)
+ {
+ rt_free(load_info->exec_info.filename);
+ }
+
+ if (load_info->interp_info.phdr != RT_NULL)
+ {
+ rt_free(load_info->interp_info.phdr);
+ }
+
+ if (load_info->interp_info.filename != RT_NULL)
+ {
+ rt_free(load_info->interp_info.filename);
+ }
+}
+
+static int elf_load_app(elf_info_t *exec_info)
+{
+ int ret;
+
+ ret = elf_load_ehdr(exec_info);
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
+
+ ret = elf_load_phdr(exec_info);
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
+
+ return ret;
+}
+
+static int elf_file_load(elf_load_info_t *load_info)
+{
+ int ret;
+
+ ret = elf_load_app(&load_info->exec_info);
+ if (ret != RT_EOK)
+ {
+ goto OUT;
+ }
+
+ ret = elf_load_interp(load_info);
+ if (ret != RT_EOK)
+ {
+ goto OUT;
+ }
+
+ ret = elf_load_segment(load_info);
+ if (ret != RT_EOK)
+ {
+ goto OUT;
+ }
+
+OUT:
+ elf_load_deinit(load_info);
+ return ret;
+}
+
+int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size,
+ struct process_aux *aux)
+{
+ elf_load_info_t load_info = { 0 };
+ int len;
+ int ret;
+
+ if (filename == RT_NULL)
+ {
+ LOG_E("%s : file is NULL", __func__);
+ return -RT_ERROR;
+ }
+
+ len = rt_strlen(filename);
+ if (len < FLF_PATH_MIN || len > ELF_PATH_MAX)
+ {
+ LOG_E("%s : file length (%d) invalid", __func__, len);
+ return -RT_ERROR;
+ }
+
+ load_info.exec_info.filename = rt_malloc(len + 1);
+ if (!load_info.exec_info.filename)
+ {
+ LOG_E("%s : alloc filename failed", __func__, len);
+ return -RT_ERROR;
+ }
+ else
+ {
+ rt_memset(load_info.exec_info.filename, 0, len + 1);
+ rt_strncpy(load_info.exec_info.filename, filename, len);
+ }
+
+ load_info.lwp = lwp;
+ load_info.aux = aux;
+
+ load_info.exec_info.fd = ELF_INVALID_FD;
+ load_info.interp_info.fd = ELF_INVALID_FD;
+ load_info.load_addr = (rt_ubase_t)load_addr;
+
+ /* copy file name to process name */
+ rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
+
+ ret = elf_file_load(&load_info);
+ if (ret != RT_EOK)
+ {
+ LOG_E("%s : elf_file_load error, ret : %d", __func__, ret);
+ return ret;
+ }
+
+ return RT_EOK;
+}
+
+#endif
diff --git a/components/lwp/lwp_ipc.c b/components/lwp/lwp_ipc.c
index 8410bc2cac..8b7bc47098 100644
--- a/components/lwp/lwp_ipc.c
+++ b/components/lwp/lwp_ipc.c
@@ -427,7 +427,6 @@ static int _ipc_msg_fd_new(void *file)
#endif
-
return fd;
}
diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c
index d0a9e2cec0..2262a33f0f 100644
--- a/components/lwp/lwp_pid.c
+++ b/components/lwp/lwp_pid.c
@@ -700,7 +700,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
/* delete from sibling list of its parent */
struct rt_lwp **lwp_node;
- *status = lwp->lwp_ret;
+ lwp_data_put(this_lwp, status, &lwp->lwp_ret, sizeof(*status));
lwp_node = &this_lwp->first_child;
while (*lwp_node != lwp)
{
diff --git a/components/lwp/lwp_shm.c b/components/lwp/lwp_shm.c
index 7ee7e29d8c..b7399c20d5 100644
--- a/components/lwp/lwp_shm.c
+++ b/components/lwp/lwp_shm.c
@@ -156,7 +156,6 @@ static int _lwp_shmget(size_t key, size_t size, int create)
p->mem_obj.on_varea_open = on_shm_varea_open;
p->mem_obj.on_varea_close = on_shm_varea_close;
p->mem_obj.hint_free = NULL;
- p->mem_obj.on_page_offload = NULL;
/* then insert it into the balancing binary tree */
node_key = (struct lwp_avl_struct *)rt_malloc(sizeof(struct lwp_avl_struct) * 2);
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index f638b0bbb1..6bdb786355 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -1305,12 +1305,41 @@ rt_base_t sys_brk(void *addr)
void *sys_mmap2(void *addr, size_t length, int prot,
int flags, int fd, size_t pgoffset)
{
- return lwp_mmap2(addr, length, prot, flags, fd, pgoffset);
+ sysret_t rc = 0;
+ long offset = 0;
+
+ /* aligned for user addr */
+ if ((rt_base_t)addr & ARCH_PAGE_MASK)
+ {
+ if (flags & MAP_FIXED)
+ rc = -EINVAL;
+ else
+ {
+ offset = (char *)addr - (char *)RT_ALIGN_DOWN((rt_base_t)addr, ARCH_PAGE_SIZE);
+ length += offset;
+ addr = (void *)RT_ALIGN_DOWN((rt_base_t)addr, ARCH_PAGE_SIZE);
+ }
+ }
+
+ if (rc == 0)
+ {
+ /* fix parameter passing (both along have same effect) */
+ if (fd == -1 || flags & MAP_ANONYMOUS)
+ {
+ fd = -1;
+ /* MAP_SHARED has no effect and treated as nothing */
+ flags &= ~MAP_SHARED;
+ flags |= MAP_PRIVATE | MAP_ANONYMOUS;
+ }
+ rc = (sysret_t)lwp_mmap2(lwp_self(), addr, length, prot, flags, fd, pgoffset);
+ }
+
+ return (char *)rc + offset;
}
sysret_t sys_munmap(void *addr, size_t length)
{
- return lwp_munmap(addr);
+ return lwp_munmap(lwp_self(), addr, length);
}
void *sys_mremap(void *old_address, size_t old_size,
@@ -1999,17 +2028,6 @@ rt_weak long sys_clone(void *arg[])
return _sys_clone(arg);
}
-int lwp_dup_user(rt_varea_t varea, void *arg);
-
-static int _copy_process(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp)
-{
- int err;
- dest_lwp->lwp_obj->source = src_lwp->aspace;
- err = rt_aspace_traversal(src_lwp->aspace, lwp_dup_user, dest_lwp);
- dest_lwp->lwp_obj->source = NULL;
- return err;
-}
-
static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src)
{
#ifdef ARCH_MM_MMU
@@ -2106,8 +2124,8 @@ sysret_t _sys_fork(void)
self_lwp = lwp_self();
- /* copy process */
- if (_copy_process(lwp, self_lwp) != 0)
+ /* copy address space of process from this proc to forked one */
+ if (lwp_fork_aspace(lwp, self_lwp) != 0)
{
SET_ERRNO(ENOMEM);
goto fail;
@@ -4222,13 +4240,27 @@ sysret_t sys_getaddrinfo(const char *nodename,
SET_ERRNO(EFAULT);
goto exit;
}
-#endif
+
+ k_nodename = (char *)kmem_get(len + 1);
+ if (!k_nodename)
+ {
+ SET_ERRNO(ENOMEM);
+ goto exit;
+ }
+
+ if (lwp_get_from_user(k_nodename, (void *)nodename, len + 1) != len + 1)
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#else
k_nodename = rt_strdup(nodename);
if (!k_nodename)
{
SET_ERRNO(ENOMEM);
goto exit;
}
+#endif
}
if (servname)
{
@@ -4239,13 +4271,27 @@ sysret_t sys_getaddrinfo(const char *nodename,
SET_ERRNO(EFAULT);
goto exit;
}
-#endif
+
+ k_servname = (char *)kmem_get(len + 1);
+ if (!k_servname)
+ {
+ SET_ERRNO(ENOMEM);
+ goto exit;
+ }
+
+ if (lwp_get_from_user(k_servname, (void *)servname, len + 1) < 0)
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#else
k_servname = rt_strdup(servname);
if (!k_servname)
{
SET_ERRNO(ENOMEM);
goto exit;
}
+#endif
}
if (hints)
@@ -4300,15 +4346,28 @@ exit:
{
ret = GET_ERRNO();
}
-
+#ifdef ARCH_MM_MMU
+ if (k_nodename)
+ {
+ kmem_put(k_nodename);
+ }
+#else
if (k_nodename)
{
rt_free(k_nodename);
}
+#endif
+#ifdef ARCH_MM_MMU
+ if (k_servname)
+ {
+ kmem_put(k_servname);
+ }
+#else
if (k_servname)
{
rt_free(k_servname);
}
+#endif
if (k_hints)
{
rt_free(k_hints);
@@ -4324,7 +4383,7 @@ sysret_t sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
{
int ret_val = -1;
int sal_ret = -1 , sal_err = -1;
- struct hostent sal_he;
+ struct hostent sal_he, sal_tmp;
struct hostent *sal_result = NULL;
char *sal_buf = NULL;
char *k_name = NULL;
@@ -4354,22 +4413,35 @@ sysret_t sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
SET_ERRNO(EFAULT);
goto __exit;
}
-#endif
- *result = ret;
- sal_buf = (char *)malloc(HOSTENT_BUFSZ);
- if (sal_buf == NULL)
+ k_name = (char *)kmem_get(len + 1);
+ if (!k_name)
{
SET_ERRNO(ENOMEM);
goto __exit;
}
+ if (lwp_get_from_user(k_name, (void *)name, len + 1) < 0)
+ {
+ SET_ERRNO(EFAULT);
+ goto __exit;
+ }
+#else
k_name = rt_strdup(name);
if (k_name == NULL)
{
SET_ERRNO(ENOMEM);
goto __exit;
}
+#endif
+
+ *result = ret;
+ sal_buf = (char *)malloc(HOSTENT_BUFSZ);
+ if (sal_buf == NULL)
+ {
+ SET_ERRNO(ENOMEM);
+ goto __exit;
+ }
/* get host by name in SAL */
sal_ret = sal_gethostbyname_r(k_name, &sal_he, sal_buf, HOSTENT_BUFSZ, &sal_result, &sal_err);
@@ -4386,6 +4458,28 @@ sysret_t sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
}
cnt = index + 1;
+#ifdef ARCH_MM_MMU
+ /* update user space hostent */
+ lwp_put_to_user(buf, k_name, buflen - (ptr - buf));
+ lwp_memcpy(&sal_tmp, &sal_he, sizeof(sal_he));
+ sal_tmp.h_name = ptr;
+ ptr += rt_strlen(k_name);
+
+ sal_tmp.h_addr_list = (char**)ptr;
+ ptr += cnt * sizeof(char *);
+
+ index = 0;
+ while (sal_he.h_addr_list[index] != NULL)
+ {
+ sal_tmp.h_addr_list[index] = ptr;
+ lwp_memcpy(ptr, sal_he.h_addr_list[index], sal_he.h_length);
+
+ ptr += sal_he.h_length;
+ index++;
+ }
+ sal_tmp.h_addr_list[index] = NULL;
+ lwp_put_to_user(ret, &sal_tmp, sizeof(sal_tmp));
+#else
/* update user space hostent */
ret->h_addrtype = sal_he.h_addrtype;
ret->h_length = sal_he.h_length;
@@ -4407,10 +4501,10 @@ sysret_t sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
index++;
}
ret->h_addr_list[index] = NULL;
+#endif
+ ret_val = 0;
}
- ret_val = 0;
-
__exit:
if (ret_val < 0)
{
@@ -4422,10 +4516,17 @@ __exit:
{
free(sal_buf);
}
+#ifdef ARCH_MM_MMU
+ if (k_name)
+ {
+ kmem_put(k_name);
+ }
+#else
if (k_name)
{
free(k_name);
}
+#endif
return ret_val;
}
diff --git a/components/lwp/lwp_user_mm.c b/components/lwp/lwp_user_mm.c
index 19ba3c5c76..eb8b59dd75 100644
--- a/components/lwp/lwp_user_mm.c
+++ b/components/lwp/lwp_user_mm.c
@@ -11,7 +11,10 @@
* 2021-02-19 lizhirui add riscv64 support for lwp_user_accessable and lwp_get_from_user
* 2021-06-07 lizhirui modify user space bound check
* 2022-12-25 wangxiaoyao adapt to new mm
+ * 2023-08-12 Shell Fix parameter passing of lwp_mmap()/lwp_munmap()
+ * 2023-08-29 Shell Add API accessible()/data_get()/data_set()/data_put()
* 2023-09-13 Shell Add lwp_memcpy and support run-time choice of memcpy base on memory attr
+ * 2023-09-19 Shell add lwp_user_memory_remap_to_kernel
*/
#include <rtthread.h>
@@ -36,28 +39,104 @@
#include "libc_musl.h"
#endif
-#define DBG_TAG "LwP"
-#define DBG_LVL DBG_LOG
+#define DBG_TAG "LwP.mman"
+#define DBG_LVL DBG_INFO
#include <rtdbg.h>
+#include <stdlib.h>
+
+#define STACK_OBJ _null_object
+
static void _init_lwp_objs(struct rt_lwp_objs *lwp_objs, rt_aspace_t aspace);
+static const char *_null_get_name(rt_varea_t varea)
+{
+ return "null";
+}
+
+static void _null_page_fault(struct rt_varea *varea,
+ struct rt_aspace_fault_msg *msg)
+{
+ static void *null_page;
+
+ if (!null_page)
+ {
+ null_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (null_page)
+ memset(null_page, 0, ARCH_PAGE_SIZE);
+ else
+ return;
+ }
+
+ msg->response.status = MM_FAULT_STATUS_OK;
+ msg->response.size = ARCH_PAGE_SIZE;
+ msg->response.vaddr = null_page;
+}
+
+static rt_err_t _null_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
+{
+ return RT_EOK;
+}
+
+static rt_err_t _null_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
+{
+ return RT_EOK;
+}
+
+static rt_err_t _null_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
+{
+ return RT_EOK;
+}
+
+static void _null_page_read(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
+{
+ void *dest = msg->buffer_vaddr;
+ memset(dest, 0, ARCH_PAGE_SIZE);
+
+ msg->response.status = MM_FAULT_STATUS_OK;
+ return ;
+}
+
+static void _null_page_write(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
+{
+ /* write operation is not allowed */
+ msg->response.status = MM_FAULT_STATUS_UNRECOVERABLE;
+ return ;
+}
+
+static struct rt_mem_obj _null_object = {
+ .get_name = _null_get_name,
+ .hint_free = RT_NULL,
+ .on_page_fault = _null_page_fault,
+
+ .page_read = _null_page_read,
+ .page_write = _null_page_write,
+
+ .on_varea_expand = _null_expand,
+ .on_varea_shrink = _null_shrink,
+ .on_varea_split = _null_split,
+};
+
int lwp_user_space_init(struct rt_lwp *lwp, rt_bool_t is_fork)
{
+ void *stk_addr;
int err = -RT_ENOMEM;
+ const size_t flags = MMF_MAP_PRIVATE;
lwp->lwp_obj = rt_malloc(sizeof(struct rt_lwp_objs));
if (lwp->lwp_obj)
{
- _init_lwp_objs(lwp->lwp_obj, lwp->aspace);
-
err = arch_user_space_init(lwp);
- if (!is_fork && err == RT_EOK)
+ if (err == RT_EOK)
{
- void *addr = (void *)USER_STACK_VSTART;
- err = rt_aspace_map(lwp->aspace, &addr,
- USER_STACK_VEND - USER_STACK_VSTART,
- MMU_MAP_U_RWCB, 0, &lwp->lwp_obj->mem_obj, 0);
+ _init_lwp_objs(lwp->lwp_obj, lwp->aspace);
+ if (!is_fork)
+ {
+ stk_addr = (void *)USER_STACK_VSTART;
+ err = rt_aspace_map(lwp->aspace, &stk_addr,
+ USER_STACK_VEND - USER_STACK_VSTART,
+ MMU_MAP_U_RWCB, flags, &STACK_OBJ, 0);
+ }
}
}
@@ -91,7 +170,7 @@ void lwp_unmap_user_space(struct rt_lwp *lwp)
rt_free(lwp->lwp_obj);
}
-static const char *user_get_name(rt_varea_t varea)
+static const char *_user_get_name(rt_varea_t varea)
{
char *name;
if (varea->flag & MMF_TEXT)
@@ -184,12 +263,9 @@ static void _init_lwp_objs(struct rt_lwp_objs *lwp_objs, rt_aspace_t aspace)
* provide identical memory. This is implemented by lwp_objs->source.
*/
lwp_objs->source = NULL;
- lwp_objs->mem_obj.get_name = user_get_name;
- lwp_objs->mem_obj.hint_free = NULL;
+ memcpy(&lwp_objs->mem_obj, &rt_mm_dummy_mapper, sizeof(struct rt_mem_obj));
+ lwp_objs->mem_obj.get_name = _user_get_name;
lwp_objs->mem_obj.on_page_fault = _user_do_page_fault;
- lwp_objs->mem_obj.on_page_offload = rt_mm_dummy_mapper.on_page_offload;
- lwp_objs->mem_obj.on_varea_open = rt_mm_dummy_mapper.on_varea_open;
- lwp_objs->mem_obj.on_varea_close = rt_mm_dummy_mapper.on_varea_close;
}
}
@@ -198,14 +274,14 @@ static void *_lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size,
{
void *va = map_va;
int ret = 0;
- size_t flags = MMF_PREFETCH;
+ rt_size_t flags = MMF_PREFETCH;
+
if (text)
flags |= MMF_TEXT;
+ if (va != RT_NULL)
+ flags |= MMF_MAP_FIXED;
- rt_mem_obj_t mem_obj = &lwp->lwp_obj->mem_obj;
-
- ret = rt_aspace_map(lwp->aspace, &va, map_size, MMU_MAP_U_RWCB, flags,
- mem_obj, 0);
+ ret = rt_aspace_map_private(lwp->aspace, &va, map_size, MMU_MAP_U_RWCB, flags);
if (ret != RT_EOK)
{
va = RT_NULL;
@@ -223,98 +299,17 @@ int lwp_unmap_user(struct rt_lwp *lwp, void *va)
return err;
}
-static void _dup_varea(rt_varea_t varea, struct rt_lwp *src_lwp,
- rt_aspace_t dst)
-{
- char *vaddr = varea->start;
- char *vend = vaddr + varea->size;
- if (vaddr < (char *)USER_STACK_VSTART || vaddr >= (char *)USER_STACK_VEND)
- {
- while (vaddr != vend)
- {
- void *paddr;
- paddr = lwp_v2p(src_lwp, vaddr);
- if (paddr != ARCH_MAP_FAILED)
- {
- rt_aspace_load_page(dst, vaddr, 1);
- }
- vaddr += ARCH_PAGE_SIZE;
- }
- }
- else
- {
- while (vaddr != vend)
- {
- vend -= ARCH_PAGE_SIZE;
- void *paddr;
- paddr = lwp_v2p(src_lwp, vend);
- if (paddr != ARCH_MAP_FAILED)
- {
- rt_aspace_load_page(dst, vend, 1);
- }
- else
- {
- break;
- }
- }
- }
-}
-
-int lwp_dup_user(rt_varea_t varea, void *arg)
+/** fork the src_lwp->aspace in current */
+int lwp_fork_aspace(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp)
{
int err;
- struct rt_lwp *self_lwp = lwp_self();
- struct rt_lwp *new_lwp = (struct rt_lwp *)arg;
-
- void *pa = RT_NULL;
- void *va = RT_NULL;
- rt_mem_obj_t mem_obj = varea->mem_obj;
-
- if (!mem_obj)
- {
- /* duplicate a physical mapping */
- pa = lwp_v2p(self_lwp, (void *)varea->start);
- RT_ASSERT(pa != ARCH_MAP_FAILED);
- struct rt_mm_va_hint hint = {.flags = MMF_MAP_FIXED,
- .limit_range_size = new_lwp->aspace->size,
- .limit_start = new_lwp->aspace->start,
- .prefer = varea->start,
- .map_size = varea->size};
- err = rt_aspace_map_phy(new_lwp->aspace, &hint, varea->attr,
- MM_PA_TO_OFF(pa), &va);
- if (err != RT_EOK)
- {
- LOG_W("%s: aspace map failed at %p with size %p", __func__,
- varea->start, varea->size);
- }
- }
- else
+ err = rt_aspace_fork(&src_lwp->aspace, &dest_lwp->aspace);
+ if (!err)
{
- /* duplicate a mem_obj backing mapping */
- va = varea->start;
- err = rt_aspace_map(new_lwp->aspace, &va, varea->size, varea->attr,
- varea->flag, &new_lwp->lwp_obj->mem_obj,
- varea->offset);
- if (err != RT_EOK)
- {
- LOG_W("%s: aspace map failed at %p with size %p", __func__,
- varea->start, varea->size);
- }
- else
- {
- /* loading page frames for !MMF_PREFETCH varea */
- if (!(varea->flag & MMF_PREFETCH))
- {
- _dup_varea(varea, self_lwp, new_lwp->aspace);
- }
- }
- }
-
- if (va != (void *)varea->start)
- {
- return -1;
+ /* do a explicit aspace switch if the page table is changed */
+ lwp_aspace_switch(rt_thread_self());
}
- return 0;
+ return err;
}
int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va)
@@ -364,6 +359,10 @@ static inline size_t _flags_to_attr(size_t flags)
static inline mm_flag_t _flags_to_aspace_flag(size_t flags)
{
mm_flag_t mm_flag = 0;
+ if (flags & LWP_MAP_FLAG_MAP_FIXED)
+ mm_flag |= MMF_MAP_FIXED;
+ if (flags & LWP_MAP_FLAG_PREFETCH)
+ mm_flag |= MMF_PREFETCH;
return mm_flag;
}
@@ -372,26 +371,17 @@ static rt_varea_t _lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t m
{
void *va = map_va;
int ret = 0;
- rt_mem_obj_t mem_obj = &lwp->lwp_obj->mem_obj;
- rt_varea_t varea;
+ rt_varea_t varea = RT_NULL;
mm_flag_t mm_flags;
size_t attr;
- varea = rt_malloc(sizeof(*varea));
- if (varea)
- {
- attr = _flags_to_attr(flags);
- mm_flags = _flags_to_aspace_flag(flags);
- ret = rt_aspace_map_static(lwp->aspace, varea, &va, map_size,
- attr, mm_flags, mem_obj, 0);
- /* let aspace handle the free of varea */
- varea->flag &= ~MMF_STATIC_ALLOC;
- /* don't apply auto fetch on this */
- varea->data = (void *)NO_AUTO_FETCH;
- }
- else
+ attr = _flags_to_attr(flags);
+ mm_flags = _flags_to_aspace_flag(flags);
+ ret = rt_aspace_map_private(lwp->aspace, &va, map_size,
+ attr, mm_flags);
+ if (ret == RT_EOK)
{
- ret = -RT_ENOMEM;
+ varea = rt_aspace_query(lwp->aspace, va);
}
if (ret != RT_EOK)
@@ -405,7 +395,6 @@ static rt_varea_t _lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t m
static rt_varea_t _map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags)
{
- rt_varea_t varea = RT_NULL;
size_t offset = 0;
if (!map_size)
@@ -417,9 +406,7 @@ static rt_varea_t _map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t m
map_size &= ~ARCH_PAGE_MASK;
map_va = (void *)((size_t)map_va & ~ARCH_PAGE_MASK);
- varea = _lwp_map_user_varea(lwp, map_va, map_size, flags);
-
- return varea;
+ return _lwp_map_user_varea(lwp, map_va, map_size, flags);
}
rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags)
@@ -456,11 +443,14 @@ void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa,
map_size &= ~ARCH_PAGE_MASK;
map_pa = (void *)((size_t)map_pa & ~ARCH_PAGE_MASK);
- struct rt_mm_va_hint hint = {.flags = MMF_MAP_FIXED,
+ struct rt_mm_va_hint hint = {.flags = 0,
.limit_range_size = lwp->aspace->size,
.limit_start = lwp->aspace->start,
.prefer = map_va,
.map_size = map_size};
+ if (map_va != RT_NULL)
+ hint.flags |= MMF_MAP_FIXED;
+
rt_size_t attr = cached ? MMU_MAP_U_RWCB : MMU_MAP_U_RW;
err =
@@ -481,56 +471,160 @@ void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa,
rt_base_t lwp_brk(void *addr)
{
rt_base_t ret = -1;
+ rt_varea_t varea = RT_NULL;
struct rt_lwp *lwp = RT_NULL;
+ size_t size = 0;
- rt_mm_lock();
- lwp = rt_thread_self()->lwp;
+ lwp = lwp_self();
- if ((size_t)addr <= lwp->end_heap)
+ if ((size_t)addr == RT_NULL)
{
- ret = (rt_base_t)lwp->end_heap;
+ addr = (char *)lwp->end_heap + 1;
}
- else
+
+ if ((size_t)addr <= lwp->end_heap && (size_t)addr > USER_HEAP_VADDR)
+ {
+ ret = (size_t)addr;
+ }
+ else if ((size_t)addr <= USER_HEAP_VEND)
+ {
+ size = RT_ALIGN((size_t)addr - lwp->end_heap, ARCH_PAGE_SIZE);
+ varea = lwp_map_user_varea_ext(lwp, (void *)lwp->end_heap, size, LWP_MAP_FLAG_PREFETCH);
+ if (varea)
+ {
+ lwp->end_heap = (long)(varea->start + varea->size);
+ ret = lwp->end_heap;
+ }
+ }
+
+ return ret;
+}
+
+rt_inline rt_mem_obj_t _get_mmap_obj(struct rt_lwp *lwp)
+{
+ return &_null_object;
+}
+
+rt_inline rt_bool_t _memory_threshold_ok(void)
+{
+ #define GUARDIAN_BITS (10)
+ size_t total, free;
+
+ rt_page_get_info(&total, &free);
+ if (free * (0x1000) < 0x100000)
+ {
+ LOG_I("%s: low of system memory", __func__);
+ return RT_FALSE;
+ }
+
+ return RT_TRUE;
+}
+
+rt_inline long _uflag_to_kernel(long flag)
+{
+ flag &= ~MMF_MAP_FIXED;
+ flag &= ~MMF_MAP_PRIVATE;
+ flag &= ~MMF_MAP_PRIVATE_DONT_SYNC;
+ return flag;
+}
+
+rt_inline long _uattr_to_kernel(long attr)
+{
+ /* Warning: be careful with the case if user attribution is unwritable */
+ return attr;
+}
+
+static void _prefetch_mmap(rt_aspace_t aspace, void *addr, long size)
+{
+ struct rt_aspace_fault_msg msg;
+
+ msg.fault_op = MM_FAULT_OP_WRITE;
+ msg.fault_type = MM_FAULT_TYPE_PAGE_FAULT;
+
+ for (char *base = addr; size > 0; base += ARCH_PAGE_SIZE, size -= ARCH_PAGE_SIZE)
{
- size_t size = 0;
- void *va = RT_NULL;
+ msg.fault_vaddr = base;
+ msg.off = (long)base >> MM_PAGE_SHIFT;
+ rt_aspace_fault_try_fix(aspace, &msg);
+ }
+ return ;
+}
+
+void *lwp_user_memory_remap_to_kernel(rt_lwp_t lwp, void *uaddr, size_t length)
+{
+ long kattr;
+ long kflag;
+ long offset_in_mobj;
+ long offset_in_page;
+ rt_err_t error;
+ rt_varea_t uarea;
+ rt_mem_obj_t mobj;
+ void *kaddr = 0;
- if ((size_t)addr <= USER_HEAP_VEND)
+ uarea = rt_aspace_query(lwp->aspace, uaddr);
+ if (uarea)
+ {
+ /* setup the identical mapping, and align up for address & length */
+ kattr = _uattr_to_kernel(uarea->attr);
+ kflag = _uflag_to_kernel(uarea->flag);
+ offset_in_mobj = uarea->offset + ((long)uaddr - (long)uarea->start) / ARCH_PAGE_SIZE;
+ mobj = uarea->mem_obj;
+ offset_in_page = (long)uaddr & ARCH_PAGE_MASK;
+ length = RT_ALIGN(length + offset_in_page, ARCH_PAGE_SIZE);
+ error = rt_aspace_map(&rt_kernel_space, &kaddr, length, kattr, kflag, mobj, offset_in_mobj);
+ if (error)
{
- size = (((size_t)addr - lwp->end_heap) + ARCH_PAGE_SIZE - 1) &
- ~ARCH_PAGE_MASK;
- va = lwp_map_user(lwp, (void *)lwp->end_heap, size, 0);
+ LOG_I("%s(length=0x%lx,attr=0x%lx,flags=0x%lx): do map failed", __func__, length, kattr, kflag);
+ kaddr = 0;
}
- if (va)
+ else
{
- lwp->end_heap += size;
- ret = lwp->end_heap;
+ /* TODO: {make a memory lock?} */
+ LOG_D("%s(length=0x%lx,attr=0x%lx,flags=0x%lx,offset=0x%lx) => %p", __func__, length, kattr, kflag, offset_in_mobj, kaddr);
+ _prefetch_mmap(&rt_kernel_space, kaddr, length);
+ kaddr += offset_in_page;
}
}
- rt_mm_unlock();
- return ret;
+
+ return kaddr;
}
-void *lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd,
- off_t pgoffset)
+void *lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot,
+ int flags, int fd, off_t pgoffset)
{
- void *ret = (void *)-1;
+ rt_err_t rc;
+ rt_size_t k_attr;
+ rt_size_t k_flags;
+ rt_size_t k_offset;
+ rt_aspace_t uspace;
+ rt_mem_obj_t mem_obj;
+ void *ret = 0;
+ LOG_D("%s(addr=0x%lx,length=%ld,fd=%d)", __func__, addr, length, fd);
if (fd == -1)
{
+ /**
+ * todo: add threshold
+ */
+ if (!_memory_threshold_ok())
+ return (void *)-ENOMEM;
- ret = lwp_map_user(lwp_self(), addr, length, 0);
+ k_offset = MM_PA_TO_OFF(addr);
+ k_flags = lwp_user_mm_flag_to_kernel(flags) | MMF_MAP_PRIVATE;
+ k_attr = lwp_user_mm_attr_to_kernel(prot);
- if (ret)
+ uspace = lwp->aspace;
+ length = RT_ALIGN(length, ARCH_PAGE_SIZE);
+ mem_obj = _get_mmap_obj(lwp);
+
+ rc = rt_aspace_map(uspace, &addr, length, k_attr, k_flags, mem_obj, k_offset);
+ if (rc == RT_EOK)
{
- if ((flags & MAP_ANONYMOUS) != 0)
- {
- rt_memset(ret, 0, length);
- }
+ ret = addr;
}
else
{
- ret = (void *)-1;
+ ret = (void *)lwp_errno_to_posix(rc);
}
}
else
@@ -538,7 +632,7 @@ void *lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd,
struct dfs_file *d;
d = fd_get(fd);
- if (d && d->vnode->type == FT_DEVICE)
+ if (d)
{
struct dfs_mmap2_args mmap2;
@@ -548,26 +642,32 @@ void *lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd,
mmap2.flags = flags;
mmap2.pgoffset = pgoffset;
mmap2.ret = (void *)-1;
+ mmap2.lwp = lwp;
- if (dfs_file_mmap2(d, &mmap2) == 0)
+ rc = dfs_file_mmap2(d, &mmap2);
+ if (rc == RT_EOK)
{
ret = mmap2.ret;
}
+ else
+ {
+ ret = (void *)lwp_errno_to_posix(rc);
+ }
}
}
+ if ((long)ret <= 0)
+ LOG_D("%s() => %ld", __func__, ret);
return ret;
}
-int lwp_munmap(void *addr)
+int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length)
{
- int ret = 0;
-
- rt_mm_lock();
- ret = lwp_unmap_user(lwp_self(), addr);
- rt_mm_unlock();
+ int ret;
- return ret;
+ RT_ASSERT(lwp);
+ ret = rt_aspace_unmap_range(lwp->aspace, addr, length);
+ return lwp_errno_to_posix(ret);
}
size_t lwp_get_from_user(void *dst, void *src, size_t size)
@@ -725,20 +825,10 @@ int lwp_user_accessible_ext(struct rt_lwp *lwp, void *addr, size_t size)
len = size;
}
tmp_addr = lwp_v2p(lwp, addr_start);
- if (tmp_addr == ARCH_MAP_FAILED)
+ if (tmp_addr == ARCH_MAP_FAILED &&
+ !rt_aspace_query(lwp->aspace, addr_start))
{
- if ((rt_ubase_t)addr_start >= USER_STACK_VSTART && (rt_ubase_t)addr_start < USER_STACK_VEND)
- {
- struct rt_aspace_fault_msg msg = {
- .fault_op = MM_FAULT_OP_WRITE,
- .fault_type = MM_FAULT_TYPE_PAGE_FAULT,
- .fault_vaddr = addr_start,
- };
- if (!rt_aspace_fault_try_fix(lwp->aspace, &msg))
- return RT_FALSE;
- }
- else
- return RT_FALSE;
+ return RT_FALSE;
}
addr_start = (void *)((char *)addr_start + len);
size -= len;
@@ -752,135 +842,234 @@ int lwp_user_accessable(void *addr, size_t size)
return lwp_user_accessible_ext(lwp_self(), addr, size);
}
-/* src is in mmu_info space, dst is in current thread space */
+#define ALIGNED(addr) (!((rt_size_t)(addr) & ARCH_PAGE_MASK))
+
+/* src is in lwp address space, dst is in current thread space */
size_t lwp_data_get(struct rt_lwp *lwp, void *dst, void *src, size_t size)
{
size_t copy_len = 0;
- void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
- void *tmp_dst = RT_NULL, *tmp_src = RT_NULL;
+ char *temp_page = 0;
+ char *dst_iter, *dst_next_page;
+ char *src_copy_end, *src_iter, *src_iter_aligned;
if (!size || !dst)
{
return 0;
}
- tmp_dst = dst;
- addr_start = src;
- addr_end = (void *)((char *)src + size);
- next_page =
- (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+ dst_iter = dst;
+ src_iter = src;
+ src_copy_end = src + size;
+ dst_next_page =
+ (char *)(((size_t)src_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
do
{
- size_t len = (char *)next_page - (char *)addr_start;
+ size_t bytes_to_copy = (char *)dst_next_page - (char *)src_iter;
+ if (bytes_to_copy > size)
+ {
+ bytes_to_copy = size;
+ }
- if (size < len)
+ if (ALIGNED(src_iter) && bytes_to_copy == ARCH_PAGE_SIZE)
{
- len = size;
+ /* get page to kernel buffer */
+ if (rt_aspace_page_get(lwp->aspace, src_iter, dst_iter))
+ break;
}
- tmp_src = lwp_v2p(lwp, addr_start);
- if (tmp_src == ARCH_MAP_FAILED)
+ else
{
- break;
+ if (!temp_page)
+ temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (!temp_page)
+ break;
+
+ src_iter_aligned = (char *)((long)src_iter & ~ARCH_PAGE_MASK);
+ if (rt_aspace_page_get(lwp->aspace, src_iter_aligned, temp_page))
+ break;
+ memcpy(dst_iter, temp_page + (src_iter - src_iter_aligned), bytes_to_copy);
}
- tmp_src = (void *)((char *)tmp_src - PV_OFFSET);
- rt_memcpy(tmp_dst, tmp_src, len);
- tmp_dst = (void *)((char *)tmp_dst + len);
- addr_start = (void *)((char *)addr_start + len);
- size -= len;
- next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
- copy_len += len;
- } while (addr_start < addr_end);
+
+ dst_iter = dst_iter + bytes_to_copy;
+ src_iter = src_iter + bytes_to_copy;
+ size -= bytes_to_copy;
+ dst_next_page = (void *)((char *)dst_next_page + ARCH_PAGE_SIZE);
+ copy_len += bytes_to_copy;
+ } while (src_iter < src_copy_end);
+
+ if (temp_page)
+ rt_pages_free(temp_page, 0);
return copy_len;
}
-/* dst is in kernel space, src is in current thread space */
+/* dst is in lwp address space, src is in current thread space */
size_t lwp_data_put(struct rt_lwp *lwp, void *dst, void *src, size_t size)
{
size_t copy_len = 0;
- void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
- void *tmp_dst = RT_NULL, *tmp_src = RT_NULL;
+ char *temp_page = 0;
+ char *dst_iter, *dst_iter_aligned, *dst_next_page;
+ char *src_put_end, *src_iter;
if (!size || !dst)
{
return 0;
}
- tmp_src = src;
- addr_start = dst;
- addr_end = (void *)((char *)dst + size);
- next_page =
- (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+
+ src_iter = src;
+ dst_iter = dst;
+ src_put_end = dst + size;
+ dst_next_page =
+ (char *)(((size_t)dst_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
do
{
- size_t len = (char *)next_page - (char *)addr_start;
+ size_t bytes_to_put = (char *)dst_next_page - (char *)dst_iter;
+ if (bytes_to_put > size)
+ {
+ bytes_to_put = size;
+ }
- if (size < len)
+ if (ALIGNED(dst_iter) && bytes_to_put == ARCH_PAGE_SIZE)
{
- len = size;
+ /* write to page in kernel */
+ if (rt_aspace_page_put(lwp->aspace, dst_iter, src_iter))
+ break;
}
- tmp_dst = lwp_v2p(lwp, addr_start);
- if (tmp_dst == ARCH_MAP_FAILED)
+ else
{
- break;
+ if (!temp_page)
+ temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (!temp_page)
+ break;
+
+ dst_iter_aligned = (void *)((long)dst_iter & ~ARCH_PAGE_MASK);
+ if (rt_aspace_page_get(lwp->aspace, dst_iter_aligned, temp_page))
+ break;
+ memcpy(temp_page + (dst_iter - dst_iter_aligned), src_iter, bytes_to_put);
+ if (rt_aspace_page_put(lwp->aspace, dst_iter_aligned, temp_page))
+ break;
}
- tmp_dst = (void *)((char *)tmp_dst - PV_OFFSET);
- rt_memcpy(tmp_dst, tmp_src, len);
- tmp_src = (void *)((char *)tmp_src + len);
- addr_start = (void *)((char *)addr_start + len);
- size -= len;
- next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
- copy_len += len;
- } while (addr_start < addr_end);
+
+ src_iter = src_iter + bytes_to_put;
+ dst_iter = dst_iter + bytes_to_put;
+ size -= bytes_to_put;
+ dst_next_page = dst_next_page + ARCH_PAGE_SIZE;
+ copy_len += bytes_to_put;
+ } while (dst_iter < src_put_end);
+
+ if (temp_page)
+ rt_pages_free(temp_page, 0);
+ return copy_len;
+}
+
+/* Set N bytes of S to C */
+size_t lwp_data_set(struct rt_lwp *lwp, void *dst, int byte, size_t size)
+{
+ size_t copy_len = 0;
+ char *temp_page = 0;
+ char *dst_iter, *dst_iter_aligned, *dst_next_page;
+ char *dst_put_end;
+
+ if (!size || !dst)
+ {
+ return 0;
+ }
+
+ dst_iter = dst;
+ dst_put_end = dst + size;
+ dst_next_page =
+ (char *)(((size_t)dst_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+ temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (temp_page)
+ {
+ do
+ {
+ size_t bytes_to_put = (char *)dst_next_page - (char *)dst_iter;
+ if (bytes_to_put > size)
+ {
+ bytes_to_put = size;
+ }
+
+ dst_iter_aligned = (void *)((long)dst_iter & ~ARCH_PAGE_MASK);
+ if (!ALIGNED(dst_iter) || bytes_to_put != ARCH_PAGE_SIZE)
+ if (rt_aspace_page_get(lwp->aspace, dst_iter_aligned, temp_page))
+ break;
+
+ memset(temp_page + (dst_iter - dst_iter_aligned), byte, bytes_to_put);
+ if (rt_aspace_page_put(lwp->aspace, dst_iter_aligned, temp_page))
+ break;
+
+ dst_iter = dst_iter + bytes_to_put;
+ size -= bytes_to_put;
+ dst_next_page = dst_next_page + ARCH_PAGE_SIZE;
+ copy_len += bytes_to_put;
+ } while (dst_iter < dst_put_end);
+
+ rt_pages_free(temp_page, 0);
+ }
+
return copy_len;
}
size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s)
{
int len = 0;
- char *new_buf = RT_NULL;
+ char *temp_buf = RT_NULL;
void *addr_start = RT_NULL;
- int size = 0;
- int err = 0;
+ int get_bytes = 0;
+ int index = 0;
if (s == RT_NULL)
return 0;
- addr_start = (void *)s;
- new_buf = rt_malloc(ARCH_PAGE_SIZE);
-
if (lwp == RT_NULL)
{
LOG_W("%s: lwp is NULL", __func__);
return -1;
}
- err = lwp_data_get(lwp, new_buf, addr_start, ARCH_PAGE_SIZE);
- if (err == 0)
+ addr_start = (void *)s;
+ temp_buf = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (!temp_buf)
+ {
+ LOG_W("%s: No memory", __func__);
+ return -1;
+ }
+
+ get_bytes = lwp_data_get(lwp, temp_buf, addr_start, ARCH_PAGE_SIZE);
+ if (get_bytes == 0)
{
- rt_free(new_buf);
+ LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000) failed", lwp, temp_buf, addr_start);
+ rt_pages_free(temp_buf, 0);
return -1;
}
- while (new_buf[size] != '\0')
+ while (temp_buf[index] != '\0')
{
- len ++;
- if (size == (ARCH_PAGE_SIZE -1))
+ len++;
+ index++;
+ if (index == get_bytes)
{
- err = lwp_data_get(lwp, new_buf, addr_start + len, ARCH_PAGE_SIZE);
- if (err == 0)
+ if (get_bytes == ARCH_PAGE_SIZE)
+ {
+ get_bytes = lwp_data_get(lwp, temp_buf, addr_start + len, ARCH_PAGE_SIZE);
+ if (get_bytes == 0)
+ {
+ LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000): user data unaccessible",
+ lwp, temp_buf, addr_start);
+ len = -1;
+ break;
+ }
+ index = 0;
+ }
+ else
{
- rt_free(new_buf);
- return -1;
+ LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000): user data unaccessible",
+ lwp, temp_buf, addr_start);
+ len = -1;
+ break;
}
-
- size = 0;
- }
- else
- {
- size ++;
}
}
- rt_free(new_buf);
-
+ rt_pages_free(temp_buf, 0);
return len;
}
@@ -894,4 +1083,72 @@ size_t lwp_user_strlen(const char *s)
return lwp_user_strlen_ext(lwp, s);
}
+
+char** lwp_get_command_line_args(struct rt_lwp *lwp)
+{
+ size_t argc = 0;
+ char** argv = NULL;
+ int ret;
+ size_t i;
+ size_t len;
+
+ if (lwp)
+ {
+ ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
+ if (ret == 0)
+ {
+ return RT_NULL;
+ }
+ argv = (char**)rt_malloc((argc + 1) * sizeof(char*));
+
+ if (argv)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ char *argvp = NULL;
+ ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
+ if (ret == 0)
+ {
+ lwp_free_command_line_args(argv);
+ return RT_NULL;
+ }
+ len = lwp_user_strlen_ext(lwp, argvp);
+
+ if (len > 0)
+ {
+ argv[i] = (char*)rt_malloc(len + 1);
+ ret = lwp_data_get(lwp, argv[i], argvp, len);
+ if (ret == 0)
+ {
+ lwp_free_command_line_args(argv);
+ return RT_NULL;
+ }
+ argv[i][len] = '\0';
+ }
+ else
+ {
+ argv[i] = NULL;
+ }
+ }
+ argv[argc] = NULL;
+ }
+ }
+
+ return argv;
+}
+
+void lwp_free_command_line_args(char** argv)
+{
+ size_t i;
+
+ if (argv)
+ {
+ for (i = 0; argv[i]; i++)
+ {
+ rt_free(argv[i]);
+ }
+ rt_free(argv);
+ }
+}
+
#endif
diff --git a/components/lwp/lwp_user_mm.h b/components/lwp/lwp_user_mm.h
index ca8845dee0..a63b19f3cd 100644
--- a/components/lwp/lwp_user_mm.h
+++ b/components/lwp/lwp_user_mm.h
@@ -7,6 +7,7 @@
* Date Author Notes
* 2019-10-28 Jesven first version
* 2021-02-12 lizhirui add 64-bit support for lwp_brk
+ * 2023-09-19 Shell add lwp_user_memory_remap_to_kernel
*/
#ifndef __LWP_USER_MM_H__
#define __LWP_USER_MM_H__
@@ -27,6 +28,8 @@ extern "C" {
#define LWP_MAP_FLAG_NONE 0x0000
#define LWP_MAP_FLAG_NOCACHE 0x0001
+#define LWP_MAP_FLAG_MAP_FIXED 0x00010000ul
+#define LWP_MAP_FLAG_PREFETCH 0x00020000ul
/**
* @brief Map files or devices into memory
@@ -41,7 +44,7 @@ extern "C" {
* @param pgoffset offset to fd in 4096 bytes unit
* @return void* the address is successful, otherwise return MAP_FAILED
*/
-void* lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
+void* lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
/**
* @brief Unmap memory region in user space
@@ -51,7 +54,7 @@ void* lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pg
* @param length length in bytes of unmapping
* @return int errno
*/
-int lwp_munmap(void *addr);
+int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length);
/**
* @brief Test if address from user is accessible address by user
@@ -145,8 +148,8 @@ void lwp_unmap_user_space(struct rt_lwp *lwp);
int lwp_unmap_user(struct rt_lwp *lwp, void *va);
void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, rt_bool_t text);
-size_t lwp_user_strlen(const char *s);
-size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s);
+void lwp_free_command_line_args(char** argv);
+char** lwp_get_command_line_args(struct rt_lwp *lwp);
rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
@@ -158,6 +161,11 @@ int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va);
rt_base_t lwp_brk(void *addr);
+size_t lwp_user_strlen(const char *s);
+size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s);
+
+int lwp_fork_aspace(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp);
+
void lwp_data_cache_flush(struct rt_lwp *lwp, void *vaddr, size_t size);
static inline void *_lwp_v2p(struct rt_lwp *lwp, void *vaddr)
@@ -173,6 +181,49 @@ static inline void *lwp_v2p(struct rt_lwp *lwp, void *vaddr)
return paddr;
}
+/**
+ * @brief Remapping user space memory region to kernel
+ *
+ * @warning the remapped region in kernel should be unmapped after usage
+ *
+ * @param lwp target process
+ * @param uaddr user space address where the data writes to
+ * @param length the bytes to redirect
+ * @return void * the redirection address in kernel space
+ */
+void *lwp_user_memory_remap_to_kernel(rt_lwp_t lwp, void *uaddr, size_t length);
+
+rt_inline rt_size_t lwp_user_mm_flag_to_kernel(int flags)
+{
+ rt_size_t k_flags = 0;
+ if (flags & MAP_FIXED)
+ k_flags |= MMF_MAP_FIXED;
+ if (flags & (MAP_PRIVATE | MAP_ANON | MAP_ANONYMOUS))
+ k_flags |= MMF_MAP_PRIVATE;
+ if (flags & MAP_SHARED)
+ k_flags |= MMF_MAP_SHARED;
+ return k_flags;
+}
+
+rt_inline rt_size_t lwp_user_mm_attr_to_kernel(int prot)
+{
+ rt_size_t k_attr = 0;
+
+#ifdef IMPL_MPROTECT
+ if ((prot & PROT_EXEC) || (prot & PROT_WRITE) ||
+ ((prot & PROT_READ) && (prot & PROT_WRITE)))
+ k_attr = MMU_MAP_U_RWCB;
+ else if (prot == PROT_NONE)
+ k_attr = MMU_MAP_K_RWCB;
+ else
+ k_attr = MMU_MAP_U_ROCB;
+#else
+ k_attr = MMU_MAP_U_RWCB;
+#endif /* IMPL_MPROTECT */
+
+ return k_attr;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/components/lwp/syscall_generic.h b/components/lwp/syscall_generic.h
index 04b93e5fb8..a589b6fcdd 100644
--- a/components/lwp/syscall_generic.h
+++ b/components/lwp/syscall_generic.h
@@ -13,6 +13,9 @@
#include <rtthread.h>
+#include <errno.h>
+#include <stdlib.h>
+
typedef long sysret_t;
struct rt_syscall_def
@@ -40,4 +43,36 @@ struct rt_syscall_def
#define _SYS_WRAP(func) ({int _ret = func; _ret < 0 ? GET_ERRNO() : _ret;})
+rt_inline sysret_t lwp_errno_to_posix(rt_err_t error)
+{
+ sysret_t posix_rc;
+
+ switch (labs(error))
+ {
+ case RT_EOK:
+ posix_rc = 0;
+ break;
+ case RT_ETIMEOUT:
+ posix_rc = -ETIMEDOUT;
+ break;
+ case RT_EINVAL:
+ posix_rc = -EINVAL;
+ break;
+ case RT_ENOENT:
+ posix_rc = -ENOENT;
+ break;
+ case RT_ENOSPC:
+ posix_rc = -ENOSPC;
+ break;
+ case RT_EPERM:
+ posix_rc = -EPERM;
+ break;
+ default:
+ posix_rc = -1;
+ break;
+ }
+
+ return posix_rc;
+}
+
#endif /* __SYSCALL_DATA_H__ */