1483 lines
34 KiB
C
1483 lines
34 KiB
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/assert.h>
|
|
#include <sos/thread.h>
|
|
#include <sos/kmalloc.h>
|
|
#include <sos/klibc.h>
|
|
#include <drivers/bochs.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"
|
|
|
|
|
|
/** To get rid of gcc's "dereferencing type-punned pointer will break
|
|
strict-aliasing rules" warning */
|
|
#define SYSCALL_VAR32_PTR(ui32_variable) \
|
|
((void*)&(ui32_variable))
|
|
|
|
|
|
/**
|
|
* 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 /* fork return value for child ! */);
|
|
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)sos_process_get_pid(new_proc);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_GETPID:
|
|
{
|
|
struct sos_thread *cur_thr;
|
|
struct sos_process * proc;
|
|
|
|
cur_thr = sos_thread_get_current();
|
|
proc = cur_thr->process;
|
|
|
|
retval = (sos_ui32_t) sos_process_get_pid(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_uaddr_t src_argaddr;
|
|
sos_size_t len_args;
|
|
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_get4args(user_ctxt, & user_str, & len,
|
|
& src_argaddr, & len_args);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Don't go any further if the arg/env array is obviously too
|
|
large */
|
|
if (SOS_DEFAULT_USER_STACK_SIZE <= len_args)
|
|
{
|
|
retval = -SOS_EINVAL;
|
|
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_UPPER_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;
|
|
}
|
|
|
|
/* ustack now refers to the initial stack pointer of the new
|
|
user thread: update it here */
|
|
ustack = SOS_ALIGN_INF((ustack + SOS_DEFAULT_USER_STACK_SIZE
|
|
- len_args), 4);
|
|
|
|
if (len_args != sos_usercpy(new_as, ustack,
|
|
NULL, src_argaddr,
|
|
len_args))
|
|
{
|
|
sos_umem_vmm_delete_as(new_as);
|
|
sos_kfree((sos_vaddr_t)str);
|
|
retval = -SOS_EFAULT;
|
|
break;
|
|
}
|
|
|
|
/* Now create the user thread */
|
|
new_thr = sos_create_user_thread(NULL,
|
|
proc,
|
|
start_uaddr,
|
|
0, 0,
|
|
ustack,
|
|
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,
|
|
SYSCALL_VAR32_PTR(start_uaddr),
|
|
SYSCALL_VAR32_PTR(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,
|
|
SYSCALL_VAR32_PTR(start_uaddr),
|
|
SYSCALL_VAR32_PTR(size),
|
|
SYSCALL_VAR32_PTR(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,
|
|
SYSCALL_VAR32_PTR(old_uaddr),
|
|
SYSCALL_VAR32_PTR(old_size),
|
|
SYSCALL_VAR32_PTR(uptr_new_uaddr),
|
|
SYSCALL_VAR32_PTR(new_size),
|
|
SYSCALL_VAR32_PTR(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_MSYNC:
|
|
{
|
|
sos_uaddr_t start_uaddr;
|
|
sos_size_t 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_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(start_uaddr),
|
|
SYSCALL_VAR32_PTR(size),
|
|
SYSCALL_VAR32_PTR(flags));
|
|
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_sync(my_as, start_uaddr, size, flags);
|
|
sos_thread_end_user_space_access();
|
|
}
|
|
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,
|
|
SYSCALL_VAR32_PTR(start_func),
|
|
SYSCALL_VAR32_PTR(start_arg1),
|
|
SYSCALL_VAR32_PTR(start_arg2),
|
|
SYSCALL_VAR32_PTR(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,
|
|
SYSCALL_VAR32_PTR(delay.sec),
|
|
SYSCALL_VAR32_PTR(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,
|
|
SYSCALL_VAR32_PTR(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,
|
|
SYSCALL_VAR32_PTR(user_src),
|
|
SYSCALL_VAR32_PTR(srclen),
|
|
SYSCALL_VAR32_PTR(user_dst),
|
|
SYSCALL_VAR32_PTR(dstlen),
|
|
SYSCALL_VAR32_PTR(user_fstype),
|
|
SYSCALL_VAR32_PTR(mountflags),
|
|
SYSCALL_VAR32_PTR(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;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_umount(proc,
|
|
path, len);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_SYNC:
|
|
{
|
|
sos_fs_sync_all_fs();
|
|
retval = SOS_OK;
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_VFSTAT64:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_uaddr_t user_vfstat_struct;
|
|
struct sos_fs_statfs kernel_vfstat_struct;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(user_vfstat_struct));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_vfstat(proc, path, len, & kernel_vfstat_struct);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
if (sizeof(kernel_vfstat_struct)
|
|
!= sos_memcpy_to_user(user_vfstat_struct,
|
|
(sos_vaddr_t) & kernel_vfstat_struct,
|
|
sizeof(kernel_vfstat_struct)))
|
|
retval = -SOS_EFAULT;
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_OPEN:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_ui32_t open_flags;
|
|
sos_ui32_t access_rights;
|
|
char * path;
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get4args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(open_flags),
|
|
SYSCALL_VAR32_PTR(access_rights));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_open(proc,
|
|
path, len,
|
|
open_flags,
|
|
access_rights,
|
|
& of);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_process_register_opened_file(proc, of, 0);
|
|
if (retval < 0)
|
|
{
|
|
sos_fs_close(of);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_CLOSE:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get1arg(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
retval = sos_process_unregister_opened_file(proc, fd);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_close(of);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_READ:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_uaddr_t uaddr_buf;
|
|
sos_uaddr_t uaddr_buflen;
|
|
sos_size_t kernel_buflen;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(uaddr_buf),
|
|
SYSCALL_VAR32_PTR(uaddr_buflen));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Retrieve the value for "buflen" */
|
|
retval = sos_memcpy_from_user((sos_vaddr_t)& kernel_buflen,
|
|
uaddr_buflen,
|
|
sizeof(kernel_buflen));
|
|
if (sizeof(kernel_buflen) != retval)
|
|
{
|
|
retval = -SOS_EFAULT;
|
|
break;
|
|
}
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual reading */
|
|
retval = sos_fs_read(of, uaddr_buf, & kernel_buflen);
|
|
|
|
/* Send successful number of bytes read to user */
|
|
sos_memcpy_to_user(uaddr_buflen,
|
|
(sos_vaddr_t)& kernel_buflen,
|
|
sizeof(kernel_buflen));
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_READDIR:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_uaddr_t uaddr_direntry;
|
|
struct sos_fs_dirent direntry;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(uaddr_direntry));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual readdir */
|
|
retval = sos_fs_readdir(of, & direntry);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Send direntry structure to user */
|
|
if (sizeof(direntry) != sos_memcpy_to_user(uaddr_direntry,
|
|
(sos_vaddr_t)& direntry,
|
|
sizeof(direntry)))
|
|
retval = -SOS_EFAULT;
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_WRITE:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_uaddr_t uaddr_buf;
|
|
sos_uaddr_t uaddr_buflen;
|
|
sos_size_t kernel_buflen;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(uaddr_buf),
|
|
SYSCALL_VAR32_PTR(uaddr_buflen));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Retrieve the value for "buflen" */
|
|
retval = sos_memcpy_from_user((sos_vaddr_t)& kernel_buflen,
|
|
uaddr_buflen,
|
|
sizeof(kernel_buflen));
|
|
if (sizeof(kernel_buflen) != retval)
|
|
{
|
|
retval = -SOS_EFAULT;
|
|
break;
|
|
}
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual writing */
|
|
retval = sos_fs_write(of, uaddr_buf, & kernel_buflen);
|
|
|
|
/* Send successful number of bytes written to user */
|
|
sos_memcpy_to_user(uaddr_buflen,
|
|
(sos_vaddr_t)& kernel_buflen,
|
|
sizeof(kernel_buflen));
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_SEEK64:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_uaddr_t uaddr_offset;
|
|
sos_seek_whence_t whence;
|
|
sos_lsoffset_t kernel_offset, result_position;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(uaddr_offset),
|
|
SYSCALL_VAR32_PTR(whence));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Retrieve the value for "buflen" */
|
|
retval = sos_memcpy_from_user((sos_vaddr_t)& kernel_offset,
|
|
uaddr_offset,
|
|
sizeof(kernel_offset));
|
|
if (sizeof(kernel_offset) != retval)
|
|
{
|
|
retval = -SOS_EFAULT;
|
|
break;
|
|
}
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual seek */
|
|
retval = sos_fs_seek(of, kernel_offset, whence, & result_position);
|
|
|
|
/* Send successful number of bytes written to user */
|
|
sos_memcpy_to_user(uaddr_offset,
|
|
(sos_vaddr_t)& result_position,
|
|
sizeof(kernel_offset));
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_FTRUNCATE64:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_lsoffset_t length;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(length));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual trunc */
|
|
retval = sos_fs_ftruncate(of, length);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_FSMMAP:
|
|
{
|
|
sos_uaddr_t ptr_hint_uaddr;
|
|
sos_uaddr_t hint_uaddr;
|
|
sos_size_t length;
|
|
sos_ui32_t prot;
|
|
sos_ui32_t flags;
|
|
int fd;
|
|
sos_ui32_t offs64_hi;
|
|
sos_ui32_t offs64_lo;
|
|
sos_luoffset_t offset_in_resource;
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get7args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(ptr_hint_uaddr),
|
|
SYSCALL_VAR32_PTR(length),
|
|
SYSCALL_VAR32_PTR(prot),
|
|
SYSCALL_VAR32_PTR(flags),
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(offs64_hi),
|
|
SYSCALL_VAR32_PTR(offs64_lo));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
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_fs_mmap(of, & hint_uaddr, length, prot, flags,
|
|
offset_in_resource);
|
|
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(sos_process_get_address_space(proc),
|
|
hint_uaddr, length);
|
|
retval = -SOS_EFAULT;
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_FSYNC:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get1arg(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual sync */
|
|
retval = sos_fs_fsync(of);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_FCNTL:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_ui32_t cmd, arg;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(cmd),
|
|
SYSCALL_VAR32_PTR(arg));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual fcntl */
|
|
retval = sos_fs_fcntl(of, cmd, arg);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_IOCTL:
|
|
{
|
|
struct sos_fs_opened_file * of;
|
|
struct sos_process * proc;
|
|
sos_ui32_t cmd, arg;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd),
|
|
SYSCALL_VAR32_PTR(cmd),
|
|
SYSCALL_VAR32_PTR(arg));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Do the actual ioctl */
|
|
retval = sos_fs_ioctl(of, cmd, arg);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_CREAT:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_ui32_t access_rights;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(access_rights));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_creat(proc,
|
|
path, len,
|
|
access_rights);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_LINK:
|
|
case SOS_SYSCALL_ID_RENAME:
|
|
{
|
|
sos_uaddr_t user_oldpath, user_newpath;
|
|
sos_size_t oldpathlen, newpathlen;
|
|
char * kernel_oldpath, * kernel_newpath;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get4args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_oldpath),
|
|
SYSCALL_VAR32_PTR(oldpathlen),
|
|
SYSCALL_VAR32_PTR(user_newpath),
|
|
SYSCALL_VAR32_PTR(newpathlen));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&kernel_oldpath,
|
|
user_oldpath,
|
|
oldpathlen, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&kernel_newpath,
|
|
user_newpath,
|
|
newpathlen, 0);
|
|
if (SOS_OK != retval)
|
|
{
|
|
sos_kfree((sos_vaddr_t) kernel_oldpath);
|
|
break;
|
|
}
|
|
|
|
if (syscall_id == SOS_SYSCALL_ID_LINK)
|
|
retval = sos_fs_link(proc,
|
|
kernel_oldpath, oldpathlen,
|
|
kernel_newpath, newpathlen);
|
|
else
|
|
retval = sos_fs_rename(proc,
|
|
kernel_oldpath, oldpathlen,
|
|
kernel_newpath, newpathlen);
|
|
sos_kfree((sos_vaddr_t)kernel_oldpath);
|
|
sos_kfree((sos_vaddr_t)kernel_newpath);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_UNLINK:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_unlink(proc,
|
|
path, len);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_SYMLINK:
|
|
{
|
|
sos_uaddr_t user_path, user_targetpath;
|
|
sos_size_t pathlen, targetpathlen;
|
|
char * kernel_path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get4args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_path),
|
|
SYSCALL_VAR32_PTR(pathlen),
|
|
SYSCALL_VAR32_PTR(user_targetpath),
|
|
SYSCALL_VAR32_PTR(targetpathlen));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&kernel_path,
|
|
user_path,
|
|
pathlen, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_symlink(proc,
|
|
kernel_path, pathlen,
|
|
user_targetpath, targetpathlen);
|
|
sos_kfree((sos_vaddr_t)kernel_path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_MKNOD:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_ui32_t access_rights;
|
|
int type;
|
|
char * path;
|
|
struct sos_fs_dev_id_t dev_id;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get6args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(type),
|
|
SYSCALL_VAR32_PTR(access_rights),
|
|
SYSCALL_VAR32_PTR(dev_id.device_class),
|
|
SYSCALL_VAR32_PTR(dev_id.device_instance));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
switch (type)
|
|
{
|
|
case SOS_FS_NODE_REGULAR_FILE:
|
|
retval = sos_fs_creat(proc, path, len, access_rights);
|
|
break;
|
|
|
|
case SOS_FS_NODE_DIRECTORY:
|
|
retval = sos_fs_mkdir(proc, path, len, access_rights);
|
|
break;
|
|
|
|
case SOS_FS_NODE_SYMLINK:
|
|
retval = -SOS_ENOSUP;
|
|
break;
|
|
|
|
case SOS_FS_NODE_DEVICE_CHAR:
|
|
case SOS_FS_NODE_DEVICE_BLOCK:
|
|
retval = sos_fs_mknod(proc,
|
|
path, len, type, access_rights, &dev_id);
|
|
break;
|
|
|
|
default:
|
|
retval = -SOS_EINVAL;
|
|
break;
|
|
}
|
|
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_MKDIR:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_ui32_t access_rights;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(access_rights));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_mkdir(proc,
|
|
path, len, access_rights);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_RMDIR:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_rmdir(proc, path, len);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_CHMOD:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_ui32_t access_rights;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get3args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(access_rights));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_chmod(proc, path, len, access_rights);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_STAT64:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
sos_uaddr_t user_stat_struct;
|
|
struct sos_fs_stat kernel_stat_struct;
|
|
int nofollow;
|
|
char * path;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get4args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len),
|
|
SYSCALL_VAR32_PTR(nofollow),
|
|
SYSCALL_VAR32_PTR(user_stat_struct));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_stat(proc, path, len, nofollow, & kernel_stat_struct);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
if (sizeof(kernel_stat_struct)
|
|
!= sos_memcpy_to_user(user_stat_struct,
|
|
(sos_vaddr_t) & kernel_stat_struct,
|
|
sizeof(kernel_stat_struct)))
|
|
retval = -SOS_EFAULT;
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_CHROOT:
|
|
case SOS_SYSCALL_ID_CHDIR:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
char * path;
|
|
struct sos_fs_opened_file * of, * old_of;
|
|
struct sos_process * proc;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get2args(user_ctxt,
|
|
SYSCALL_VAR32_PTR(user_str),
|
|
SYSCALL_VAR32_PTR(len));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(&path, user_str, len, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_fs_open(proc,
|
|
path, len,
|
|
SOS_FS_OPEN_DIRECTORY,
|
|
SOS_FS_OPEN_READ,
|
|
& of);
|
|
sos_kfree((sos_vaddr_t)path);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
if (syscall_id == SOS_SYSCALL_ID_CHROOT)
|
|
retval = sos_process_chroot(proc, of, & old_of);
|
|
else
|
|
retval = sos_process_chdir(proc, of, & old_of);
|
|
|
|
if (retval < 0)
|
|
{
|
|
sos_fs_close(of);
|
|
break;
|
|
}
|
|
|
|
sos_fs_close(old_of);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_FCHDIR:
|
|
{
|
|
struct sos_fs_opened_file * of, * new_of, * old_of;
|
|
struct sos_process * proc;
|
|
int fd;
|
|
|
|
proc = sos_thread_get_current()->process;
|
|
retval = sos_syscall_get1arg(user_ctxt,
|
|
SYSCALL_VAR32_PTR(fd));
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
of = sos_process_get_opened_file(proc, fd);
|
|
if (NULL == of)
|
|
{
|
|
retval = -SOS_EBADF;
|
|
break;
|
|
}
|
|
|
|
/* Duplicate this FD */
|
|
retval = sos_fs_duplicate_opened_file(of, proc, & new_of);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
/* Do the actual chdir */
|
|
retval = sos_process_chdir(proc, new_of, & old_of);
|
|
if (retval < 0)
|
|
{
|
|
sos_fs_close(new_of);
|
|
break;
|
|
}
|
|
|
|
sos_fs_close(old_of);
|
|
}
|
|
break;
|
|
|
|
case SOS_SYSCALL_ID_BOCHS_WRITE:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
sos_size_t len;
|
|
char * str;
|
|
retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(& str, user_str, len + 1, 0);
|
|
if (SOS_OK == retval)
|
|
{
|
|
sos_bochs_printf("THR 0x%x: ",
|
|
(unsigned)sos_thread_get_current());
|
|
retval = sos_bochs_putstring(str);
|
|
retval = len;
|
|
sos_kfree((sos_vaddr_t)str);
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
/* ***********************************************
|
|
* Debug syscalls (will be removed in the future)
|
|
*/
|
|
|
|
|
|
/**
|
|
* Syscall 4012: hexdump of a user-space memory region
|
|
* args: addr_start size, retval=ignored
|
|
*/
|
|
case 4012:
|
|
{
|
|
sos_uaddr_t user_str;
|
|
unsigned int len;
|
|
unsigned char * str;
|
|
|
|
retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
str = (unsigned char*)sos_kmalloc(len, 0);
|
|
if (str)
|
|
{
|
|
sos_bochs_printf("THR %p, Hexdump(0x%x, %d):\n",
|
|
sos_thread_get_current(), user_str, len);
|
|
retval = sos_memcpy_from_user((sos_vaddr_t) str, user_str, len);
|
|
sos_bochs_printf(" (Successfully copied %d out of %d)\n",
|
|
retval, len);
|
|
if (retval > 0)
|
|
sos_bochs_hexdump(str, retval);
|
|
|
|
sos_kfree((sos_vaddr_t)str);
|
|
}
|
|
else
|
|
retval = -SOS_ENOMEM;
|
|
}
|
|
break;
|
|
|
|
|
|
/**
|
|
* Syscall 4004: lists the VR of the current thread's address space
|
|
* args: debug_string, retval=ignored
|
|
*/
|
|
case 4004:
|
|
{
|
|
sos_uaddr_t ustr;
|
|
char * kstr;
|
|
struct sos_umem_vmm_as * my_as;
|
|
|
|
retval = sos_syscall_get1arg(user_ctxt, & ustr);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
retval = sos_strndup_from_user(& kstr, ustr, 256, 0);
|
|
if (SOS_OK != retval)
|
|
break;
|
|
|
|
extern void sos_dump_as(const struct sos_umem_vmm_as *, const char *);
|
|
my_as
|
|
= sos_process_get_address_space(sos_thread_get_current()->process);
|
|
sos_dump_as(my_as, kstr);
|
|
sos_kfree((sos_vaddr_t)kstr);
|
|
}
|
|
break;
|
|
|
|
|
|
/**
|
|
* Syscall 4008: dump the list of processes in the system
|
|
* args: none, retval=ignored
|
|
*/
|
|
case 4008:
|
|
{
|
|
extern void sos_process_dumplist(void);
|
|
sos_process_dumplist();
|
|
retval = SOS_OK;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sos_bochs_printf("Syscall: UNKNOWN[%d]\n", syscall_id);
|
|
retval = -SOS_ENOSUP;
|
|
}
|
|
|
|
return retval;
|
|
}
|