1 /* linux/arch/sparc/kernel/sys_sparc.c 2 * 3 * This file contains various random system calls that 4 * have a non-standard calling sequence on the Linux/sparc 5 * platform. 6 */ 7 8 #include <linux/errno.h> 9 #include <linux/types.h> 10 #include <linux/sched.h> 11 #include <linux/mm.h> 12 #include <linux/fs.h> 13 #include <linux/file.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/utsname.h> 21 #include <linux/smp.h> 22 #include <linux/smp_lock.h> 23 #include <linux/ipc.h> 24 25 #include <asm/uaccess.h> 26 #include <asm/unistd.h> 27 28 /* #define DEBUG_UNIMP_SYSCALL */ 29 30 /* XXX Make this per-binary type, this way we can detect the type of 31 * XXX a binary. Every Sparc executable calls this very early on. 32 */ 33 asmlinkage unsigned long sys_getpagesize(void) 34 { 35 return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ 36 } 37 38 #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) 39 40 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) 41 { 42 struct vm_area_struct * vmm; 43 44 if (flags & MAP_FIXED) { 45 /* We do not accept a shared mapping if it would violate 46 * cache aliasing constraints. 47 */ 48 if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) 49 return -EINVAL; 50 return addr; 51 } 52 53 /* See asm-sparc/uaccess.h */ 54 if (len > TASK_SIZE - PAGE_SIZE) 55 return -ENOMEM; 56 if (ARCH_SUN4C && len > 0x20000000) 57 return -ENOMEM; 58 if (!addr) 59 addr = TASK_UNMAPPED_BASE; 60 61 if (flags & MAP_SHARED) 62 addr = COLOUR_ALIGN(addr); 63 else 64 addr = PAGE_ALIGN(addr); 65 66 for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { 67 /* At this point: (!vmm || addr < vmm->vm_end). */ 68 if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) { 69 addr = PAGE_OFFSET; 70 vmm = find_vma(current->mm, PAGE_OFFSET); 71 } 72 if (TASK_SIZE - PAGE_SIZE - len < addr) 73 return -ENOMEM; 74 if (!vmm || addr + len <= vmm->vm_start) 75 return addr; 76 addr = vmm->vm_end; 77 if (flags & MAP_SHARED) 78 addr = COLOUR_ALIGN(addr); 79 } 80 } 81 82 asmlinkage unsigned long sparc_brk(unsigned long brk) 83 { 84 if(ARCH_SUN4C) { 85 if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) 86 return current->mm->brk; 87 } 88 return sys_brk(brk); 89 } 90 91 /* 92 * sys_pipe() is the normal C calling standard for creating 93 * a pipe. It's not the way unix traditionally does this, though. 94 */ 95 asmlinkage int sparc_pipe(struct pt_regs *regs) 96 { 97 int fd[2]; 98 int error; 99 100 error = do_pipe_flags(fd, 0); 101 if (error) 102 goto out; 103 regs->u_regs[UREG_I1] = fd[1]; 104 error = fd[0]; 105 out: 106 return error; 107 } 108 109 /* 110 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 111 * 112 * This is really horribly ugly. 113 */ 114 115 asmlinkage int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth) 116 { 117 int version, err; 118 119 version = call >> 16; /* hack for backward compatibility */ 120 call &= 0xffff; 121 122 if (call <= SEMCTL) 123 switch (call) { 124 case SEMOP: 125 err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); 126 goto out; 127 case SEMTIMEDOP: 128 err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, (const struct timespec __user *) fifth); 129 goto out; 130 case SEMGET: 131 err = sys_semget (first, second, third); 132 goto out; 133 case SEMCTL: { 134 union semun fourth; 135 err = -EINVAL; 136 if (!ptr) 137 goto out; 138 err = -EFAULT; 139 if (get_user(fourth.__pad, 140 (void __user * __user *)ptr)) 141 goto out; 142 err = sys_semctl (first, second, third, fourth); 143 goto out; 144 } 145 default: 146 err = -ENOSYS; 147 goto out; 148 } 149 if (call <= MSGCTL) 150 switch (call) { 151 case MSGSND: 152 err = sys_msgsnd (first, (struct msgbuf __user *) ptr, 153 second, third); 154 goto out; 155 case MSGRCV: 156 switch (version) { 157 case 0: { 158 struct ipc_kludge tmp; 159 err = -EINVAL; 160 if (!ptr) 161 goto out; 162 err = -EFAULT; 163 if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr, sizeof (tmp))) 164 goto out; 165 err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); 166 goto out; 167 } 168 case 1: default: 169 err = sys_msgrcv (first, 170 (struct msgbuf __user *) ptr, 171 second, fifth, third); 172 goto out; 173 } 174 case MSGGET: 175 err = sys_msgget ((key_t) first, second); 176 goto out; 177 case MSGCTL: 178 err = sys_msgctl (first, second, (struct msqid_ds __user *) ptr); 179 goto out; 180 default: 181 err = -ENOSYS; 182 goto out; 183 } 184 if (call <= SHMCTL) 185 switch (call) { 186 case SHMAT: 187 switch (version) { 188 case 0: default: { 189 ulong raddr; 190 err = do_shmat (first, (char __user *) ptr, second, &raddr); 191 if (err) 192 goto out; 193 err = -EFAULT; 194 if (put_user (raddr, (ulong __user *) third)) 195 goto out; 196 err = 0; 197 goto out; 198 } 199 case 1: /* iBCS2 emulator entry point */ 200 err = -EINVAL; 201 goto out; 202 } 203 case SHMDT: 204 err = sys_shmdt ((char __user *)ptr); 205 goto out; 206 case SHMGET: 207 err = sys_shmget (first, second, third); 208 goto out; 209 case SHMCTL: 210 err = sys_shmctl (first, second, (struct shmid_ds __user *) ptr); 211 goto out; 212 default: 213 err = -ENOSYS; 214 goto out; 215 } 216 else 217 err = -ENOSYS; 218 out: 219 return err; 220 } 221 222 int sparc_mmap_check(unsigned long addr, unsigned long len) 223 { 224 if (ARCH_SUN4C && 225 (len > 0x20000000 || 226 (addr < 0xe0000000 && addr + len > 0x20000000))) 227 return -EINVAL; 228 229 /* See asm-sparc/uaccess.h */ 230 if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE) 231 return -EINVAL; 232 233 return 0; 234 } 235 236 /* Linux version of mmap */ 237 static unsigned long do_mmap2(unsigned long addr, unsigned long len, 238 unsigned long prot, unsigned long flags, unsigned long fd, 239 unsigned long pgoff) 240 { 241 struct file * file = NULL; 242 unsigned long retval = -EBADF; 243 244 if (!(flags & MAP_ANONYMOUS)) { 245 file = fget(fd); 246 if (!file) 247 goto out; 248 } 249 250 len = PAGE_ALIGN(len); 251 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 252 253 down_write(¤t->mm->mmap_sem); 254 retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 255 up_write(¤t->mm->mmap_sem); 256 257 if (file) 258 fput(file); 259 out: 260 return retval; 261 } 262 263 asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, 264 unsigned long prot, unsigned long flags, unsigned long fd, 265 unsigned long pgoff) 266 { 267 /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE 268 we have. */ 269 return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); 270 } 271 272 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, 273 unsigned long prot, unsigned long flags, unsigned long fd, 274 unsigned long off) 275 { 276 return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); 277 } 278 279 long sparc_remap_file_pages(unsigned long start, unsigned long size, 280 unsigned long prot, unsigned long pgoff, 281 unsigned long flags) 282 { 283 /* This works on an existing mmap so we don't need to validate 284 * the range as that was done at the original mmap call. 285 */ 286 return sys_remap_file_pages(start, size, prot, 287 (pgoff >> (PAGE_SHIFT - 12)), flags); 288 } 289 290 extern unsigned long do_mremap(unsigned long addr, 291 unsigned long old_len, unsigned long new_len, 292 unsigned long flags, unsigned long new_addr); 293 294 asmlinkage unsigned long sparc_mremap(unsigned long addr, 295 unsigned long old_len, unsigned long new_len, 296 unsigned long flags, unsigned long new_addr) 297 { 298 unsigned long ret = -EINVAL; 299 300 if (unlikely(sparc_mmap_check(addr, old_len))) 301 goto out; 302 if (unlikely(sparc_mmap_check(new_addr, new_len))) 303 goto out; 304 down_write(¤t->mm->mmap_sem); 305 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 306 up_write(¤t->mm->mmap_sem); 307 out: 308 return ret; 309 } 310 311 /* we come to here via sys_nis_syscall so it can setup the regs argument */ 312 asmlinkage unsigned long 313 c_sys_nis_syscall (struct pt_regs *regs) 314 { 315 static int count = 0; 316 317 if (count++ > 5) 318 return -ENOSYS; 319 printk ("%s[%d]: Unimplemented SPARC system call %d\n", 320 current->comm, task_pid_nr(current), (int)regs->u_regs[1]); 321 #ifdef DEBUG_UNIMP_SYSCALL 322 show_regs (regs); 323 #endif 324 return -ENOSYS; 325 } 326 327 /* #define DEBUG_SPARC_BREAKPOINT */ 328 329 asmlinkage void 330 sparc_breakpoint (struct pt_regs *regs) 331 { 332 siginfo_t info; 333 334 lock_kernel(); 335 #ifdef DEBUG_SPARC_BREAKPOINT 336 printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc); 337 #endif 338 info.si_signo = SIGTRAP; 339 info.si_errno = 0; 340 info.si_code = TRAP_BRKPT; 341 info.si_addr = (void __user *)regs->pc; 342 info.si_trapno = 0; 343 force_sig_info(SIGTRAP, &info, current); 344 345 #ifdef DEBUG_SPARC_BREAKPOINT 346 printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc); 347 #endif 348 unlock_kernel(); 349 } 350 351 asmlinkage int 352 sparc_sigaction (int sig, const struct old_sigaction __user *act, 353 struct old_sigaction __user *oact) 354 { 355 struct k_sigaction new_ka, old_ka; 356 int ret; 357 358 WARN_ON_ONCE(sig >= 0); 359 sig = -sig; 360 361 if (act) { 362 unsigned long mask; 363 364 if (!access_ok(VERIFY_READ, act, sizeof(*act)) || 365 __get_user(new_ka.sa.sa_handler, &act->sa_handler) || 366 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) 367 return -EFAULT; 368 __get_user(new_ka.sa.sa_flags, &act->sa_flags); 369 __get_user(mask, &act->sa_mask); 370 siginitset(&new_ka.sa.sa_mask, mask); 371 new_ka.ka_restorer = NULL; 372 } 373 374 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 375 376 if (!ret && oact) { 377 /* In the clone() case we could copy half consistent 378 * state to the user, however this could sleep and 379 * deadlock us if we held the signal lock on SMP. So for 380 * now I take the easy way out and do no locking. 381 */ 382 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || 383 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || 384 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) 385 return -EFAULT; 386 __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 387 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); 388 } 389 390 return ret; 391 } 392 393 asmlinkage long 394 sys_rt_sigaction(int sig, 395 const struct sigaction __user *act, 396 struct sigaction __user *oact, 397 void __user *restorer, 398 size_t sigsetsize) 399 { 400 struct k_sigaction new_ka, old_ka; 401 int ret; 402 403 /* XXX: Don't preclude handling different sized sigset_t's. */ 404 if (sigsetsize != sizeof(sigset_t)) 405 return -EINVAL; 406 407 if (act) { 408 new_ka.ka_restorer = restorer; 409 if (copy_from_user(&new_ka.sa, act, sizeof(*act))) 410 return -EFAULT; 411 } 412 413 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 414 415 if (!ret && oact) { 416 if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) 417 return -EFAULT; 418 } 419 420 return ret; 421 } 422 423 asmlinkage int sys_getdomainname(char __user *name, int len) 424 { 425 int nlen, err; 426 427 if (len < 0) 428 return -EINVAL; 429 430 down_read(&uts_sem); 431 432 nlen = strlen(utsname()->domainname) + 1; 433 err = -EINVAL; 434 if (nlen > len) 435 goto out; 436 437 err = -EFAULT; 438 if (!copy_to_user(name, utsname()->domainname, nlen)) 439 err = 0; 440 441 out: 442 up_read(&uts_sem); 443 return err; 444 } 445 446 /* 447 * Do a system call from kernel instead of calling sys_execve so we 448 * end up with proper pt_regs. 449 */ 450 int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 451 { 452 long __res; 453 register long __g1 __asm__ ("g1") = __NR_execve; 454 register long __o0 __asm__ ("o0") = (long)(filename); 455 register long __o1 __asm__ ("o1") = (long)(argv); 456 register long __o2 __asm__ ("o2") = (long)(envp); 457 asm volatile ("t 0x10\n\t" 458 "bcc 1f\n\t" 459 "mov %%o0, %0\n\t" 460 "sub %%g0, %%o0, %0\n\t" 461 "1:\n\t" 462 : "=r" (__res), "=&r" (__o0) 463 : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) 464 : "cc"); 465 return __res; 466 } 467