From 74926d2db1d9f3228acdfca03013a8ba0ac1d8c0 Mon Sep 17 00:00:00 2001 From: Minep Date: Sat, 31 Dec 2022 01:26:10 +0000 Subject: [PATCH] feat: basic elf32 loader (only LOAD segment is supported) feat: execve(2) feat: MAP_FIXED, MAP_FIXED_NOREPLACE refactor: mem_map: improved arguments passing refactor: mm_region: custom page init policy and managed region_release() refactor: use mem_map to create user stack chore: update READMEs --- README.md | 7 +- docs/README_en.md | 7 +- lunaix-os/includes/lunaix/common.h | 12 ++- lunaix-os/includes/lunaix/elf.h | 75 +++++++++++++ lunaix-os/includes/lunaix/fs.h | 3 + lunaix-os/includes/lunaix/ld.h | 25 +++++ lunaix-os/includes/lunaix/mm/mm.h | 13 ++- lunaix-os/includes/lunaix/mm/mmap.h | 19 ++-- lunaix-os/includes/lunaix/mm/region.h | 5 +- lunaix-os/includes/lunaix/spike.h | 3 + lunaix-os/includes/lunaix/status.h | 2 + lunaix-os/includes/lunaix/syscall.h | 2 + lunaix-os/includes/usr/sys/mann_flags.h | 2 + lunaix-os/includes/usr/unistd.h | 3 + lunaix-os/kernel/asm/x86/pfault.c | 10 +- lunaix-os/kernel/asm/x86/syscall.S | 1 + lunaix-os/kernel/fs/vfs.c | 6 ++ lunaix-os/kernel/loader/elf.c | 138 ++++++++++++++++++++++++ lunaix-os/kernel/loader/exec.c | 132 +++++++++++++++++++++++ lunaix-os/kernel/loader/ld.c | 7 ++ lunaix-os/kernel/mm/mmap.c | 135 ++++++++++++++++------- lunaix-os/kernel/mm/region.c | 18 +++- lunaix-os/kernel/process/process.c | 22 ++-- lunaix-os/kernel/process/sched.c | 2 +- lunaix-os/usr/api/unistd.c | 11 +- 25 files changed, 586 insertions(+), 74 deletions(-) create mode 100644 lunaix-os/includes/lunaix/elf.h create mode 100644 lunaix-os/includes/lunaix/ld.h create mode 100644 lunaix-os/kernel/loader/elf.c create mode 100644 lunaix-os/kernel/loader/exec.c create mode 100644 lunaix-os/kernel/loader/ld.c diff --git a/README.md b/README.md index c3c7cdd..f1cf6b6 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 + 内存管理与按需分页(Demand Paging) + 键盘输入 + 多进程 -+ 49个常见的Linux/POSIX系统调用([附录1](#appendix1)) ++ 50个常见的Linux/POSIX系统调用([附录1](#appendix1)) + 用户模式 + 信号机制 + PCI 3.0 @@ -216,8 +216,9 @@ qemu-img create -f vdi machine/disk0.vdi 128M 2. `ioctl(2)` 2. `getpgid(2)` 2. `setpgid(2)` -2. `mmap(2)`※ -2. `munmap(2)`※ +2. `mmap(2)` +2. `munmap(2)` +2. `execve(2)`※ **LunaixOS自有** diff --git a/docs/README_en.md b/docs/README_en.md index be03432..07d17b7 100644 --- a/docs/README_en.md +++ b/docs/README_en.md @@ -25,7 +25,7 @@ The following list presents all features it does have in current stage. + Memory management & demand paging + PS/2 Keyboard support + Muti-tasking and task management -+ 47 commonly used POSIX syscall([See Appendix 1](#appendix1)) ++ 50 commonly used POSIX syscall([See Appendix 1](#appendix1)) + User Space + Signal + PCI 3.0 @@ -209,9 +209,12 @@ The following list also enumerated such materials the author has used: 2. `setxattr(2)`※ 2. `fgetxattr(2)`※ 2. `fsetxattr(2)`※ -2. `ioctl(2)`※ +2. `ioctl(2)` 2. `getpgid(2)` 2. `setpgid(2)` +2. `mmap(2)` +2. `munmap(2)` +2. `execve(2)`※ **LunaixOS** diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index 1ebf158..daa55af 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -8,9 +8,11 @@ #define MEM_1MB 0x100000 #define MEM_4MB 0x400000 +#define USER_START 0x400000 + #define KSTACK_SIZE MEM_1MB -#define KSTACK_START ((0x3FFFFFU - KSTACK_SIZE) + 1) -#define KSTACK_TOP 0x3FFFF0U +#define KSTACK_START (USER_START - KSTACK_SIZE) +#define KSTACK_TOP ((USER_START - 1) & ~0xf) #define KERNEL_MM_BASE 0xC0000000 @@ -26,11 +28,11 @@ #define UDATA_SEG 0x23 #define TSS_SEG 0x28 -#define USER_START 0x400000 -#define USTACK_SIZE 0x100000 +#define USTACK_SIZE MEM_4MB #define USTACK_TOP 0x9ffffff0 #define USTACK_END (0x9fffffff - USTACK_SIZE + 1) -#define UMMAP_AREA 0x4D000000 +#define UMMAP_START 0x4D000000 +#define UMMAP_END (USTACK_END - MEM_4MB) #ifndef __ASM__ #include diff --git a/lunaix-os/includes/lunaix/elf.h b/lunaix-os/includes/lunaix/elf.h new file mode 100644 index 0000000..ec4196b --- /dev/null +++ b/lunaix-os/includes/lunaix/elf.h @@ -0,0 +1,75 @@ +#ifndef __LUNAIX_ELF_H +#define __LUNAIX_ELF_H + +#include + +typedef unsigned int elf32_ptr_t; +typedef unsigned short elf32_hlf_t; +typedef unsigned int elf32_off_t; +typedef unsigned int elf32_swd_t; +typedef unsigned int elf32_wrd_t; + +#define ET_NONE 0 +#define ET_EXEC 2 + +#define PT_LOAD 1 + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 + +#define EM_NONE 0 +#define EM_386 3 + +#define EV_CURRENT 1 + +#define ELFMAGIC 0x464c457fU +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EI_CLASS 4 +#define EI_DATA 5 + +struct elf32_ehdr +{ + u8_t e_ident[16]; + elf32_hlf_t e_type; + elf32_hlf_t e_machine; + elf32_wrd_t e_version; + elf32_ptr_t e_entry; + elf32_off_t e_phoff; + elf32_off_t e_shoff; + elf32_wrd_t e_flags; + elf32_hlf_t e_ehsize; + elf32_hlf_t e_phentsize; + elf32_hlf_t e_phnum; + elf32_hlf_t e_shentsize; + elf32_hlf_t e_shnum; + elf32_hlf_t e_shstrndx; +}; + +struct elf32_phdr +{ + elf32_wrd_t p_type; + elf32_off_t p_offset; + elf32_ptr_t p_va; + elf32_ptr_t p_pa; + elf32_wrd_t p_filesz; + elf32_wrd_t p_memsz; + elf32_wrd_t p_flags; + elf32_wrd_t p_align; +}; + +#define SIZE_EHDR sizeof(struct elf32_ehdr) +#define SIZE_PHDR sizeof(struct elf32_phdr) + +static inline int +elf_check_exec(struct elf32_ehdr* ehdr) +{ + return (*(u32_t*)(ehdr->e_ident) == ELFMAGIC) || + ehdr->e_ident[EI_CLASS] == ELFCLASS32 || + ehdr->e_ident[EI_DATA] == ELFDATA2LSB || ehdr->e_type == ET_EXEC; +} +#endif /* __LUNAIX_ELF_H */ diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h index 59faabc..4b28881 100644 --- a/lunaix-os/includes/lunaix/fs.h +++ b/lunaix-os/includes/lunaix/fs.h @@ -396,6 +396,9 @@ vfs_get_dtype(int itype); void vfs_ref_dnode(struct v_dnode* dnode); +void +vfs_ref_file(struct v_file* file); + void vfs_unref_dnode(struct v_dnode* dnode); diff --git a/lunaix-os/includes/lunaix/ld.h b/lunaix-os/includes/lunaix/ld.h new file mode 100644 index 0000000..88114f5 --- /dev/null +++ b/lunaix-os/includes/lunaix/ld.h @@ -0,0 +1,25 @@ +#ifndef __LUNAIX_LOADER_H +#define __LUNAIX_LOADER_H + +#include +#include + +#define LD_STAT_FKUP 0x1U + +#define MAX_VAR_PAGES 8 + +struct ld_param +{ + struct proc_info* proc; + ptr_t vms_mnt; + struct elf32_ehdr ehdr_out; + int status; +}; + +int +elf_load(struct ld_param* ldparam, struct v_file* elfile); + +void +ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms); + +#endif /* __LUNAIX_LOADER_H */ diff --git a/lunaix-os/includes/lunaix/mm/mm.h b/lunaix-os/includes/lunaix/mm/mm.h index 5e31e51..43ef96e 100644 --- a/lunaix-os/includes/lunaix/mm/mm.h +++ b/lunaix-os/includes/lunaix/mm/mm.h @@ -46,10 +46,11 @@ typedef struct #define REGION_ANON MAP_ANON #define REGION_RW REGION_READ | REGION_WRITE -#define REGION_TYPE_CODE (1 << 16); -#define REGION_TYPE_GENERAL (2 << 16); -#define REGION_TYPE_HEAP (3 << 16); -#define REGION_TYPE_STACK (4 << 16); +#define REGION_TYPE_CODE (1 << 16) +#define REGION_TYPE_GENERAL (2 << 16) +#define REGION_TYPE_HEAP (3 << 16) +#define REGION_TYPE_STACK (4 << 16) +#define REGION_TYPE_VARS (5 << 16) struct mm_region { @@ -59,6 +60,10 @@ struct mm_region ptr_t start; ptr_t end; u32_t attr; + + void* data; + int (*init_page)(struct mm_region*, void*, off_t); + void (*destruct_region)(struct mm_region*); }; #endif /* __LUNAIX_MM_H */ diff --git a/lunaix-os/includes/lunaix/mm/mmap.h b/lunaix-os/includes/lunaix/mm/mmap.h index fffed07..6429225 100644 --- a/lunaix-os/includes/lunaix/mm/mmap.h +++ b/lunaix-os/includes/lunaix/mm/mmap.h @@ -5,16 +5,23 @@ #include #include +struct mmap_param +{ + ptr_t vms_mnt; + vm_regions_t* regions; + off_t offset; + size_t length; + u32_t proct; + u32_t flags; + u32_t type; +}; + int mem_map(void** addr_out, - ptr_t mnt, - vm_regions_t* regions, + struct mm_region** created, void* addr, struct v_file* file, - off_t offset, - size_t length, - u32_t proct, - u32_t options); + struct mmap_param* param); int mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length); diff --git a/lunaix-os/includes/lunaix/mm/region.h b/lunaix-os/includes/lunaix/mm/region.h index 24b1dfe..3aa522a 100644 --- a/lunaix-os/includes/lunaix/mm/region.h +++ b/lunaix-os/includes/lunaix/mm/region.h @@ -15,7 +15,10 @@ void region_add(vm_regions_t* lead, struct mm_region* vmregion); void -region_release_all(vm_regions_t* lead); +region_release(pid_t pid, struct mm_region* region); + +void +region_release_all(pid_t pid, vm_regions_t* lead); struct mm_region* region_get(vm_regions_t* lead, unsigned long vaddr); diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 91c92fc..f87b00a 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -81,6 +81,9 @@ spin() if (!(cond)) { \ __assert_fail(msg, __FILE__, __LINE__); \ } + +#define fail(msg) __assert_fail(msg, __FILE__, __LINE__); + void __assert_fail(const char* expr, const char* file, unsigned int line) __attribute__((noinline, noreturn)); diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h index f9b947d..31d2327 100644 --- a/lunaix-os/includes/lunaix/status.h +++ b/lunaix-os/includes/lunaix/status.h @@ -30,5 +30,7 @@ #define ENOTDEV -24 #define EOVERFLOW -25 #define ENOTBLK -26 +#define ENOEXEC -27 +#define E2BIG -28 #endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index 6c42252..a512bd7 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -63,6 +63,8 @@ #define __SYSCALL_sys_mmap 52 #define __SYSCALL_munmap 53 +#define __SYSCALL_execve 54 + #define __SYSCALL_MAX 0x100 #ifndef __ASM__ diff --git a/lunaix-os/includes/usr/sys/mann_flags.h b/lunaix-os/includes/usr/sys/mann_flags.h index 2627430..479c60b 100644 --- a/lunaix-os/includes/usr/sys/mann_flags.h +++ b/lunaix-os/includes/usr/sys/mann_flags.h @@ -21,9 +21,11 @@ // other MAP_* goes should beyond 0x20 #define MAP_FIXED 0x40 +#define MAP_FIXED_NOREPLACE 0x80 #define MS_ASYNC 0x1 #define MS_SYNC 0x2 #define MS_INVALIDATE 0x4 +#define MS_INVALIDATE_ALL 0x8 #endif /* __LUNAIX_MANN_FLAGS_H */ diff --git a/lunaix-os/includes/usr/unistd.h b/lunaix-os/includes/usr/unistd.h index 92992be..5232a80 100644 --- a/lunaix-os/includes/usr/unistd.h +++ b/lunaix-os/includes/usr/unistd.h @@ -108,4 +108,7 @@ fgetxattr(int fd, const char* name, void* value, size_t len); int fsetxattr(int fd, const char* name, void* value, size_t len); +int +execve(const char* filename, const char* argv[], const char* envp[]); + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 4f0ccda..2388f38 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -102,9 +102,15 @@ intr_routine_page_fault(const isr_param* param) ptr = PG_ALIGN(ptr); memset(ptr, 0, PG_SIZE); - int errno = file->ops->read_page(file->inode, ptr, PG_SIZE, offset); + int errno = 0; + if (hit_region->init_page) { + errno = hit_region->init_page(hit_region, ptr, offset); + } else { + errno = file->ops->read_page(file->inode, ptr, PG_SIZE, offset); + } + if (errno < 0) { - kprintf(KERROR "fail to read page (%d)\n", errno); + kprintf(KERROR "fail to populate page (%d)\n", errno); goto segv_term; } diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index eb16783..bde7f36 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -61,6 +61,7 @@ .long __lxsys_syslog .long __lxsys_sys_mmap .long __lxsys_munmap + .long __lxsys_execve 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c index e436eba..d3d1023 100644 --- a/lunaix-os/kernel/fs/vfs.c +++ b/lunaix-os/kernel/fs/vfs.c @@ -1225,6 +1225,12 @@ done: return DO_STATUS(errno); } +void +vfs_ref_file(struct v_file* file) +{ + atomic_fetch_add(&file->ref_count, 1); +} + void vfs_ref_dnode(struct v_dnode* dnode) { diff --git a/lunaix-os/kernel/loader/elf.c b/lunaix-os/kernel/loader/elf.c new file mode 100644 index 0000000..7880fe6 --- /dev/null +++ b/lunaix-os/kernel/loader/elf.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int +__elf_populate_mapped(struct mm_region* region, void* pg, off_t offset) +{ + struct elf32_phdr* phdr = (struct elf32_phdr*)region->data; + size_t segsz = phdr->p_filesz; + size_t segoff = offset - phdr->p_offset; + + if (segoff >= segsz) { + return 0; + } + + struct v_file* file = region->mfile; + size_t rdlen = MIN(segsz - segoff, PG_SIZE); + + if (rdlen == PG_SIZE) { + // This is because we want to exploit any optimization on read_page + return file->ops->read_page(file->inode, pg, PG_SIZE, offset); + } else { + return file->ops->read(file->inode, pg, rdlen, offset); + } +} + +void +__elf_destruct_mapped(struct mm_region* region) +{ + vfree(region->data); +} + +int +elf_map_segment(struct ld_param* ldparam, + struct v_file* elfile, + struct elf32_phdr* phdr) +{ + int proct = 0; + if ((phdr->p_flags & PF_R)) { + proct |= PROT_READ; + } + if ((phdr->p_flags & PF_W)) { + proct |= PROT_WRITE; + } + if ((phdr->p_flags & PF_X)) { + proct |= PROT_EXEC; + } + + struct mm_region* seg_reg; + struct mmap_param param = { .vms_mnt = ldparam->vms_mnt, + .regions = &ldparam->proc->mm.regions, + .proct = proct, + .offset = phdr->p_offset, + .length = ROUNDUP(phdr->p_memsz, PG_SIZE), + .flags = + MAP_FIXED | MAP_PRIVATE | REGION_TYPE_CODE }; + + int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdr->p_va), elfile, ¶m); + + if (!status) { + struct elf32_phdr* phdr_ = valloc(sizeof(SIZE_PHDR)); + *phdr_ = *phdr; + seg_reg->data = phdr; + + seg_reg->init_page = __elf_populate_mapped; + seg_reg->destruct_region = __elf_destruct_mapped; + } + + return status; +} + +int +elf_setup_mapping(struct ld_param* ldparam, + struct v_file* elfile, + struct elf32_ehdr* ehdr) +{ + int status = 0; + size_t tbl_sz = ehdr->e_phnum * SIZE_PHDR; + struct elf32_phdr* phdrs = valloc(tbl_sz); + + if (!phdrs) { + status = ENOMEM; + goto done; + } + + tbl_sz = 1 << ILOG2(tbl_sz); + phdrs = elfile->ops->read(elfile->inode, phdrs, tbl_sz, ehdr->e_phoff); + + size_t entries = tbl_sz / SIZE_PHDR; + for (size_t i = 0; i < entries; i++) { + struct elf32_phdr* phdr = &phdrs[i]; + + if (phdr->p_type == PT_LOAD) { + status = elf_map_segment(ldparam, elfile, phdr); + } + // TODO process other types of segments + + if (status) { + ldparam->status |= LD_STAT_FKUP; + goto done; + } + } + +done: + vfree(phdrs); + return status; +} + +int +elf_load(struct ld_param* ldparam, struct v_file* elfile) +{ + struct elf32_ehdr* ehdr = valloc(SIZE_EHDR); + int status = elfile->ops->read(elfile->inode, ehdr, SIZE_EHDR, 0); + + if (status) { + goto done; + } + + if (!elf_check_exec(ehdr)) { + status = ENOEXEC; + goto done; + } + + if ((status = elf_setup_mapping(ldparam, elfile, ehdr))) { + goto done; + } + + ldparam->ehdr_out = *ehdr; + +done: + vfree(ehdr); + return status; +} \ No newline at end of file diff --git a/lunaix-os/kernel/loader/exec.c b/lunaix-os/kernel/loader/exec.c new file mode 100644 index 0000000..6c33495 --- /dev/null +++ b/lunaix-os/kernel/loader/exec.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +size_t +exec_str_size(const char** str_arr, size_t* length) +{ + const char* chr = *str_arr; + size_t sz = 0, len = 0; + + while (chr) { + sz += strlen(chr); + len++; + + chr = *(str_arr + sz); + } + + *length = len; + return sz + 1; +} + +int +exec_loadto(struct ld_param* param, + struct v_file* executable, + const char** argv, + const char** envp) +{ + int errno = 0; + + size_t argv_len, envp_len; + size_t sz_argv = exec_str_size(argv, &argv_len); + size_t sz_envp = exec_str_size(envp, &envp_len); + size_t total_sz = ROUNDUP(sz_argv + sz_envp, PG_SIZE); + + if (total_sz / PG_SIZE > MAX_VAR_PAGES) { + errno = E2BIG; + goto done; + } + + if ((errno = elf_load(param, executable))) { + goto done; + } + + struct mmap_param map_param = { .regions = ¶m->proc->mm.regions, + .vms_mnt = param->vms_mnt, + .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED, + .type = REGION_TYPE_VARS, + .proct = PROT_READ, + .length = MAX_VAR_PAGES * PG_SIZE }; + + void* mapped; + isr_param* intr_ctx = ¶m->proc->intr_ctx; + + // TODO reinitialize heap + + if (param->vms_mnt == VMS_SELF) { + // we are loading executable into current addr space + if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_param))) { + goto done; + } + + memcpy(mapped, (void*)argv, sz_argv); + memcpy(mapped + sz_argv, (void*)envp, sz_envp); + + ptr_t* ustack = (void*)USTACK_TOP; + size_t* argc = &((size_t*)&ustack[-1])[-1]; + + ustack[-1] = (ptr_t)mapped; + *argc = argv_len; + + // TODO handle envp. + + intr_ctx->esp = argc; + } else { + // TODO need to find a way to inject argv and envp remotely + fail("not implemented"); + } + + intr_ctx->eip = param->ehdr_out.e_entry; + // we will jump to new entry point upon syscall's return + // so execve will not return from the perspective of it's invoker + +done: + return errno; +} + +__DEFINE_LXSYSCALL3(int, + execve, + const char*, + filename, + const char*, + argv[], + const char*, + envp[]) +{ + int errno = 0; + struct v_dnode* dnode; + struct v_file* file; + + if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) { + goto done; + } + + if ((errno = vfs_open(dnode, &file))) { + goto done; + } + + struct ld_param ldparam; + ld_create_param(&ldparam, __current, VMS_SELF); + + if ((errno = exec_loadto(&ldparam, file, argv, envp))) { + vfs_pclose(file, __current->pid); + + if ((ldparam.status & LD_STAT_FKUP)) { + // we fucked up our address space. + terminate_proc(11451); + schedule(); + fail("should not reach"); + } + } + +done: + return errno; +} \ No newline at end of file diff --git a/lunaix-os/kernel/loader/ld.c b/lunaix-os/kernel/loader/ld.c new file mode 100644 index 0000000..413e0f8 --- /dev/null +++ b/lunaix-os/kernel/loader/ld.c @@ -0,0 +1,7 @@ +#include + +void +ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms) +{ + *param = (struct ld_param){ .proc = proc, .vms_mnt = vms }; +} \ No newline at end of file diff --git a/lunaix-os/kernel/mm/mmap.c b/lunaix-os/kernel/mm/mmap.c index c1ebe09..0c0c383 100644 --- a/lunaix-os/kernel/mm/mmap.c +++ b/lunaix-os/kernel/mm/mmap.c @@ -8,34 +8,63 @@ #include // any size beyond this is bullshit -#define BS_SIZE (2 << 30) +#define BS_SIZE (KERNEL_MM_BASE - UMMAP_START) + +int +mem_has_overlap(vm_regions_t* regions, ptr_t start, size_t len) +{ + ptr_t end = start + end - 1; + struct mm_region *pos, *n; + llist_for_each(pos, n, regions, head) + { + if (pos->end >= start && pos->start < start) { + return 1; + } + + if (pos->end <= end && pos->start >= start) { + return 1; + } + + if (pos->end >= end && pos->start < end) { + return 1; + } + } + + return 0; +} int mem_map(void** addr_out, - ptr_t mnt, - vm_regions_t* regions, + struct mm_region** created, void* addr, struct v_file* file, - off_t offset, - size_t length, - u32_t proct, - u32_t options) + struct mmap_param* param) { ptr_t last_end = USER_START; struct mm_region *pos, *n; - if ((options & MAP_FIXED)) { - pos = region_get(regions, addr); - if (!pos) { - last_end = addr; - goto found; + if ((param->flags & MAP_FIXED_NOREPLACE)) { + if (mem_has_overlap(param->regions, addr, param->length)) { + return EEXIST; } - return EEXIST; + last_end = addr; + goto found; } - llist_for_each(pos, n, regions, head) + if ((param->flags & MAP_FIXED)) { + int status = + mem_unmap(param->vms_mnt, param->regions, addr, param->length); + if (status) { + return status; + } + last_end = addr; + goto found; + } + + llist_for_each(pos, n, param->regions, head) { - if (pos->start - last_end >= length && last_end >= addr) { + if (pos->start - last_end > param->length && last_end > addr) { + last_end += 1; goto found; } last_end = pos->end; @@ -46,23 +75,37 @@ mem_map(void** addr_out, found: addr = last_end; - struct mm_region* region = - region_create_range(addr, length, proct | (options & 0x1f)); + if (addr >= KERNEL_MM_BASE || addr < USER_START) { + return ENOMEM; + } + + struct mm_region* region = region_create_range( + addr, + param->length, + ((param->proct | param->flags) & 0x1f) | (param->type & ~0xffff)); + region->mfile = file; - region->offset = offset; + region->offset = param->offset; - region_add(regions, region); + region_add(param->regions, region); u32_t attr = PG_ALLOW_USER; - if ((proct & REGION_WRITE)) { + if ((param->proct & REGION_WRITE)) { attr |= PG_WRITE; } - for (u32_t i = 0; i < length; i += PG_SIZE) { - vmm_set_mapping(mnt, addr + i, 0, attr, 0); + for (u32_t i = 0; i < param->length; i += PG_SIZE) { + vmm_set_mapping(param->vms_mnt, addr + i, 0, attr, 0); } - *addr_out = addr; + vfs_ref_file(file); + + if (addr_out) { + *addr_out = addr; + } + if (created) { + *created = region; + } return 0; } @@ -82,16 +125,27 @@ mem_sync_pages(ptr_t mnt, if (!vmm_lookupat(mnt, start + i, &mapping)) { continue; } + if (PG_IS_DIRTY(*mapping.pte)) { size_t offset = mapping.va - region->start + region->offset; struct v_inode* inode = region->mfile->inode; region->mfile->ops->write_page(inode, mapping.va, PG_SIZE, offset); *mapping.pte &= ~PG_DIRTY; - cpu_invplg(mapping.va); + cpu_invplg(mapping.pte); } else if ((options & MS_INVALIDATE)) { - *mapping.pte &= ~PG_PRESENT; - cpu_invplg(mapping.va); + goto invalidate; } + + if (options & MS_INVALIDATE_ALL) { + goto invalidate; + } + + continue; + + invalidate: + *mapping.pte &= ~PG_PRESENT; + pmm_free_page(KERNEL_PID, mapping.pa); + cpu_invplg(mapping.pte); } } @@ -160,13 +214,15 @@ mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length) n = container_of(pos->head.next, typeof(*pos), head); if (pos->end == pos->start) { llist_delete(&pos->head); - vfree(pos); + region_release(__current->pid, pos); } pos = n; length -= l; cur_addr += length; } + + return 0; } __DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst) @@ -183,6 +239,13 @@ __DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst) goto done; } + if (!addr) { + addr = UMMAP_START; + } else if (addr < UMMAP_START || addr + length >= UMMAP_END) { + errno = ENOMEM; + goto done; + } + struct v_fd* vfd; if ((errno = vfs_getfd(fd, &vfd))) { goto done; @@ -199,17 +262,15 @@ __DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst) file = NULL; } - length = ROUNDUP(length, PG_SIZE); + struct mmap_param param = { .flags = options, + .length = ROUNDUP(length, PG_SIZE), + .offset = offset, + .type = REGION_TYPE_GENERAL, + .proct = proct, + .regions = &__current->mm.regions, + .vms_mnt = VMS_SELF }; - errno = mem_map(&result, - VMS_SELF, - &__current->mm.regions, - addr, - file, - offset, - length, - proct, - options); + errno = mem_map(&result, NULL, addr, file, ¶m); done: __current->k_status = errno; diff --git a/lunaix-os/kernel/mm/region.c b/lunaix-os/kernel/mm/region.c index fe7c5c9..2821428 100644 --- a/lunaix-os/kernel/mm/region.c +++ b/lunaix-os/kernel/mm/region.c @@ -53,13 +53,27 @@ region_add(vm_regions_t* lead, struct mm_region* vmregion) } void -region_release_all(vm_regions_t* lead) +region_release(pid_t pid, struct mm_region* region) +{ + if (region->destruct_region) { + region->destruct_region(region); + } + + if (region->mfile) { + vfs_pclose(region->mfile, pid); + } + + vfree(region); +} + +void +region_release_all(pid_t pid, vm_regions_t* lead) { struct mm_region *pos, *n; llist_for_each(pos, n, lead, head) { - vfree(pos); + region_release(pid, pos); } } diff --git a/lunaix-os/kernel/process/process.c b/lunaix-os/kernel/process/process.c index 1647e10..65384d1 100644 --- a/lunaix-os/kernel/process/process.c +++ b/lunaix-os/kernel/process/process.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -141,16 +142,17 @@ init_proc_user_space(struct proc_info* pcb) /*--- 分配用户栈 ---*/ - struct mm_region* stack_vm; - - stack_vm = region_create_range( - USTACK_END, USTACK_SIZE, REGION_RW | REGION_RSHARED | REGION_ANON); - // 注册用户栈区域 - region_add(&pcb->mm.regions, stack_vm); - - // 预留地址空间,具体物理页将由Page Fault Handler按需分配。 - for (uintptr_t i = PG_ALIGN(USTACK_END); i < USTACK_TOP; i += PG_SIZE) { - vmm_set_mapping(VMS_MOUNT_1, i, 0, PG_ALLOW_USER | PG_WRITE, VMAP_NULL); + struct mm_region* mapped; + struct mmap_param param = { .vms_mnt = VMS_MOUNT_1, + .regions = &pcb->mm.regions, + .length = USTACK_SIZE, + .proct = PROT_READ | PROT_WRITE, + .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED, + .type = REGION_TYPE_STACK }; + + int status = 0; + if ((status = mem_map(NULL, &mapped, USTACK_END, NULL, ¶m))) { + kprint_panic("fail to alloc user stack: %d", status); } // TODO other uspace initialization stuff diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index 1c6bd97..de1a4a5 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -407,7 +407,7 @@ destroy_process(pid_t pid) llist_for_each(pos, n, &proc->mm.regions, head) { mem_sync_pages(VMS_MOUNT_1, pos, pos->start, pos->end - pos->start, 0); - vfree(pos); + region_release(pid, pos); } __del_pagetable(pid, VMS_MOUNT_1); diff --git a/lunaix-os/usr/api/unistd.c b/lunaix-os/usr/api/unistd.c index bd7cb24..78891d1 100644 --- a/lunaix-os/usr/api/unistd.c +++ b/lunaix-os/usr/api/unistd.c @@ -114,4 +114,13 @@ __LXSYSCALL4(int, __LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname) -__LXSYSCALL1(int, mkdir, const char*, path) \ No newline at end of file +__LXSYSCALL1(int, mkdir, const char*, path) + +__LXSYSCALL3(int, + execve, + const char*, + filename, + const char**, + argv, + const char**, + envp) \ No newline at end of file -- 2.27.0