Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-serial
[pandora-kernel.git] / arch / um / kernel / syscall.c
index 1429c13..f5ed862 100644 (file)
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
+#include "linux/sched.h"
+#include "linux/file.h"
+#include "linux/smp_lock.h"
+#include "linux/mm.h"
+#include "linux/utsname.h"
+#include "linux/msg.h"
+#include "linux/shm.h"
+#include "linux/sys.h"
+#include "linux/syscalls.h"
+#include "linux/unistd.h"
+#include "linux/slab.h"
+#include "linux/utime.h"
+#include "asm/mman.h"
+#include "asm/uaccess.h"
 #include "kern_util.h"
-#include "syscall.h"
-#include "os.h"
+#include "user_util.h"
+#include "sysdep/syscalls.h"
+#include "mode_kern.h"
+#include "choose-mode.h"
 
-struct {
-       int syscall;
-       int pid;
-       long result;
-       unsigned long long start;
-       unsigned long long end;
-} syscall_record[1024];
+/*  Unlocked, I don't care if this is a bit off */
+int nsyscalls = 0;
 
-int record_syscall_start(int syscall)
+long sys_fork(void)
 {
-       int max, index;
+       long ret;
 
-       max = sizeof(syscall_record)/sizeof(syscall_record[0]);
-       index = next_syscall_index(max);
+       current->thread.forking = 1;
+       ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+                     &current->thread.regs, 0, NULL, NULL);
+       current->thread.forking = 0;
+       return(ret);
+}
+
+long sys_vfork(void)
+{
+       long ret;
+
+       current->thread.forking = 1;
+       ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+                     UPT_SP(&current->thread.regs.regs),
+                     &current->thread.regs, 0, NULL, NULL);
+       current->thread.forking = 0;
+       return(ret);
+}
+
+/* common code for old and new mmaps */
+long sys_mmap2(unsigned long addr, unsigned long len,
+              unsigned long prot, unsigned long flags,
+              unsigned long fd, unsigned long pgoff)
+{
+       long error = -EBADF;
+       struct file * file = NULL;
+
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+       if (!(flags & MAP_ANONYMOUS)) {
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
+       down_write(&current->mm->mmap_sem);
+       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
+       if (file)
+               fput(file);
+ out:
+       return error;
+}
+
+long old_mmap(unsigned long addr, unsigned long len,
+             unsigned long prot, unsigned long flags,
+             unsigned long fd, unsigned long offset)
+{
+       long err = -EINVAL;
+       if (offset & ~PAGE_MASK)
+               goto out;
+
+       err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+ out:
+       return err;
+}
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+long sys_pipe(unsigned long __user * fildes)
+{
+        int fd[2];
+        long error;
 
-       syscall_record[index].syscall = syscall;
-       syscall_record[index].pid = current_pid();
-       syscall_record[index].result = 0xdeadbeef;
-       syscall_record[index].start = os_usecs();
-       return(index);
+        error = do_pipe(fd);
+        if (!error) {
+               if (copy_to_user(fildes, fd, sizeof(fd)))
+                        error = -EFAULT;
+        }
+        return error;
 }
 
-void record_syscall_end(int index, long result)
+
+long sys_uname(struct old_utsname __user * name)
 {
-       syscall_record[index].result = result;
-       syscall_record[index].end = os_usecs();
+       long err;
+       if (!name)
+               return -EFAULT;
+       down_read(&uts_sem);
+       err = copy_to_user(name, utsname(), sizeof (*name));
+       up_read(&uts_sem);
+       return err?-EFAULT:0;
+}
+
+long sys_olduname(struct oldold_utsname __user * name)
+{
+       long error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+               return -EFAULT;
+
+       down_read(&uts_sem);
+
+       error = __copy_to_user(&name->sysname, &utsname()->sysname,
+                              __OLD_UTS_LEN);
+       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->release, &utsname()->release,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->release + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->version, &utsname()->version,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->version + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->machine, &utsname()->machine,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+
+       up_read(&uts_sem);
+
+       error = error ? -EFAULT : 0;
+
+       return error;
+}
+
+DEFINE_SPINLOCK(syscall_lock);
+
+static int syscall_index = 0;
+
+int next_syscall_index(int limit)
+{
+       int ret;
+
+       spin_lock(&syscall_lock);
+       ret = syscall_index;
+       if(++syscall_index == limit)
+               syscall_index = 0;
+       spin_unlock(&syscall_lock);
+       return(ret);
+}
+
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+       mm_segment_t fs;
+       int ret;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = um_execve(filename, argv, envp);
+       set_fs(fs);
+
+       return ret;
 }