diff options
Diffstat (limited to 'components/lwp')
| -rw-r--r-- | components/lwp/Kconfig | 16 | ||||
| -rw-r--r-- | components/lwp/arch/aarch64/cortex-a/lwp_arch.c | 24 | ||||
| -rw-r--r-- | components/lwp/arch/aarch64/cortex-a/lwp_arch.h | 7 | ||||
| -rw-r--r-- | components/lwp/arch/aarch64/cortex-a/lwp_gcc.S | 4 | ||||
| -rw-r--r-- | components/lwp/arch/arm/cortex-a/lwp_arch.c | 9 | ||||
| -rw-r--r-- | components/lwp/arch/arm/cortex-a/lwp_arch.h | 2 | ||||
| -rw-r--r-- | components/lwp/arch/arm/cortex-a/lwp_gcc.S | 7 | ||||
| -rw-r--r-- | components/lwp/arch/risc-v/rv64/lwp_arch.c | 8 | ||||
| -rw-r--r-- | components/lwp/lwp.c | 42 | ||||
| -rw-r--r-- | components/lwp/lwp.h | 4 | ||||
| -rw-r--r-- | components/lwp/lwp_elf.c | 811 | ||||
| -rw-r--r-- | components/lwp/lwp_ipc.c | 1 | ||||
| -rw-r--r-- | components/lwp/lwp_pid.c | 2 | ||||
| -rw-r--r-- | components/lwp/lwp_shm.c | 1 | ||||
| -rw-r--r-- | components/lwp/lwp_syscall.c | 151 | ||||
| -rw-r--r-- | components/lwp/lwp_user_mm.c | 747 | ||||
| -rw-r--r-- | components/lwp/lwp_user_mm.h | 59 | ||||
| -rw-r--r-- | components/lwp/syscall_generic.h | 35 |
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__ */ |
