1 /* 2 * linux/arch/sh/kernel/sys_sh.c 3 * 4 * This file contains various random system calls that 5 * have a non-standard calling sequence on the Linux/SuperH 6 * platform. 7 * 8 * Taken from i386 version. 9 */ 10 #include <linux/errno.h> 11 #include <linux/sched.h> 12 #include <linux/mm.h> 13 #include <linux/smp.h> 14 #include <linux/sem.h> 15 #include <linux/msg.h> 16 #include <linux/shm.h> 17 #include <linux/stat.h> 18 #include <linux/syscalls.h> 19 #include <linux/mman.h> 20 #include <linux/file.h> 21 #include <linux/utsname.h> 22 #include <linux/module.h> 23 #include <linux/fs.h> 24 #include <linux/ipc.h> 25 #include <asm/syscalls.h> 26 #include <asm/uaccess.h> 27 #include <asm/unistd.h> 28 #include <asm/cacheflush.h> 29 #include <asm/cachectl.h> 30 31 asmlinkage int old_mmap(unsigned long addr, unsigned long len, 32 unsigned long prot, unsigned long flags, 33 int fd, unsigned long off) 34 { 35 if (off & ~PAGE_MASK) 36 return -EINVAL; 37 return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT); 38 } 39 40 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 41 unsigned long prot, unsigned long flags, 42 unsigned long fd, unsigned long pgoff) 43 { 44 /* 45 * The shift for mmap2 is constant, regardless of PAGE_SIZE 46 * setting. 47 */ 48 if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1)) 49 return -EINVAL; 50 51 pgoff >>= PAGE_SHIFT - 12; 52 53 return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); 54 } 55 56 /* 57 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 58 * 59 * This is really horribly ugly. 60 */ 61 asmlinkage int sys_ipc(uint call, int first, int second, 62 int third, void __user *ptr, long fifth) 63 { 64 int version, ret; 65 66 version = call >> 16; /* hack for backward compatibility */ 67 call &= 0xffff; 68 69 if (call <= SEMTIMEDOP) 70 switch (call) { 71 case SEMOP: 72 return sys_semtimedop(first, 73 (struct sembuf __user *)ptr, 74 second, NULL); 75 case SEMTIMEDOP: 76 return sys_semtimedop(first, 77 (struct sembuf __user *)ptr, second, 78 (const struct timespec __user *)fifth); 79 case SEMGET: 80 return sys_semget (first, second, third); 81 case SEMCTL: { 82 union semun fourth; 83 if (!ptr) 84 return -EINVAL; 85 if (get_user(fourth.__pad, (void __user * __user *) ptr)) 86 return -EFAULT; 87 return sys_semctl (first, second, third, fourth); 88 } 89 default: 90 return -EINVAL; 91 } 92 93 if (call <= MSGCTL) 94 switch (call) { 95 case MSGSND: 96 return sys_msgsnd (first, (struct msgbuf __user *) ptr, 97 second, third); 98 case MSGRCV: 99 switch (version) { 100 case 0: 101 { 102 struct ipc_kludge tmp; 103 104 if (!ptr) 105 return -EINVAL; 106 107 if (copy_from_user(&tmp, 108 (struct ipc_kludge __user *) ptr, 109 sizeof (tmp))) 110 return -EFAULT; 111 112 return sys_msgrcv (first, tmp.msgp, second, 113 tmp.msgtyp, third); 114 } 115 default: 116 return sys_msgrcv (first, 117 (struct msgbuf __user *) ptr, 118 second, fifth, third); 119 } 120 case MSGGET: 121 return sys_msgget ((key_t) first, second); 122 case MSGCTL: 123 return sys_msgctl (first, second, 124 (struct msqid_ds __user *) ptr); 125 default: 126 return -EINVAL; 127 } 128 if (call <= SHMCTL) 129 switch (call) { 130 case SHMAT: 131 switch (version) { 132 default: { 133 ulong raddr; 134 ret = do_shmat (first, (char __user *) ptr, 135 second, &raddr); 136 if (ret) 137 return ret; 138 return put_user (raddr, (ulong __user *) third); 139 } 140 case 1: /* iBCS2 emulator entry point */ 141 if (!segment_eq(get_fs(), get_ds())) 142 return -EINVAL; 143 return do_shmat (first, (char __user *) ptr, 144 second, (ulong *) third); 145 } 146 case SHMDT: 147 return sys_shmdt ((char __user *)ptr); 148 case SHMGET: 149 return sys_shmget (first, second, third); 150 case SHMCTL: 151 return sys_shmctl (first, second, 152 (struct shmid_ds __user *) ptr); 153 default: 154 return -EINVAL; 155 } 156 157 return -EINVAL; 158 } 159 160 /* sys_cacheflush -- flush (part of) the processor cache. */ 161 asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op) 162 { 163 struct vm_area_struct *vma; 164 165 if ((op <= 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I))) 166 return -EINVAL; 167 168 /* 169 * Verify that the specified address region actually belongs 170 * to this process. 171 */ 172 if (addr + len < addr) 173 return -EFAULT; 174 175 down_read(¤t->mm->mmap_sem); 176 vma = find_vma (current->mm, addr); 177 if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) { 178 up_read(¤t->mm->mmap_sem); 179 return -EFAULT; 180 } 181 182 switch (op & CACHEFLUSH_D_PURGE) { 183 case CACHEFLUSH_D_INVAL: 184 __flush_invalidate_region((void *)addr, len); 185 break; 186 case CACHEFLUSH_D_WB: 187 __flush_wback_region((void *)addr, len); 188 break; 189 case CACHEFLUSH_D_PURGE: 190 __flush_purge_region((void *)addr, len); 191 break; 192 } 193 194 if (op & CACHEFLUSH_I) 195 flush_cache_all(); 196 197 up_read(¤t->mm->mmap_sem); 198 return 0; 199 } 200 201 asmlinkage int sys_uname(struct old_utsname __user *name) 202 { 203 int err; 204 if (!name) 205 return -EFAULT; 206 down_read(&uts_sem); 207 err = copy_to_user(name, utsname(), sizeof(*name)); 208 up_read(&uts_sem); 209 return err?-EFAULT:0; 210 } 211