1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 1995 - 2000, 2001 by Ralf Baechle 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 * Copyright (C) 2001 MIPS Technologies, Inc. 9 * 10 * Hairy, the userspace application uses a different argument passing 11 * convention than the kernel, so we have to translate things from o32 12 * to ABI64 calling convention. 64-bit syscalls are also processed 13 * here for now. 14 */ 15#include <asm/asm.h> 16#include <linux/errno.h> 17#include <asm/current.h> 18#include <asm/mipsregs.h> 19#include <asm/offset.h> 20#include <asm/regdef.h> 21#include <asm/stackframe.h> 22#include <asm/unistd.h> 23#include <asm/sysmips.h> 24 25 .align 5 26NESTED(handle_sys, PT_SIZE, sp) 27 .set noat 28 SAVE_SOME 29 STI 30 .set at 31 ld t1, PT_EPC(sp) # skip syscall on return 32 33 subu t0, v0, __NR_O32_Linux # check syscall number 34 sltiu t0, t0, __NR_O32_Linux_syscalls + 1 35 daddiu t1, 4 # skip to next instruction 36 sd t1, PT_EPC(sp) 37 beqz t0, not_o32_scall 38#if 0 39 SAVE_ALL 40 move a1, v0 41 PRINT("Scall %ld\n") 42 RESTORE_ALL 43#endif 44 45 sll a0, a0, 0 46 sll a1, a1, 0 47 sll a2, a2, 0 48 sll a3, a3, 0 49 50 /* XXX Put both in one cacheline, should save a bit. */ 51 dsll t0, v0, 3 # offset into table 52 ld t2, (sys_call_table - (__NR_O32_Linux * 8))(t0) 53 lbu t3, (sys_narg_table - __NR_O32_Linux)(v0) 54 55 subu t0, t3, 5 # 5 or more arguments? 56 sd a3, PT_R26(sp) # save a3 for syscall restarting 57 bgez t0, stackargs 58 59stack_done: 60 ld t0, TASK_PTRACE($28) # syscall tracing enabled? 61 andi t0, _PT_TRACESYS 62 bnez t0, trace_a_syscall 63 64 jalr t2 # Do The Real Thing (TM) 65 66 li t0, -EMAXERRNO - 1 # error? 67 sltu t0, t0, v0 68 sd t0, PT_R7(sp) # set error flag 69 beqz t0, 1f 70 71 negu v0 # error 72 sd v0, PT_R0(sp) # flag for syscall restarting 731: sd v0, PT_R2(sp) # result 74 75FEXPORT(o32_ret_from_sys_call) 76 mfc0 t0, CP0_STATUS # need_resched and signals atomic test 77 ori t0, t0, 1 78 xori t0, t0, 1 79 mtc0 t0, CP0_STATUS 80 SSNOP; SSNOP; SSNOP 81 82 ld t2, TASK_NEED_RESCHED($28) 83 bnez t2, o32_reschedule 84 lw v0, TASK_SIGPENDING($28) 85 bnez v0, signal_return 86 87restore_all: RESTORE_SOME 88 RESTORE_SP 89 .set mips3 90 eret 91 .set mips0 92 93signal_return: 94 .type signal_return, @function 95 96 mfc0 t0, CP0_STATUS 97 ori t0, t0, 1 98 mtc0 t0, CP0_STATUS 99 100 SAVE_STATIC 101 move a0, zero 102 move a1, sp 103 jal do_signal 104 RESTORE_STATIC 105 b restore_all 106 107o32_reschedule: 108 SAVE_STATIC 109 jal schedule 110 j ret_from_sys_call 111 112/* ------------------------------------------------------------------------ */ 113 114trace_a_syscall: 115 SAVE_STATIC 116 sd a4, PT_R8(sp) 117 sd a5, PT_R9(sp) 118 sd a6, PT_R10(sp) 119 sd a7, PT_R11(sp) 120 121 sd t2,PT_R1(sp) 122 jal syscall_trace 123 ld t2,PT_R1(sp) 124 125 ld a0, PT_R4(sp) # Restore argument registers 126 ld a1, PT_R5(sp) 127 ld a2, PT_R6(sp) 128 ld a3, PT_R7(sp) 129 ld a4, PT_R8(sp) 130 ld a5, PT_R9(sp) 131 132 jalr t2 133 134 li t0, -EMAXERRNO - 1 # error? 135 sltu t0, t0, v0 136 sd t0, PT_R7(sp) # set error flag 137 beqz t0, 1f 138 139 negu v0 # error 140 sd v0, PT_R0(sp) # set flag for syscall restarting 1411: sd v0, PT_R2(sp) # result 142 143 jal syscall_trace 144 j o32_ret_from_sys_call 145 146/* ------------------------------------------------------------------------ */ 147 148 /* 149 * More than four arguments. Try to deal with it by copying the 150 * stack arguments from the user stack to the kernel stack. 151 * This Sucks (TM). 152 */ 153stackargs: 154 ld t0, PT_R29(sp) # get old user stack pointer 155 subu t3, 4 156 sll t1, t3, 2 # stack valid? 157 158 addu t1, t0 # end address 159 or t0, t1 160 bltz t0, bad_stack # -> sp is bad 161 162 ld t0, PT_R29(sp) # get old user stack pointer 163 PTR_LA t1, 3f # copy 1 to 2 arguments 164 sll t3, t3, 2 165 subu t1, t3 166 jr t1 167 168 /* Ok, copy the args from the luser stack to the kernel stack */ 169 .set push 170 .set noreorder 171 .set nomacro 1721: lw a5, 20(t0) # argument #6 from usp 1732: lw a4, 16(t0) # argument #5 from usp 1743: .set pop 175 176 j stack_done # go back 177 178 .section __ex_table,"a" 179 PTR 1b, bad_stack 180 PTR 2b, bad_stack 181 .previous 182 183 /* 184 * The stackpointer for a call with more than 4 arguments is bad. 185 */ 186bad_stack: 187 negu v0 # error 188 sd v0, PT_R0(sp) 189 sd v0, PT_R2(sp) 190 li t0, 1 # set error flag 191 sd t0, PT_R7(sp) 192 j ret_from_sys_call 193 194not_o32_scall: 195 /* This is not an o32 compatibility syscall, pass it on to 196 the 64-bit syscall handlers. */ 197#ifdef CONFIG_MIPS32_N32 198 j handle_sysn32 199#else 200 j handle_sys64 201#endif 202 203illegal_syscall: 204 /* This also isn't a 64-bit syscall, throw an error. */ 205 li v0, ENOSYS # error 206 sd v0, PT_R2(sp) 207 li t0, 1 # set error flag 208 sd t0, PT_R7(sp) 209 j ret_from_sys_call 210 END(handle_sys) 211 212LEAF(mips_atomic_set) 213 andi v0, a1, 3 # must be word aligned 214 bnez v0, bad_alignment 215 216 ld v1, THREAD_CURDS($28) # in legal address range? 217 daddiu a0, a1, 4 218 or a0, a0, a1 219 and a0, a0, v1 220 bnez a0, bad_address 221 222 /* Ok, this is the ll/sc case. World is sane :-) */ 2231: ll v0, (a1) 224 move a0, a2 2252: sc a0, (a1) 226 beqz a0, 1b 227 228 .section __ex_table,"a" 229 PTR 1b, bad_stack 230 PTR 2b, bad_stack 231 .previous 232 2331: sd v0, PT_R2(sp) # result 234 235 /* Success, so skip usual error handling garbage. */ 236 ld t0, TASK_PTRACE($28) # syscall tracing enabled? 237 andi t0, _PT_TRACESYS 238 bnez t0, 1f 239 b o32_ret_from_sys_call 240 2411: SAVE_STATIC 242 jal syscall_trace 243 li a3, 0 # success 244 j ret_from_sys_call 245 246bad_address: 247 li v0, -EFAULT 248 jr ra 249 250bad_alignment: 251 li v0, -EINVAL 252 jr ra 253 END(mips_atomic_set) 254 255LEAF(sys32_sysmips) 256 beq a0, MIPS_ATOMIC_SET, mips_atomic_set 257 j sys_sysmips 258 END(sys32_sysmips) 259 260LEAF(sys32_syscall) 261 ld t0, PT_R29(sp) # user sp 262 263 sltu v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1 264 beqz v0, enosys 265 266 dsll v0, a0, 3 267 dla v1, sys32_syscall 268 ld t2, (sys_call_table - (__NR_O32_Linux * 8))(v0) 269 lbu t3, (sys_narg_table - __NR_O32_Linux)(a0) 270 271 li v0, -EINVAL 272 beq t2, v1, out # do not recurse 273 274 beqz t2, enosys # null function pointer? 275 276 andi v0, t0, 0x3 # unaligned stack pointer? 277 bnez v0, sigsegv 278 279 daddiu v0, t0, 16 # v0 = usp + 16 280 daddu t1, v0, 12 # 3 32-bit arguments 281 ld v1, THREAD_CURDS($28) 282 or v0, v0, t1 283 and v1, v1, v0 284 bnez v1, efault 285 286 move a0, a1 # shift argument registers 287 move a1, a2 288 move a2, a3 289 2901: lw a3, 16(t0) 2912: lw t3, 20(t0) 2923: lw t1, 24(t0) 293 294 .section __ex_table,"a" 295 PTR 1b, efault 296 PTR 2b, efault 297 PTR 3b, efault 298 .previous 299 300 sw t3, 16(sp) # put into new stackframe 301 sw t1, 20(sp) 302 303 bnez t1, 1f # zero arguments? 304 daddu a0, sp, 32 # then pass sp in a0 3051: 306 307 sw t3, 16(sp) 308 sw v1, 20(sp) 309 jr t2 310 /* Unreached */ 311 312enosys: li v0, -ENOSYS 313 b out 314 315sigsegv: 316 li a0, _SIGSEGV 317 move a1, $28 318 jal force_sig 319 /* Fall through */ 320 321efault: li v0, -EFAULT 322 323out: jr ra 324 END(sys32_syscall) 325 326 .macro syscalltable 327 sys sys32_syscall 0 /* 4000 */ 328 sys sys_exit 1 329 sys sys_fork 0 330 sys sys_read 3 331 sys sys_write 3 332 sys sys_open 3 /* 4005 */ 333 sys sys_close 1 334 sys sys_waitpid 3 335 sys sys_creat 2 336 sys sys_link 2 337 sys sys_unlink 1 /* 4010 */ 338 sys sys32_execve 0 339 sys sys_chdir 1 340 sys sys_time 1 341 sys sys_mknod 3 342 sys sys_chmod 2 /* 4015 */ 343 sys sys_lchown 3 344 sys sys_ni_syscall 0 345 sys sys_ni_syscall 0 /* was sys_stat */ 346 sys sys_lseek 3 347 sys sys_getpid 0 /* 4020 */ 348 sys sys_mount 5 349 sys sys_oldumount 1 350 sys sys_setuid 1 351 sys sys_getuid 0 352 sys sys_stime 1 /* 4025 */ 353 sys sys32_ptrace 4 354 sys sys_alarm 1 355 sys sys_ni_syscall 0 /* was sys_fstat */ 356 sys sys_pause 0 357 sys sys32_utime 2 /* 4030 */ 358 sys sys_ni_syscall 0 359 sys sys_ni_syscall 0 360 sys sys_access 2 361 sys sys_nice 1 362 sys sys_ni_syscall 0 /* 4035 */ 363 sys sys_sync 0 364 sys sys_kill 2 365 sys sys_rename 2 366 sys sys_mkdir 2 367 sys sys_rmdir 1 /* 4040 */ 368 sys sys_dup 1 369 sys sys_pipe 0 370 sys sys32_times 1 371 sys sys_ni_syscall 0 372 sys sys_brk 1 /* 4045 */ 373 sys sys_setgid 1 374 sys sys_getgid 0 375 sys sys_ni_syscall 0 /* was signal 2 */ 376 sys sys_geteuid 0 377 sys sys_getegid 0 /* 4050 */ 378 sys sys_acct 0 379 sys sys_umount 2 380 sys sys_ni_syscall 0 381 sys sys32_ioctl 3 382 sys sys32_fcntl 3 /* 4055 */ 383 sys sys_ni_syscall 2 384 sys sys_setpgid 2 385 sys sys_ni_syscall, 0 386 sys sys_ni_syscall 0 /* was sys_olduname */ 387 sys sys_umask 1 /* 4060 */ 388 sys sys_chroot 1 389 sys sys32_ustat 2 390 sys sys_dup2 2 391 sys sys_getppid 0 392 sys sys_getpgrp 0 /* 4065 */ 393 sys sys_setsid 0 394 sys sys32_sigaction 3 395 sys sys_sgetmask 0 396 sys sys_ssetmask 1 397 sys sys_setreuid 2 /* 4070 */ 398 sys sys_setregid 2 399 sys sys32_sigsuspend 0 400 sys sys32_sigpending 1 401 sys sys_sethostname 2 402 sys sys32_setrlimit 2 /* 4075 */ 403 sys sys32_getrlimit 2 404 sys sys32_getrusage 2 405 sys sys32_gettimeofday 2 406 sys sys32_settimeofday 2 407 sys sys_getgroups 2 /* 4080 */ 408 sys sys_setgroups 2 409 sys sys_ni_syscall 0 /* old_select */ 410 sys sys_symlink 2 411 sys sys_ni_syscall 0 /* was sys_lstat */ 412 sys sys_readlink 3 /* 4085 */ 413 sys sys_uselib 1 414 sys sys_swapon 2 415 sys sys_reboot 3 416 sys sys32_readdir 3 417 sys sys_mmap 6 /* 4090 */ 418 sys sys_munmap 2 419 sys sys_truncate 2 420 sys sys_ftruncate 2 421 sys sys_fchmod 2 422 sys sys_fchown 3 /* 4095 */ 423 sys sys_getpriority 2 424 sys sys_setpriority 3 425 sys sys_ni_syscall 0 426 sys sys32_statfs 2 427 sys sys32_fstatfs 2 /* 4100 */ 428 sys sys_ni_syscall 0 /* sys_ioperm */ 429 sys sys32_socketcall 2 430 sys sys_syslog 3 431 sys sys32_setitimer 3 432 sys sys32_getitimer 2 /* 4105 */ 433 sys sys32_newstat 2 434 sys sys32_newlstat 2 435 sys sys32_newfstat 2 436 sys sys_ni_syscall 0 /* was sys_uname */ 437 sys sys_ni_syscall 0 /* sys_ioperm *//* 4110 */ 438 sys sys_vhangup 0 439 sys sys_ni_syscall 0 /* was sys_idle */ 440 sys sys_ni_syscall 0 /* sys_vm86 */ 441 sys sys32_wait4 4 442 sys sys_swapoff 1 /* 4115 */ 443 sys sys32_sysinfo 1 444 sys sys32_ipc 6 445 sys sys_fsync 1 446 sys sys32_sigreturn 0 447 sys sys_clone 0 /* 4120 */ 448 sys sys_setdomainname 2 449 sys sys32_newuname 1 450 sys sys_ni_syscall 0 /* sys_modify_ldt */ 451 sys sys32_adjtimex 1 452 sys sys_mprotect 3 /* 4125 */ 453 sys sys32_sigprocmask 3 454 sys sys32_create_module 2 455 sys sys32_init_module 5 456 sys sys32_delete_module 1 457 sys sys32_get_kernel_syms 1 /* 4130 */ 458 sys sys_quotactl 0 459 sys sys_getpgid 1 460 sys sys_fchdir 1 461 sys sys_bdflush 2 462 sys sys_sysfs 3 /* 4135 */ 463 sys sys32_personality 1 464 sys sys_ni_syscall 0 /* for afs_syscall */ 465 sys sys_setfsuid 1 466 sys sys_setfsgid 1 467 sys sys32_llseek 5 /* 4140 */ 468 sys sys32_getdents 3 469 sys sys32_select 5 470 sys sys_flock 2 471 sys sys_msync 3 472 sys sys32_readv 3 /* 4145 */ 473 sys sys32_writev 3 474 sys sys_cacheflush 3 475 sys sys_cachectl 3 476 sys sys32_sysmips 4 477 sys sys_ni_syscall 0 /* 4150 */ 478 sys sys_getsid 1 479 sys sys_fdatasync 0 480 sys sys32_sysctl 1 481 sys sys_mlock 2 482 sys sys_munlock 2 /* 4155 */ 483 sys sys_mlockall 1 484 sys sys_munlockall 0 485 sys sys_sched_setparam 2 486 sys sys_sched_getparam 2 487 sys sys_sched_setscheduler 3 /* 4160 */ 488 sys sys_sched_getscheduler 1 489 sys sys_sched_yield 0 490 sys sys_sched_get_priority_max 1 491 sys sys_sched_get_priority_min 1 492 sys sys32_sched_rr_get_interval 2 /* 4165 */ 493 sys sys32_nanosleep 2 494 sys sys_mremap 4 495 sys sys_accept 3 496 sys sys_bind 3 497 sys sys_connect 3 /* 4170 */ 498 sys sys_getpeername 3 499 sys sys_getsockname 3 500 sys sys_getsockopt 5 501 sys sys_listen 2 502 sys sys_recv 4 /* 4175 */ 503 sys sys_recvfrom 6 504 sys sys32_recvmsg 3 505 sys sys_send 4 506 sys sys32_sendmsg 3 507 sys sys_sendto 6 /* 4180 */ 508 sys sys32_setsockopt 5 509 sys sys_shutdown 2 510 sys sys_socket 3 511 sys sys_socketpair 4 512 sys sys_setresuid 3 /* 4185 */ 513 sys sys_getresuid 3 514 sys sys32_query_module 5 515 sys sys_poll 3 516 sys sys_nfsservctl 3 517 sys sys_setresgid 3 /* 4190 */ 518 sys sys_getresgid 3 519 sys sys_prctl 5 520 sys sys32_rt_sigreturn 0 521 sys sys32_rt_sigaction 4 522 sys sys32_rt_sigprocmask 4 /* 4195 */ 523 sys sys32_rt_sigpending 2 524 sys sys32_rt_sigtimedwait 4 525 sys sys32_rt_sigqueueinfo 3 526 sys sys32_rt_sigsuspend 0 527 sys sys32_pread 6 /* 4200 */ 528 sys sys32_pwrite 6 529 sys sys_chown 3 530 sys sys_getcwd 2 531 sys sys_capget 2 532 sys sys_capset 2 /* 4205 */ 533 sys sys32_sigaltstack 0 534 sys sys32_sendfile 4 535 sys sys_ni_syscall 0 536 sys sys_ni_syscall 0 537 sys sys32_mmap2 6 /* 4210 */ 538 sys sys32_truncate64 4 539 sys sys32_ftruncate64 4 540 sys sys_newstat 2 541 sys sys_newlstat 2 542 sys sys_newfstat 2 /* 4215 */ 543 sys sys_pivot_root 2 544 sys sys_mincore 3 545 sys sys_madvise 3 546 sys sys_getdents64 3 547 sys sys32_fcntl64 3 /* 4220 */ 548 sys sys_ni_syscall 0 549 sys sys_gettid 0 550 sys sys32_readahead 5 551 sys sys_setxattr 5 552 sys sys_lsetxattr 5 /* 4225 */ 553 sys sys_fsetxattr 5 554 sys sys_getxattr 4 555 sys sys_lgetxattr 4 556 sys sys_fgetxattr 4 557 sys sys_listxattr 3 /* 4230 */ 558 sys sys_llistxattr 3 559 sys sys_flistxattr 3 560 sys sys_removexattr 2 561 sys sys_lremovexattr 2 562 sys sys_fremovexattr 2 /* 4235 */ 563 sys sys_tkill, 2 564 sys sys_sendfile64, 5 565 sys sys_ni_syscall, 0 /* res. for futex */ 566 sys sys_ni_syscall, 0 /* res. for sched_setaffinity */ 567 sys sys_ni_syscall, 0 /* 4240 res. for sched_getaffinity */ 568 569 .endm 570 571 .macro sys function, nargs 572 PTR \function 573 .endm 574 575 .align 3 576sys_call_table: 577 syscalltable 578 579 .macro sys function, nargs 580 .byte \nargs 581 .endm 582 583sys_narg_table: 584 syscalltable 585