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