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 static inline long 32 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 33 unsigned long flags, int fd, unsigned long pgoff) 34 { 35 int error = -EBADF; 36 struct file *file = NULL; 37 38 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 39 if (!(flags & MAP_ANONYMOUS)) { 40 file = fget(fd); 41 if (!file) 42 goto out; 43 } 44 45 down_write(¤t->mm->mmap_sem); 46 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 47 up_write(¤t->mm->mmap_sem); 48 49 if (file) 50 fput(file); 51 out: 52 return error; 53 } 54 55 asmlinkage int old_mmap(unsigned long addr, unsigned long len, 56 unsigned long prot, unsigned long flags, 57 int fd, unsigned long off) 58 { 59 if (off & ~PAGE_MASK) 60 return -EINVAL; 61 return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); 62 } 63 64 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 65 unsigned long prot, unsigned long flags, 66 unsigned long fd, unsigned long pgoff) 67 { 68 /* 69 * The shift for mmap2 is constant, regardless of PAGE_SIZE 70 * setting. 71 */ 72 if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1)) 73 return -EINVAL; 74 75 pgoff >>= PAGE_SHIFT - 12; 76 77 return do_mmap2(addr, len, prot, flags, fd, pgoff); 78 } 79 80 /* 81 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 82 * 83 * This is really horribly ugly. 84 */ 85 asmlinkage int sys_ipc(uint call, int first, int second, 86 int third, void __user *ptr, long fifth) 87 { 88 int version, ret; 89 90 version = call >> 16; /* hack for backward compatibility */ 91 call &= 0xffff; 92 93 if (call <= SEMTIMEDOP) 94 switch (call) { 95 case SEMOP: 96 return sys_semtimedop(first, 97 (struct sembuf __user *)ptr, 98 second, NULL); 99 case SEMTIMEDOP: 100 return sys_semtimedop(first, 101 (struct sembuf __user *)ptr, second, 102 (const struct timespec __user *)fifth); 103 case SEMGET: 104 return sys_semget (first, second, third); 105 case SEMCTL: { 106 union semun fourth; 107 if (!ptr) 108 return -EINVAL; 109 if (get_user(fourth.__pad, (void __user * __user *) ptr)) 110 return -EFAULT; 111 return sys_semctl (first, second, third, fourth); 112 } 113 default: 114 return -EINVAL; 115 } 116 117 if (call <= MSGCTL) 118 switch (call) { 119 case MSGSND: 120 return sys_msgsnd (first, (struct msgbuf __user *) ptr, 121 second, third); 122 case MSGRCV: 123 switch (version) { 124 case 0: 125 { 126 struct ipc_kludge tmp; 127 128 if (!ptr) 129 return -EINVAL; 130 131 if (copy_from_user(&tmp, 132 (struct ipc_kludge __user *) ptr, 133 sizeof (tmp))) 134 return -EFAULT; 135 136 return sys_msgrcv (first, tmp.msgp, second, 137 tmp.msgtyp, third); 138 } 139 default: 140 return sys_msgrcv (first, 141 (struct msgbuf __user *) ptr, 142 second, fifth, third); 143 } 144 case MSGGET: 145 return sys_msgget ((key_t) first, second); 146 case MSGCTL: 147 return sys_msgctl (first, second, 148 (struct msqid_ds __user *) ptr); 149 default: 150 return -EINVAL; 151 } 152 if (call <= SHMCTL) 153 switch (call) { 154 case SHMAT: 155 switch (version) { 156 default: { 157 ulong raddr; 158 ret = do_shmat (first, (char __user *) ptr, 159 second, &raddr); 160 if (ret) 161 return ret; 162 return put_user (raddr, (ulong __user *) third); 163 } 164 case 1: /* iBCS2 emulator entry point */ 165 if (!segment_eq(get_fs(), get_ds())) 166 return -EINVAL; 167 return do_shmat (first, (char __user *) ptr, 168 second, (ulong *) third); 169 } 170 case SHMDT: 171 return sys_shmdt ((char __user *)ptr); 172 case SHMGET: 173 return sys_shmget (first, second, third); 174 case SHMCTL: 175 return sys_shmctl (first, second, 176 (struct shmid_ds __user *) ptr); 177 default: 178 return -EINVAL; 179 } 180 181 return -EINVAL; 182 } 183 184 /* sys_cacheflush -- flush (part of) the processor cache. */ 185 asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op) 186 { 187 struct vm_area_struct *vma; 188 189 if ((op <= 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I))) 190 return -EINVAL; 191 192 /* 193 * Verify that the specified address region actually belongs 194 * to this process. 195 */ 196 if (addr + len < addr) 197 return -EFAULT; 198 199 down_read(¤t->mm->mmap_sem); 200 vma = find_vma (current->mm, addr); 201 if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) { 202 up_read(¤t->mm->mmap_sem); 203 return -EFAULT; 204 } 205 206 switch (op & CACHEFLUSH_D_PURGE) { 207 case CACHEFLUSH_D_INVAL: 208 __flush_invalidate_region((void *)addr, len); 209 break; 210 case CACHEFLUSH_D_WB: 211 __flush_wback_region((void *)addr, len); 212 break; 213 case CACHEFLUSH_D_PURGE: 214 __flush_purge_region((void *)addr, len); 215 break; 216 } 217 218 if (op & CACHEFLUSH_I) 219 flush_cache_all(); 220 221 up_read(¤t->mm->mmap_sem); 222 return 0; 223 } 224 225 asmlinkage int sys_uname(struct old_utsname __user *name) 226 { 227 int err; 228 if (!name) 229 return -EFAULT; 230 down_read(&uts_sem); 231 err = copy_to_user(name, utsname(), sizeof(*name)); 232 up_read(&uts_sem); 233 return err?-EFAULT:0; 234 } 235