1/* 2 * linux/arch/m68knommu/kernel/sys_m68k.c 3 * 4 * This file contains various random system calls that 5 * have a non-standard calling sequence on the Linux/m68k 6 * platform. 7 */ 8 9#include <linux/errno.h> 10#include <linux/sched.h> 11#include <linux/mm.h> 12#include <linux/smp.h> 13#include <linux/sem.h> 14#include <linux/msg.h> 15#include <linux/shm.h> 16#include <linux/stat.h> 17#include <linux/syscalls.h> 18#include <linux/mman.h> 19#include <linux/file.h> 20#include <linux/utsname.h> 21 22#include <asm/setup.h> 23#include <asm/uaccess.h> 24#include <asm/cachectl.h> 25#include <asm/traps.h> 26#include <asm/ipc.h> 27#include <asm/cacheflush.h> 28#include <asm/unistd.h> 29 30/* 31 * sys_pipe() is the normal C calling standard for creating 32 * a pipe. It's not the way unix traditionally does this, though. 33 */ 34asmlinkage int sys_pipe(unsigned long * fildes) 35{ 36 int fd[2]; 37 int error; 38 39 error = do_pipe(fd); 40 if (!error) { 41 if (copy_to_user(fildes, fd, 2*sizeof(int))) 42 error = -EFAULT; 43 } 44 return error; 45} 46 47/* common code for old and new mmaps */ 48static inline long do_mmap2( 49 unsigned long addr, unsigned long len, 50 unsigned long prot, unsigned long flags, 51 unsigned long fd, unsigned long pgoff) 52{ 53 int error = -EBADF; 54 struct file * file = NULL; 55 56 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 57 if (!(flags & MAP_ANONYMOUS)) { 58 file = fget(fd); 59 if (!file) 60 goto out; 61 } 62 63 down_write(¤t->mm->mmap_sem); 64 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 65 up_write(¤t->mm->mmap_sem); 66 67 if (file) 68 fput(file); 69out: 70 return error; 71} 72 73asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 74 unsigned long prot, unsigned long flags, 75 unsigned long fd, unsigned long pgoff) 76{ 77 return do_mmap2(addr, len, prot, flags, fd, pgoff); 78} 79 80/* 81 * Perform the select(nd, in, out, ex, tv) and mmap() system 82 * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to 83 * handle more than 4 system call parameters, so these system calls 84 * used a memory block for parameter passing.. 85 */ 86 87struct mmap_arg_struct { 88 unsigned long addr; 89 unsigned long len; 90 unsigned long prot; 91 unsigned long flags; 92 unsigned long fd; 93 unsigned long offset; 94}; 95 96asmlinkage int old_mmap(struct mmap_arg_struct *arg) 97{ 98 struct mmap_arg_struct a; 99 int error = -EFAULT; 100 101 if (copy_from_user(&a, arg, sizeof(a))) 102 goto out; 103 104 error = -EINVAL; 105 if (a.offset & ~PAGE_MASK) 106 goto out; 107 108 a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 109 110 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); 111out: 112 return error; 113} 114 115struct sel_arg_struct { 116 unsigned long n; 117 fd_set *inp, *outp, *exp; 118 struct timeval *tvp; 119}; 120 121asmlinkage int old_select(struct sel_arg_struct *arg) 122{ 123 struct sel_arg_struct a; 124 125 if (copy_from_user(&a, arg, sizeof(a))) 126 return -EFAULT; 127 /* sys_select() does the appropriate kernel locking */ 128 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); 129} 130 131/* 132 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 133 * 134 * This is really horribly ugly. 135 */ 136asmlinkage int sys_ipc (uint call, int first, int second, 137 int third, void *ptr, long fifth) 138{ 139 int version, ret; 140 141 version = call >> 16; /* hack for backward compatibility */ 142 call &= 0xffff; 143 144 if (call <= SEMCTL) 145 switch (call) { 146 case SEMOP: 147 return sys_semop (first, (struct sembuf *)ptr, second); 148 case SEMGET: 149 return sys_semget (first, second, third); 150 case SEMCTL: { 151 union semun fourth; 152 if (!ptr) 153 return -EINVAL; 154 if (get_user(fourth.__pad, (void **) ptr)) 155 return -EFAULT; 156 return sys_semctl (first, second, third, fourth); 157 } 158 default: 159 return -EINVAL; 160 } 161 if (call <= MSGCTL) 162 switch (call) { 163 case MSGSND: 164 return sys_msgsnd (first, (struct msgbuf *) ptr, 165 second, third); 166 case MSGRCV: 167 switch (version) { 168 case 0: { 169 struct ipc_kludge tmp; 170 if (!ptr) 171 return -EINVAL; 172 if (copy_from_user (&tmp, 173 (struct ipc_kludge *)ptr, 174 sizeof (tmp))) 175 return -EFAULT; 176 return sys_msgrcv (first, tmp.msgp, second, 177 tmp.msgtyp, third); 178 } 179 default: 180 return sys_msgrcv (first, 181 (struct msgbuf *) ptr, 182 second, fifth, third); 183 } 184 case MSGGET: 185 return sys_msgget ((key_t) first, second); 186 case MSGCTL: 187 return sys_msgctl (first, second, 188 (struct msqid_ds *) ptr); 189 default: 190 return -EINVAL; 191 } 192 if (call <= SHMCTL) 193 switch (call) { 194 case SHMAT: 195 switch (version) { 196 default: { 197 ulong raddr; 198 ret = do_shmat (first, ptr, second, &raddr); 199 if (ret) 200 return ret; 201 return put_user (raddr, (ulong __user *) third); 202 } 203 } 204 case SHMDT: 205 return sys_shmdt (ptr); 206 case SHMGET: 207 return sys_shmget (first, second, third); 208 case SHMCTL: 209 return sys_shmctl (first, second, ptr); 210 default: 211 return -ENOSYS; 212 } 213 214 return -EINVAL; 215} 216 217/* sys_cacheflush -- flush (part of) the processor cache. */ 218asmlinkage int 219sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) 220{ 221 flush_cache_all(); 222 return(0); 223} 224 225asmlinkage int sys_getpagesize(void) 226{ 227 return PAGE_SIZE; 228} 229 230/* 231 * Do a system call from kernel instead of calling sys_execve so we 232 * end up with proper pt_regs. 233 */ 234int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 235{ 236 register long __res asm ("%d0") = __NR_execve; 237 register long __a asm ("%d1") = (long)(filename); 238 register long __b asm ("%d2") = (long)(argv); 239 register long __c asm ("%d3") = (long)(envp); 240 asm volatile ("trap #0" : "+d" (__res) 241 : "d" (__a), "d" (__b), "d" (__c)); 242 return __res; 243} 244