root/arch/mips/kernel/syscall.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_pipe
  2. sys_mmap
  3. sys_idle
  4. sys_fork
  5. sys_clone
  6. sys_execve
  7. sys_syscall
  8. do_sys

   1 /*
   2  * MIPS specific syscall handling functions and syscalls
   3  *
   4  * This file is subject to the terms and conditions of the GNU General Public
   5  * License.  See the file "COPYING" in the main directory of this archive
   6  * for more details.
   7  *
   8  * Copyright (C) 1995 by Ralf Baechle
   9  */
  10 #include <linux/linkage.h>
  11 #include <linux/mm.h>
  12 #include <linux/mman.h>
  13 #include <linux/sched.h>
  14 #include <linux/unistd.h>
  15 #include <asm/ptrace.h>
  16 #include <asm/segment.h>
  17 #include <asm/signal.h>
  18 
  19 extern asmlinkage void syscall_trace(void);
  20 typedef asmlinkage int (*syscall_t)(void *a0,...);
  21 extern asmlinkage int do_syscalls(struct pt_regs *regs, syscall_t fun,
  22                                   int narg);
  23 extern syscall_t sys_call_table[];
  24 extern unsigned char sys_narg_table[];
  25 
  26 asmlinkage int sys_pipe(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28         int fd[2];
  29         int error;
  30 
  31         error = do_pipe(fd);
  32         if (error)
  33                 return error;
  34         regs->reg2 = fd[0];
  35         regs->reg3 = fd[1];
  36         return 0;
  37 }
  38 
  39 asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
     /* [previous][next][first][last][top][bottom][index][help] */
  40                                   int flags, int fd, off_t offset)
  41 {
  42         struct file * file = NULL;
  43 
  44         if (flags & MAP_RENAME) {
  45                 if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  46                         return -EBADF;
  47         }
  48         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
  49 
  50         return do_mmap(file, addr, len, prot, flags, offset);
  51 }
  52 
  53 asmlinkage int sys_idle(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55         if (current->pid != 0)
  56                 return -EPERM;
  57 
  58         /* endless idle loop with no priority at all */
  59         current->counter = -100;
  60         for (;;) {
  61                 /*
  62                  * R4[26]00 have wait, R4[04]00 don't.
  63                  */
  64                 if (wait_available && !need_resched)
  65                         __asm__(".set\tmips3\n\t"
  66                                 "wait\n\t"
  67                                 ".set\tmips0\n\t");
  68                 schedule();
  69         }
  70 }
  71 
  72 asmlinkage int sys_fork(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         return do_fork(SIGCHLD, regs->reg29, regs);
  75 }
  76 
  77 asmlinkage int sys_clone(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79         unsigned long clone_flags;
  80         unsigned long newsp;
  81 
  82         clone_flags = regs->reg4;
  83         newsp = regs->reg5;
  84         if (!newsp)
  85                 newsp = regs->reg29;
  86         return do_fork(clone_flags, newsp, regs);
  87 }
  88 
  89 /*
  90  * sys_execve() executes a new program.
  91  */
  92 asmlinkage int sys_execve(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         int error;
  95         char * filename;
  96 
  97         error = getname((char *) regs->reg4, &filename);
  98         if (error)
  99                 return error;
 100         error = do_execve(filename, (char **) regs->reg5,
 101                           (char **) regs->reg6, regs);
 102         putname(filename);
 103         return error;
 104 }
 105 
 106 /*
 107  * Do the indirect syscall syscall.
 108  */
 109 asmlinkage int sys_syscall(unsigned long a0, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
 110                            unsigned long a3, unsigned long a4, unsigned long a5,
 111                            unsigned long a6)
 112 {
 113         syscall_t syscall;
 114 
 115         if (a0 > __NR_Linux + __NR_Linux_syscalls)
 116                 return -ENOSYS;
 117 
 118         syscall = sys_call_table[a0];
 119         /*
 120          * Prevent stack overflow by recursive
 121          * syscall(__NR_syscall, __NR_syscall,...);
 122          */
 123         if (syscall == (syscall_t) sys_syscall)
 124                 return -EINVAL;
 125 
 126         if (syscall == NULL)
 127                 return -ENOSYS;
 128 
 129         return syscall((void *)a0, a1, a2, a3, a4, a5, a6);
 130 }
 131 
 132 void do_sys(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134         unsigned long syscallnr, usp;
 135         syscall_t syscall;
 136         int errno, narg;
 137 
 138         /*
 139          * Compute the return address;
 140          */
 141         if (regs->cp0_cause & CAUSEF_BD)
 142         {
 143                 /*
 144                  * This syscall is in a branch delay slot.  Since we don't do
 145                  * branch delay slot handling we would get a process trying
 146                  * to do syscalls ever and ever again.  So better zap it.
 147                  */
 148                 printk("%s: syscall in branch delay slot.\n", current->comm);
 149                 current->sig->action[SIGILL-1].sa_handler = NULL;
 150                 current->blocked &= ~(1<<(SIGILL-1));
 151                 send_sig(SIGILL, current, 1);
 152                 return;
 153         }
 154         regs->cp0_epc += 4;
 155 
 156         syscallnr = regs->reg2;
 157         if (syscallnr > (__NR_Linux + __NR_Linux_syscalls))
 158                 goto illegal_syscall;
 159 
 160         syscall = sys_call_table[syscallnr];
 161         if (syscall == NULL)
 162                 goto illegal_syscall;
 163 
 164         narg = sys_narg_table[syscallnr];
 165         if (narg > 4)
 166         {
 167                 /*
 168                  * Verify that we can savely get the additional parameters
 169                  * from the user stack.  Of course I could read the params
 170                  * from unaligned addresses ...  Consider this a programming
 171                  * course caliber .45.
 172                  */
 173                 usp = regs->reg29;
 174                 if (usp & 3)
 175                 {
 176                         printk("unaligned usp\n");
 177                         send_sig(SIGSEGV, current, 1);
 178                         regs->reg2 = EFAULT;
 179                         regs->reg7 = 1;
 180                         return;
 181                 }
 182                 errno = verify_area(VERIFY_READ, (void *) (usp + 16),
 183                                     (narg - 4) * sizeof(unsigned long));
 184                 if (errno < 0)
 185                         goto bad_syscall;
 186         }
 187 
 188         if ((current->flags & PF_TRACESYS) == 0)
 189         {
 190                 errno = do_syscalls(regs, syscall, narg);
 191                 if (errno < 0 || current->errno)
 192                         goto bad_syscall;
 193 
 194                 regs->reg2 = errno;
 195                 regs->reg7 = 0;
 196         }
 197         else
 198         {
 199                 syscall_trace();
 200 
 201                 errno = do_syscalls(regs, syscall, narg);
 202                 if (errno < 0 || current->errno)
 203                 {
 204                         regs->reg2 = -errno;
 205                         regs->reg7 = 1;
 206                 }
 207                 else
 208                 {
 209                         regs->reg2 = errno;
 210                         regs->reg7 = 0;
 211                 }
 212 
 213                 syscall_trace();
 214         }
 215         return;
 216 
 217 bad_syscall:
 218         regs->reg2 = -errno;
 219         regs->reg7 = 1;
 220         return;
 221 illegal_syscall:
 222         regs->reg2 = ENOSYS;
 223         regs->reg7 = 1;
 224         return;
 225 }

/* [previous][next][first][last][top][bottom][index][help] */