⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syscall.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -