1 /* 2 * Implementation of various system calls for Linux/PowerPC 3 * 4 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 5 * 6 * Derived from "arch/i386/kernel/sys_i386.c" 7 * Adapted from the i386 version by Gary Thomas 8 * Modified by Cort Dougan (cort@cs.nmt.edu) 9 * and Paul Mackerras (paulus@cs.anu.edu.au). 10 * 11 * This file contains various random system calls that 12 * have a non-standard calling sequence on the Linux/PPC 13 * platform. 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * as published by the Free Software Foundation; either version 18 * 2 of the License, or (at your option) any later version. 19 * 20 */ 21 22 #include <linux/errno.h> 23 #include <linux/sched.h> 24 #include <linux/syscalls.h> 25 #include <linux/mm.h> 26 #include <linux/smp.h> 27 #include <linux/smp_lock.h> 28 #include <linux/sem.h> 29 #include <linux/msg.h> 30 #include <linux/shm.h> 31 #include <linux/stat.h> 32 #include <linux/mman.h> 33 #include <linux/sys.h> 34 #include <linux/ipc.h> 35 #include <linux/utsname.h> 36 #include <linux/file.h> 37 #include <linux/init.h> 38 #include <linux/personality.h> 39 40 #include <asm/uaccess.h> 41 #include <asm/ipc.h> 42 #include <asm/semaphore.h> 43 #include <asm/time.h> 44 #include <asm/unistd.h> 45 46 extern unsigned long wall_jiffies; 47 48 49 /* 50 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 51 * 52 * This is really horribly ugly. 53 */ 54 int sys_ipc(uint call, int first, unsigned long second, long third, 55 void __user *ptr, long fifth) 56 { 57 int version, ret; 58 59 version = call >> 16; /* hack for backward compatibility */ 60 call &= 0xffff; 61 62 ret = -ENOSYS; 63 switch (call) { 64 case SEMOP: 65 ret = sys_semtimedop(first, (struct sembuf __user *)ptr, 66 (unsigned)second, NULL); 67 break; 68 case SEMTIMEDOP: 69 ret = sys_semtimedop(first, (struct sembuf __user *)ptr, 70 (unsigned)second, 71 (const struct timespec __user *) fifth); 72 break; 73 case SEMGET: 74 ret = sys_semget (first, (int)second, third); 75 break; 76 case SEMCTL: { 77 union semun fourth; 78 79 ret = -EINVAL; 80 if (!ptr) 81 break; 82 if ((ret = get_user(fourth.__pad, (void __user * __user *)ptr))) 83 break; 84 ret = sys_semctl(first, (int)second, third, fourth); 85 break; 86 } 87 case MSGSND: 88 ret = sys_msgsnd(first, (struct msgbuf __user *)ptr, 89 (size_t)second, third); 90 break; 91 case MSGRCV: 92 switch (version) { 93 case 0: { 94 struct ipc_kludge tmp; 95 96 ret = -EINVAL; 97 if (!ptr) 98 break; 99 if ((ret = copy_from_user(&tmp, 100 (struct ipc_kludge __user *) ptr, 101 sizeof (tmp)) ? -EFAULT : 0)) 102 break; 103 ret = sys_msgrcv(first, tmp.msgp, (size_t) second, 104 tmp.msgtyp, third); 105 break; 106 } 107 default: 108 ret = sys_msgrcv (first, (struct msgbuf __user *) ptr, 109 (size_t)second, fifth, third); 110 break; 111 } 112 break; 113 case MSGGET: 114 ret = sys_msgget((key_t)first, (int)second); 115 break; 116 case MSGCTL: 117 ret = sys_msgctl(first, (int)second, 118 (struct msqid_ds __user *)ptr); 119 break; 120 case SHMAT: { 121 ulong raddr; 122 ret = do_shmat(first, (char __user *)ptr, (int)second, &raddr); 123 if (ret) 124 break; 125 ret = put_user(raddr, (ulong __user *) third); 126 break; 127 } 128 case SHMDT: 129 ret = sys_shmdt((char __user *)ptr); 130 break; 131 case SHMGET: 132 ret = sys_shmget(first, (size_t)second, third); 133 break; 134 case SHMCTL: 135 ret = sys_shmctl(first, (int)second, 136 (struct shmid_ds __user *)ptr); 137 break; 138 } 139 140 return ret; 141 } 142 143 /* 144 * sys_pipe() is the normal C calling standard for creating 145 * a pipe. It's not the way unix traditionally does this, though. 146 */ 147 int sys_pipe(int __user *fildes) 148 { 149 int fd[2]; 150 int error; 151 152 error = do_pipe(fd); 153 if (!error) { 154 if (copy_to_user(fildes, fd, 2*sizeof(int))) 155 error = -EFAULT; 156 } 157 return error; 158 } 159 160 static inline unsigned long do_mmap2(unsigned long addr, size_t len, 161 unsigned long prot, unsigned long flags, 162 unsigned long fd, unsigned long off, int shift) 163 { 164 struct file * file = NULL; 165 unsigned long ret = -EINVAL; 166 167 if (shift) { 168 if (off & ((1 << shift) - 1)) 169 goto out; 170 off >>= shift; 171 } 172 173 ret = -EBADF; 174 if (!(flags & MAP_ANONYMOUS)) { 175 if (!(file = fget(fd))) 176 goto out; 177 } 178 179 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 180 181 down_write(¤t->mm->mmap_sem); 182 ret = do_mmap_pgoff(file, addr, len, prot, flags, off); 183 up_write(¤t->mm->mmap_sem); 184 if (file) 185 fput(file); 186 out: 187 return ret; 188 } 189 190 unsigned long sys_mmap2(unsigned long addr, size_t len, 191 unsigned long prot, unsigned long flags, 192 unsigned long fd, unsigned long pgoff) 193 { 194 return do_mmap2(addr, len, prot, flags, fd, pgoff, PAGE_SHIFT-12); 195 } 196 197 unsigned long sys_mmap(unsigned long addr, size_t len, 198 unsigned long prot, unsigned long flags, 199 unsigned long fd, off_t offset) 200 { 201 return do_mmap2(addr, len, prot, flags, fd, offset, PAGE_SHIFT); 202 } 203 204 #ifdef CONFIG_PPC32 205 /* 206 * Due to some executables calling the wrong select we sometimes 207 * get wrong args. This determines how the args are being passed 208 * (a single ptr to them all args passed) then calls 209 * sys_select() with the appropriate args. -- Cort 210 */ 211 int 212 ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) 213 { 214 if ( (unsigned long)n >= 4096 ) 215 { 216 unsigned long __user *buffer = (unsigned long __user *)n; 217 if (!access_ok(VERIFY_READ, buffer, 5*sizeof(unsigned long)) 218 || __get_user(n, buffer) 219 || __get_user(inp, ((fd_set __user * __user *)(buffer+1))) 220 || __get_user(outp, ((fd_set __user * __user *)(buffer+2))) 221 || __get_user(exp, ((fd_set __user * __user *)(buffer+3))) 222 || __get_user(tvp, ((struct timeval __user * __user *)(buffer+4)))) 223 return -EFAULT; 224 } 225 return sys_select(n, inp, outp, exp, tvp); 226 } 227 #endif 228 229 #ifdef CONFIG_PPC64 230 long ppc64_personality(unsigned long personality) 231 { 232 long ret; 233 234 if (personality(current->personality) == PER_LINUX32 235 && personality == PER_LINUX) 236 personality = PER_LINUX32; 237 ret = sys_personality(personality); 238 if (ret == PER_LINUX32) 239 ret = PER_LINUX; 240 return ret; 241 } 242 #endif 243 244 #ifdef CONFIG_PPC64 245 #define OVERRIDE_MACHINE (personality(current->personality) == PER_LINUX32) 246 #else 247 #define OVERRIDE_MACHINE 0 248 #endif 249 250 static inline int override_machine(char *mach) 251 { 252 if (OVERRIDE_MACHINE) { 253 /* change ppc64 to ppc */ 254 if (__put_user(0, mach+3) || __put_user(0, mach+4)) 255 return -EFAULT; 256 } 257 return 0; 258 } 259 260 long ppc_newuname(struct new_utsname __user * name) 261 { 262 int err = 0; 263 264 down_read(&uts_sem); 265 if (copy_to_user(name, &system_utsname, sizeof(*name))) 266 err = -EFAULT; 267 up_read(&uts_sem); 268 if (!err) 269 err = override_machine(name->machine); 270 return err; 271 } 272 273 int sys_uname(struct old_utsname __user *name) 274 { 275 int err = 0; 276 277 down_read(&uts_sem); 278 if (copy_to_user(name, &system_utsname, sizeof(*name))) 279 err = -EFAULT; 280 up_read(&uts_sem); 281 if (!err) 282 err = override_machine(name->machine); 283 return err; 284 } 285 286 int sys_olduname(struct oldold_utsname __user *name) 287 { 288 int error; 289 290 if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) 291 return -EFAULT; 292 293 down_read(&uts_sem); 294 error = __copy_to_user(&name->sysname, &system_utsname.sysname, 295 __OLD_UTS_LEN); 296 error |= __put_user(0, name->sysname + __OLD_UTS_LEN); 297 error |= __copy_to_user(&name->nodename, &system_utsname.nodename, 298 __OLD_UTS_LEN); 299 error |= __put_user(0, name->nodename + __OLD_UTS_LEN); 300 error |= __copy_to_user(&name->release, &system_utsname.release, 301 __OLD_UTS_LEN); 302 error |= __put_user(0, name->release + __OLD_UTS_LEN); 303 error |= __copy_to_user(&name->version, &system_utsname.version, 304 __OLD_UTS_LEN); 305 error |= __put_user(0, name->version + __OLD_UTS_LEN); 306 error |= __copy_to_user(&name->machine, &system_utsname.machine, 307 __OLD_UTS_LEN); 308 error |= override_machine(name->machine); 309 up_read(&uts_sem); 310 311 return error? -EFAULT: 0; 312 } 313 314 #ifdef CONFIG_PPC64 315 time_t sys64_time(time_t __user * tloc) 316 { 317 time_t secs; 318 time_t usecs; 319 320 long tb_delta = tb_ticks_since(tb_last_stamp); 321 tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; 322 323 secs = xtime.tv_sec; 324 usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec; 325 while (usecs >= USEC_PER_SEC) { 326 ++secs; 327 usecs -= USEC_PER_SEC; 328 } 329 330 if (tloc) { 331 if (put_user(secs,tloc)) 332 secs = -EFAULT; 333 } 334 335 return secs; 336 } 337 #endif 338 339 long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, 340 u32 len_high, u32 len_low) 341 { 342 return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, 343 (u64)len_high << 32 | len_low, advice); 344 } 345 346 void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5, 347 unsigned long r6, unsigned long r7, unsigned long r8, 348 struct pt_regs *regs) 349 { 350 printk("syscall %ld(%lx, %lx, %lx, %lx, %lx, %lx) regs=%p current=%p" 351 " cpu=%d\n", regs->gpr[0], r3, r4, r5, r6, r7, r8, regs, 352 current, smp_processor_id()); 353 } 354 355 void do_show_syscall_exit(unsigned long r3) 356 { 357 printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id()); 358 } 359