📄 syscall.c
字号:
/* Copyright (C) 2005 David Decotigny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <sos/thread.h>#include <sos/kmalloc.h>#include <sos/klibc.h>#include <drivers/bochs.h>#include <hwcore/paging.h>#include <sos/physmem.h>#include <sos/umem_vmm.h>#include <drivers/zero.h>#include <drivers/mem.h>#include <sos/binfmt_elf32.h>#include <hwcore/cpu_context.h>#include <sos/uaccess.h>#include "syscall.h"/** * THE syscall entry point */sos_ret_t sos_do_syscall(int syscall_id, const struct sos_cpu_state *user_ctxt){ sos_ret_t retval; switch(syscall_id) { case SOS_SYSCALL_ID_EXIT: { unsigned int status; retval = sos_syscall_get1arg(user_ctxt, & status); if (SOS_OK != retval) break; sos_thread_exit(); retval = -SOS_EFATAL; /* Not reached */ } break; case SOS_SYSCALL_ID_FORK: { struct sos_thread *cur_thr, *new_thr; struct sos_process *new_proc; cur_thr = sos_thread_get_current(); /* Duplicate the current process (and its address space) */ new_proc = sos_process_create(NULL, TRUE); if (! new_proc) { retval = -SOS_ENOMEM; break; } /* Create *the* thread in this new processs, copy of the current user thread (same registers, EXCEPT eax which is set to 0) */ new_thr = sos_duplicate_user_thread(NULL, new_proc, cur_thr, user_ctxt, 0); if (! new_thr) { sos_process_unref(new_proc); retval = -SOS_ENOMEM; break; } sos_process_unref(new_proc); /* Return to the "parent" thread with a value different from 0. Unix says it should be the "PID" of the child. We don't have such a "PID" notion for now */ retval = (sos_ui32_t)new_proc; } break; case SOS_SYSCALL_ID_EXEC: { struct sos_thread *cur_thr, *new_thr; struct sos_process * proc; struct sos_umem_vmm_as *new_as; sos_uaddr_t user_str, ustack, start_uaddr; sos_size_t len; char * str; cur_thr = sos_thread_get_current(); proc = cur_thr->process; /* Make sure the process has exactly 1 thread in it */ if (sos_process_get_nb_threads(proc) != 1) { retval = -SOS_EBUSY; break; } /* Get the user arguments */ retval = sos_syscall_get2args(user_ctxt, & user_str, & len); if (SOS_OK != retval) break; /* Copy the program name into kernel sppace */ retval = sos_strndup_from_user(& str, user_str, len + 1, 0); if (SOS_OK != retval) { break; } /* Create a new empty address space to map the program */ new_as = sos_umem_vmm_create_empty_as(proc); if (! new_as) { sos_kfree((sos_vaddr_t)str); retval = -SOS_ENOMEM; break; } /* Map the program in it */ start_uaddr = sos_binfmt_elf32_map(new_as, str); if (start_uaddr == (sos_uaddr_t)NULL) { sos_umem_vmm_delete_as(new_as); sos_kfree((sos_vaddr_t)str); retval = -SOS_ENOENT; break; } /* Allocate space for the user stack (8MB) */#define SOS_DEFAULT_USER_STACK_SIZE (8 << 20) ustack = (SOS_PAGING_TOP_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) + 1; retval = sos_dev_zero_map(new_as, &ustack, SOS_DEFAULT_USER_STACK_SIZE, SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, /* PRIVATE */ 0); if (SOS_OK != retval) { sos_umem_vmm_delete_as(new_as); sos_kfree((sos_vaddr_t)str); break; } /* Now create the user thread */ new_thr = sos_create_user_thread(NULL, proc, start_uaddr, 0, 0, ustack + SOS_DEFAULT_USER_STACK_SIZE - 4, SOS_SCHED_PRIO_TS_LOWEST); if (! new_thr) { sos_umem_vmm_delete_as(new_as); sos_kfree((sos_vaddr_t)str); retval = -SOS_ENOMEM; break; } sos_process_set_name(proc, str); /* Switch to this address space */ retval = sos_process_set_address_space(proc, new_as); if (SOS_OK != retval) { sos_umem_vmm_delete_as(new_as); sos_kfree((sos_vaddr_t)str); break; } /* The current thread must exit now */ sos_kfree((sos_vaddr_t)str); sos_thread_exit(); retval = -SOS_EFATAL; } break; case SOS_SYSCALL_ID_MUNMAP: { sos_uaddr_t start_uaddr; sos_size_t size; struct sos_umem_vmm_as * my_as; my_as = sos_process_get_address_space(sos_thread_get_current()->process); retval = sos_syscall_get2args(user_ctxt, (unsigned int*)& start_uaddr, (unsigned int*)& size); if (SOS_OK != retval) break; retval = sos_umem_vmm_unmap(my_as, start_uaddr, size); } break; case SOS_SYSCALL_ID_MPROTECT: { sos_uaddr_t start_uaddr; sos_size_t size; sos_ui32_t new_access_rights; struct sos_umem_vmm_as * my_as; my_as = sos_process_get_address_space(sos_thread_get_current()->process); retval = sos_syscall_get3args(user_ctxt, (unsigned int*)& start_uaddr, (unsigned int*)& size, (unsigned int*)& new_access_rights); if (SOS_OK != retval) break; retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL); if (SOS_OK != retval) break; retval = sos_umem_vmm_chprot(my_as, start_uaddr, size, new_access_rights); sos_thread_end_user_space_access(); } break; case SOS_SYSCALL_ID_MRESIZE: { sos_uaddr_t old_uaddr; sos_size_t old_size; sos_uaddr_t *uptr_new_uaddr; sos_uaddr_t new_uaddr; sos_size_t new_size; sos_ui32_t flags; struct sos_umem_vmm_as * my_as; my_as = sos_process_get_address_space(sos_thread_get_current()->process); retval = sos_syscall_get5args(user_ctxt, (unsigned int*)& old_uaddr, (unsigned int*)& old_size, (unsigned int*)& uptr_new_uaddr, (unsigned int*)& new_size, (unsigned int*)& flags); if (SOS_OK != retval) break; if (sizeof(new_uaddr) != sos_memcpy_from_user((sos_vaddr_t)& new_uaddr, (sos_uaddr_t) uptr_new_uaddr, sizeof(new_uaddr))) { retval = -SOS_EFAULT; break; } retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL); if (SOS_OK != retval) break; retval = sos_umem_vmm_resize(my_as, old_uaddr, old_size, & new_uaddr, new_size, flags); sos_thread_end_user_space_access(); if (SOS_OK != retval) break; if (sizeof(new_uaddr) == sos_memcpy_to_user((sos_uaddr_t)uptr_new_uaddr, (sos_vaddr_t)&new_uaddr, sizeof(new_uaddr))) { retval = -SOS_EFAULT; break; } } break; case SOS_SYSCALL_ID_NEW_THREAD: { sos_uaddr_t start_func; sos_ui32_t start_arg1, start_arg2; sos_size_t stack_size; sos_uaddr_t stack_uaddr; struct sos_thread * new_thr; struct sos_umem_vmm_as * my_as; my_as = sos_process_get_address_space(sos_thread_get_current()->process); retval = sos_syscall_get4args(user_ctxt, (unsigned int*)& start_func, (unsigned int*)& start_arg1, (unsigned int*)& start_arg2, (unsigned int*)& stack_size); if (SOS_OK != retval) break; if (stack_size <= 0) { retval = -SOS_EINVAL; break; } /* Allocate the stack */ stack_uaddr = 0; stack_size = SOS_PAGE_ALIGN_SUP(stack_size); retval = sos_dev_zero_map(my_as, & stack_uaddr, stack_size, SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, /* PRIVATE */ 0); if (SOS_OK != retval) break; /* Now create the user thread */ new_thr = sos_create_user_thread(NULL, sos_thread_get_current()->process, start_func, start_arg1, start_arg2, stack_uaddr + stack_size - 4, SOS_SCHED_PRIO_TS_LOWEST); if (! new_thr) { sos_umem_vmm_unmap(my_as, stack_uaddr, stack_size); retval = -SOS_ENOMEM; break; } } break; case SOS_SYSCALL_ID_NANOSLEEP: { struct sos_time delay; retval = sos_syscall_get2args(user_ctxt, (unsigned int*)& delay.sec, (unsigned int*)& delay.nanosec); if (SOS_OK != retval) break; retval = sos_thread_sleep(& delay); } break; case SOS_SYSCALL_ID_BRK: { sos_uaddr_t new_top_heap; struct sos_umem_vmm_as * my_as; my_as = sos_process_get_address_space(sos_thread_get_current()->process); retval = sos_syscall_get1arg(user_ctxt, (unsigned int*)& new_top_heap); if (SOS_OK != retval) break; retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL); if (SOS_OK != retval) break; retval = sos_umem_vmm_brk(my_as, new_top_heap); sos_thread_end_user_space_access(); } break; /** * File system interface */ case SOS_SYSCALL_ID_MOUNT: { sos_uaddr_t user_src; sos_size_t srclen; char * kernel_src = NULL; sos_uaddr_t user_dst; sos_size_t dstlen; char * kernel_dst; sos_ui32_t mountflags; sos_uaddr_t user_fstype; char * kernel_fstype; sos_uaddr_t user_args; char * kernel_args = NULL; struct sos_process * proc; proc = sos_thread_get_current()->process; retval = sos_syscall_get7args(user_ctxt, (unsigned int*)& user_src, (unsigned int*)& srclen, (unsigned int*)& user_dst, (unsigned int*)& dstlen, (unsigned int*)& user_fstype, (unsigned int*)& mountflags, (unsigned int*)& user_args); if (SOS_OK != retval) break; if (user_src != (sos_uaddr_t)NULL) { retval = sos_strndup_from_user(&kernel_src, user_src, srclen, 0); if (SOS_OK != retval) break; } retval = sos_strndup_from_user(&kernel_dst, user_dst, dstlen, 0); if (SOS_OK != retval) { if (kernel_src) sos_kfree((sos_vaddr_t)kernel_src); break; } retval = sos_strndup_from_user(& kernel_fstype, user_fstype, 256, 0); if (SOS_OK != retval) { if (kernel_src) sos_kfree((sos_vaddr_t)kernel_src); sos_kfree((sos_vaddr_t)kernel_dst); break; } if (user_args != (sos_uaddr_t)NULL) { retval = sos_strndup_from_user(& kernel_args, user_args, 1024, 0); if (SOS_OK != retval) { if (kernel_src) sos_kfree((sos_vaddr_t)kernel_src); sos_kfree((sos_vaddr_t)kernel_dst); sos_kfree((sos_vaddr_t)kernel_fstype); break; } } retval = sos_fs_mount(proc, kernel_src, srclen, kernel_dst, dstlen, kernel_fstype, mountflags, kernel_args, NULL); if (kernel_src) sos_kfree((sos_vaddr_t)kernel_src); sos_kfree((sos_vaddr_t)kernel_dst); sos_kfree((sos_vaddr_t)kernel_fstype); if (kernel_args) sos_kfree((sos_vaddr_t)kernel_args); } break; case SOS_SYSCALL_ID_UMOUNT: { sos_uaddr_t user_str; sos_size_t len; char * path; struct sos_process * proc; proc = sos_thread_get_current()->process;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -