📄 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_FAKEMMAP: { sos_uaddr_t ptr_hint_uaddr; sos_uaddr_t hint_uaddr; sos_size_t length; sos_ui32_t prot; sos_ui32_t flags; sos_uaddr_t name_user; sos_ui32_t offs64_hi; sos_ui32_t offs64_lo; sos_luoffset_t offset_in_resource; char name[256]; struct sos_umem_vmm_as * my_as; retval = sos_syscall_get7args(user_ctxt, (unsigned int*)& ptr_hint_uaddr, (unsigned int*)& length, (unsigned int*)& prot, (unsigned int*)& flags, (unsigned int*)& name_user, (unsigned int*)& offs64_hi, (unsigned int*)& offs64_lo); if (SOS_OK != retval) break; /* Compute 64 bits offset value */ offset_in_resource = offs64_hi; offset_in_resource <<= 32; offset_in_resource |= offs64_lo; retval = sos_memcpy_from_user((sos_vaddr_t)& hint_uaddr, ptr_hint_uaddr, sizeof(hint_uaddr)); if (sizeof(hint_uaddr) != retval) { retval = -SOS_EFAULT; break; } retval = sos_strzcpy_from_user(name, name_user, sizeof(name)); if (SOS_OK != retval) break; my_as = sos_process_get_address_space(sos_thread_get_current()->process); if ( (0 == strncmp(name, "/dev/zero", sizeof(name))) || (0 == strncmp(name, "/dev/null", sizeof(name))) ) retval = sos_dev_zero_map(my_as, & hint_uaddr, length, prot, flags); else if (0 == strncmp(name, "/dev/mem", sizeof(name))) retval = sos_dev_physmem_map(my_as, & hint_uaddr, length, offset_in_resource, prot, flags); else if (0 == strncmp(name, "/dev/kmem", sizeof(name))) retval = sos_dev_kmem_map(my_as, & hint_uaddr, length, offset_in_resource, prot, flags); else retval = -SOS_ENOENT; if (SOS_OK == retval) { if (sizeof(hint_uaddr) != sos_memcpy_to_user(ptr_hint_uaddr, (sos_vaddr_t)& hint_uaddr, sizeof(hint_uaddr))) { sos_umem_vmm_unmap(my_as, hint_uaddr, length); retval = -SOS_EFAULT; } } } 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; const char * kernel_src = NULL; sos_uaddr_t user_dst; sos_size_t dstlen; const char * kernel_dst; sos_ui32_t mountflags; sos_uaddr_t user_fstype; char * kernel_fstype; sos_uaddr_t user_args;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -