1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * linux/arch/sh/kernel/sys_sh.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * This file contains various random system calls that 5*1da177e4SLinus Torvalds * have a non-standard calling sequence on the Linux/SuperH 6*1da177e4SLinus Torvalds * platform. 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * Taken from i386 version. 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds 11*1da177e4SLinus Torvalds #include <linux/errno.h> 12*1da177e4SLinus Torvalds #include <linux/sched.h> 13*1da177e4SLinus Torvalds #include <linux/mm.h> 14*1da177e4SLinus Torvalds #include <linux/smp.h> 15*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 16*1da177e4SLinus Torvalds #include <linux/sem.h> 17*1da177e4SLinus Torvalds #include <linux/msg.h> 18*1da177e4SLinus Torvalds #include <linux/shm.h> 19*1da177e4SLinus Torvalds #include <linux/stat.h> 20*1da177e4SLinus Torvalds #include <linux/syscalls.h> 21*1da177e4SLinus Torvalds #include <linux/mman.h> 22*1da177e4SLinus Torvalds #include <linux/file.h> 23*1da177e4SLinus Torvalds #include <linux/utsname.h> 24*1da177e4SLinus Torvalds 25*1da177e4SLinus Torvalds #include <asm/uaccess.h> 26*1da177e4SLinus Torvalds #include <asm/ipc.h> 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds /* 29*1da177e4SLinus Torvalds * sys_pipe() is the normal C calling standard for creating 30*1da177e4SLinus Torvalds * a pipe. It's not the way Unix traditionally does this, though. 31*1da177e4SLinus Torvalds */ 32*1da177e4SLinus Torvalds asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, 33*1da177e4SLinus Torvalds unsigned long r6, unsigned long r7, 34*1da177e4SLinus Torvalds struct pt_regs regs) 35*1da177e4SLinus Torvalds { 36*1da177e4SLinus Torvalds int fd[2]; 37*1da177e4SLinus Torvalds int error; 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds error = do_pipe(fd); 40*1da177e4SLinus Torvalds if (!error) { 41*1da177e4SLinus Torvalds regs.regs[1] = fd[1]; 42*1da177e4SLinus Torvalds return fd[0]; 43*1da177e4SLinus Torvalds } 44*1da177e4SLinus Torvalds return error; 45*1da177e4SLinus Torvalds } 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds #if defined(HAVE_ARCH_UNMAPPED_AREA) 48*1da177e4SLinus Torvalds /* 49*1da177e4SLinus Torvalds * To avoid cache alias, we map the shard page with same color. 50*1da177e4SLinus Torvalds */ 51*1da177e4SLinus Torvalds #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) 52*1da177e4SLinus Torvalds 53*1da177e4SLinus Torvalds unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, 54*1da177e4SLinus Torvalds unsigned long len, unsigned long pgoff, unsigned long flags) 55*1da177e4SLinus Torvalds { 56*1da177e4SLinus Torvalds struct mm_struct *mm = current->mm; 57*1da177e4SLinus Torvalds struct vm_area_struct *vma; 58*1da177e4SLinus Torvalds unsigned long start_addr; 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds if (flags & MAP_FIXED) { 61*1da177e4SLinus Torvalds /* We do not accept a shared mapping if it would violate 62*1da177e4SLinus Torvalds * cache aliasing constraints. 63*1da177e4SLinus Torvalds */ 64*1da177e4SLinus Torvalds if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) 65*1da177e4SLinus Torvalds return -EINVAL; 66*1da177e4SLinus Torvalds return addr; 67*1da177e4SLinus Torvalds } 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds if (len > TASK_SIZE) 70*1da177e4SLinus Torvalds return -ENOMEM; 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds if (addr) { 73*1da177e4SLinus Torvalds if (flags & MAP_PRIVATE) 74*1da177e4SLinus Torvalds addr = PAGE_ALIGN(addr); 75*1da177e4SLinus Torvalds else 76*1da177e4SLinus Torvalds addr = COLOUR_ALIGN(addr); 77*1da177e4SLinus Torvalds vma = find_vma(mm, addr); 78*1da177e4SLinus Torvalds if (TASK_SIZE - len >= addr && 79*1da177e4SLinus Torvalds (!vma || addr + len <= vma->vm_start)) 80*1da177e4SLinus Torvalds return addr; 81*1da177e4SLinus Torvalds } 82*1da177e4SLinus Torvalds if (flags & MAP_PRIVATE) 83*1da177e4SLinus Torvalds addr = PAGE_ALIGN(mm->free_area_cache); 84*1da177e4SLinus Torvalds else 85*1da177e4SLinus Torvalds addr = COLOUR_ALIGN(mm->free_area_cache); 86*1da177e4SLinus Torvalds start_addr = addr; 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds full_search: 89*1da177e4SLinus Torvalds for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { 90*1da177e4SLinus Torvalds /* At this point: (!vma || addr < vma->vm_end). */ 91*1da177e4SLinus Torvalds if (TASK_SIZE - len < addr) { 92*1da177e4SLinus Torvalds /* 93*1da177e4SLinus Torvalds * Start a new search - just in case we missed 94*1da177e4SLinus Torvalds * some holes. 95*1da177e4SLinus Torvalds */ 96*1da177e4SLinus Torvalds if (start_addr != TASK_UNMAPPED_BASE) { 97*1da177e4SLinus Torvalds start_addr = addr = TASK_UNMAPPED_BASE; 98*1da177e4SLinus Torvalds goto full_search; 99*1da177e4SLinus Torvalds } 100*1da177e4SLinus Torvalds return -ENOMEM; 101*1da177e4SLinus Torvalds } 102*1da177e4SLinus Torvalds if (!vma || addr + len <= vma->vm_start) { 103*1da177e4SLinus Torvalds /* 104*1da177e4SLinus Torvalds * Remember the place where we stopped the search: 105*1da177e4SLinus Torvalds */ 106*1da177e4SLinus Torvalds mm->free_area_cache = addr + len; 107*1da177e4SLinus Torvalds return addr; 108*1da177e4SLinus Torvalds } 109*1da177e4SLinus Torvalds addr = vma->vm_end; 110*1da177e4SLinus Torvalds if (!(flags & MAP_PRIVATE)) 111*1da177e4SLinus Torvalds addr = COLOUR_ALIGN(addr); 112*1da177e4SLinus Torvalds } 113*1da177e4SLinus Torvalds } 114*1da177e4SLinus Torvalds #endif 115*1da177e4SLinus Torvalds 116*1da177e4SLinus Torvalds static inline long 117*1da177e4SLinus Torvalds do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 118*1da177e4SLinus Torvalds unsigned long flags, int fd, unsigned long pgoff) 119*1da177e4SLinus Torvalds { 120*1da177e4SLinus Torvalds int error = -EBADF; 121*1da177e4SLinus Torvalds struct file *file = NULL; 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 124*1da177e4SLinus Torvalds if (!(flags & MAP_ANONYMOUS)) { 125*1da177e4SLinus Torvalds file = fget(fd); 126*1da177e4SLinus Torvalds if (!file) 127*1da177e4SLinus Torvalds goto out; 128*1da177e4SLinus Torvalds } 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds down_write(¤t->mm->mmap_sem); 131*1da177e4SLinus Torvalds error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 132*1da177e4SLinus Torvalds up_write(¤t->mm->mmap_sem); 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds if (file) 135*1da177e4SLinus Torvalds fput(file); 136*1da177e4SLinus Torvalds out: 137*1da177e4SLinus Torvalds return error; 138*1da177e4SLinus Torvalds } 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds asmlinkage int old_mmap(unsigned long addr, unsigned long len, 141*1da177e4SLinus Torvalds unsigned long prot, unsigned long flags, 142*1da177e4SLinus Torvalds int fd, unsigned long off) 143*1da177e4SLinus Torvalds { 144*1da177e4SLinus Torvalds if (off & ~PAGE_MASK) 145*1da177e4SLinus Torvalds return -EINVAL; 146*1da177e4SLinus Torvalds return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); 147*1da177e4SLinus Torvalds } 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 150*1da177e4SLinus Torvalds unsigned long prot, unsigned long flags, 151*1da177e4SLinus Torvalds unsigned long fd, unsigned long pgoff) 152*1da177e4SLinus Torvalds { 153*1da177e4SLinus Torvalds return do_mmap2(addr, len, prot, flags, fd, pgoff); 154*1da177e4SLinus Torvalds } 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds /* 157*1da177e4SLinus Torvalds * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 158*1da177e4SLinus Torvalds * 159*1da177e4SLinus Torvalds * This is really horribly ugly. 160*1da177e4SLinus Torvalds */ 161*1da177e4SLinus Torvalds asmlinkage int sys_ipc(uint call, int first, int second, 162*1da177e4SLinus Torvalds int third, void __user *ptr, long fifth) 163*1da177e4SLinus Torvalds { 164*1da177e4SLinus Torvalds int version, ret; 165*1da177e4SLinus Torvalds 166*1da177e4SLinus Torvalds version = call >> 16; /* hack for backward compatibility */ 167*1da177e4SLinus Torvalds call &= 0xffff; 168*1da177e4SLinus Torvalds 169*1da177e4SLinus Torvalds if (call <= SEMCTL) 170*1da177e4SLinus Torvalds switch (call) { 171*1da177e4SLinus Torvalds case SEMOP: 172*1da177e4SLinus Torvalds return sys_semtimedop(first, (struct sembuf __user *)ptr, 173*1da177e4SLinus Torvalds second, NULL); 174*1da177e4SLinus Torvalds case SEMTIMEDOP: 175*1da177e4SLinus Torvalds return sys_semtimedop(first, (struct sembuf __user *)ptr, 176*1da177e4SLinus Torvalds second, 177*1da177e4SLinus Torvalds (const struct timespec __user *)fifth); 178*1da177e4SLinus Torvalds case SEMGET: 179*1da177e4SLinus Torvalds return sys_semget (first, second, third); 180*1da177e4SLinus Torvalds case SEMCTL: { 181*1da177e4SLinus Torvalds union semun fourth; 182*1da177e4SLinus Torvalds if (!ptr) 183*1da177e4SLinus Torvalds return -EINVAL; 184*1da177e4SLinus Torvalds if (get_user(fourth.__pad, (void * __user *) ptr)) 185*1da177e4SLinus Torvalds return -EFAULT; 186*1da177e4SLinus Torvalds return sys_semctl (first, second, third, fourth); 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds default: 189*1da177e4SLinus Torvalds return -EINVAL; 190*1da177e4SLinus Torvalds } 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds if (call <= MSGCTL) 193*1da177e4SLinus Torvalds switch (call) { 194*1da177e4SLinus Torvalds case MSGSND: 195*1da177e4SLinus Torvalds return sys_msgsnd (first, (struct msgbuf __user *) ptr, 196*1da177e4SLinus Torvalds second, third); 197*1da177e4SLinus Torvalds case MSGRCV: 198*1da177e4SLinus Torvalds switch (version) { 199*1da177e4SLinus Torvalds case 0: { 200*1da177e4SLinus Torvalds struct ipc_kludge tmp; 201*1da177e4SLinus Torvalds if (!ptr) 202*1da177e4SLinus Torvalds return -EINVAL; 203*1da177e4SLinus Torvalds 204*1da177e4SLinus Torvalds if (copy_from_user(&tmp, 205*1da177e4SLinus Torvalds (struct ipc_kludge __user *) ptr, 206*1da177e4SLinus Torvalds sizeof (tmp))) 207*1da177e4SLinus Torvalds return -EFAULT; 208*1da177e4SLinus Torvalds return sys_msgrcv (first, tmp.msgp, second, 209*1da177e4SLinus Torvalds tmp.msgtyp, third); 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds default: 212*1da177e4SLinus Torvalds return sys_msgrcv (first, 213*1da177e4SLinus Torvalds (struct msgbuf __user *) ptr, 214*1da177e4SLinus Torvalds second, fifth, third); 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds case MSGGET: 217*1da177e4SLinus Torvalds return sys_msgget ((key_t) first, second); 218*1da177e4SLinus Torvalds case MSGCTL: 219*1da177e4SLinus Torvalds return sys_msgctl (first, second, 220*1da177e4SLinus Torvalds (struct msqid_ds __user *) ptr); 221*1da177e4SLinus Torvalds default: 222*1da177e4SLinus Torvalds return -EINVAL; 223*1da177e4SLinus Torvalds } 224*1da177e4SLinus Torvalds if (call <= SHMCTL) 225*1da177e4SLinus Torvalds switch (call) { 226*1da177e4SLinus Torvalds case SHMAT: 227*1da177e4SLinus Torvalds switch (version) { 228*1da177e4SLinus Torvalds default: { 229*1da177e4SLinus Torvalds ulong raddr; 230*1da177e4SLinus Torvalds ret = do_shmat (first, (char __user *) ptr, 231*1da177e4SLinus Torvalds second, &raddr); 232*1da177e4SLinus Torvalds if (ret) 233*1da177e4SLinus Torvalds return ret; 234*1da177e4SLinus Torvalds return put_user (raddr, (ulong __user *) third); 235*1da177e4SLinus Torvalds } 236*1da177e4SLinus Torvalds case 1: /* iBCS2 emulator entry point */ 237*1da177e4SLinus Torvalds if (!segment_eq(get_fs(), get_ds())) 238*1da177e4SLinus Torvalds return -EINVAL; 239*1da177e4SLinus Torvalds return do_shmat (first, (char __user *) ptr, 240*1da177e4SLinus Torvalds second, (ulong *) third); 241*1da177e4SLinus Torvalds } 242*1da177e4SLinus Torvalds case SHMDT: 243*1da177e4SLinus Torvalds return sys_shmdt ((char __user *)ptr); 244*1da177e4SLinus Torvalds case SHMGET: 245*1da177e4SLinus Torvalds return sys_shmget (first, second, third); 246*1da177e4SLinus Torvalds case SHMCTL: 247*1da177e4SLinus Torvalds return sys_shmctl (first, second, 248*1da177e4SLinus Torvalds (struct shmid_ds __user *) ptr); 249*1da177e4SLinus Torvalds default: 250*1da177e4SLinus Torvalds return -EINVAL; 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds return -EINVAL; 254*1da177e4SLinus Torvalds } 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds asmlinkage int sys_uname(struct old_utsname * name) 257*1da177e4SLinus Torvalds { 258*1da177e4SLinus Torvalds int err; 259*1da177e4SLinus Torvalds if (!name) 260*1da177e4SLinus Torvalds return -EFAULT; 261*1da177e4SLinus Torvalds down_read(&uts_sem); 262*1da177e4SLinus Torvalds err=copy_to_user(name, &system_utsname, sizeof (*name)); 263*1da177e4SLinus Torvalds up_read(&uts_sem); 264*1da177e4SLinus Torvalds return err?-EFAULT:0; 265*1da177e4SLinus Torvalds } 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf, 268*1da177e4SLinus Torvalds size_t count, long dummy, loff_t pos) 269*1da177e4SLinus Torvalds { 270*1da177e4SLinus Torvalds return sys_pread64(fd, buf, count, pos); 271*1da177e4SLinus Torvalds } 272*1da177e4SLinus Torvalds 273*1da177e4SLinus Torvalds asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf, 274*1da177e4SLinus Torvalds size_t count, long dummy, loff_t pos) 275*1da177e4SLinus Torvalds { 276*1da177e4SLinus Torvalds return sys_pwrite64(fd, buf, count, pos); 277*1da177e4SLinus Torvalds } 278*1da177e4SLinus Torvalds 279*1da177e4SLinus Torvalds asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, 280*1da177e4SLinus Torvalds u32 len0, u32 len1, int advice) 281*1da177e4SLinus Torvalds { 282*1da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN__ 283*1da177e4SLinus Torvalds return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0, 284*1da177e4SLinus Torvalds (u64)len1 << 32 | len0, advice); 285*1da177e4SLinus Torvalds #else 286*1da177e4SLinus Torvalds return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1, 287*1da177e4SLinus Torvalds (u64)len0 << 32 | len1, advice); 288*1da177e4SLinus Torvalds #endif 289*1da177e4SLinus Torvalds } 290