Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 1995 - 2000, 2001 by Ralf Baechle
0007  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
0008  * Copyright (C) 2001 MIPS Technologies, Inc.
0009  * Copyright (C) 2004 Thiemo Seufer
0010  *
0011  * Hairy, the userspace application uses a different argument passing
0012  * convention than the kernel, so we have to translate things from o32
0013  * to ABI64 calling convention.  64-bit syscalls are also processed
0014  * here for now.
0015  */
0016 #include <linux/errno.h>
0017 #include <asm/asm.h>
0018 #include <asm/asmmacro.h>
0019 #include <asm/irqflags.h>
0020 #include <asm/mipsregs.h>
0021 #include <asm/regdef.h>
0022 #include <asm/stackframe.h>
0023 #include <asm/thread_info.h>
0024 #include <asm/unistd.h>
0025 #include <asm/sysmips.h>
0026 
0027     .align  5
0028 NESTED(handle_sys, PT_SIZE, sp)
0029     .set    noat
0030     SAVE_SOME
0031     TRACE_IRQS_ON_RELOAD
0032     STI
0033     .set    at
0034     ld  t1, PT_EPC(sp)      # skip syscall on return
0035 
0036     dsubu   t0, v0, __NR_O32_Linux  # check syscall number
0037     sltiu   t0, t0, __NR_O32_Linux_syscalls
0038     daddiu  t1, 4           # skip to next instruction
0039     sd  t1, PT_EPC(sp)
0040     beqz    t0, not_o32_scall
0041 #if 0
0042  SAVE_ALL
0043  move a1, v0
0044  ASM_PRINT("Scall %ld\n")
0045  RESTORE_ALL
0046 #endif
0047 
0048     /* We don't want to stumble over broken sign extensions from
0049        userland. O32 does never use the upper half. */
0050     sll a0, a0, 0
0051     sll a1, a1, 0
0052     sll a2, a2, 0
0053     sll a3, a3, 0
0054 
0055     sd  a3, PT_R26(sp)      # save a3 for syscall restarting
0056 
0057     /*
0058      * More than four arguments.  Try to deal with it by copying the
0059      * stack arguments from the user stack to the kernel stack.
0060      * This Sucks (TM).
0061      *
0062      * We intentionally keep the kernel stack a little below the top of
0063      * userspace so we don't have to do a slower byte accurate check here.
0064      */
0065     ld  t0, PT_R29(sp)      # get old user stack pointer
0066     daddu   t1, t0, 32
0067     bltz    t1, bad_stack
0068 
0069 load_a4: lw a4, 16(t0)      # argument #5 from usp
0070 load_a5: lw a5, 20(t0)      # argument #6 from usp
0071 load_a6: lw a6, 24(t0)      # argument #7 from usp
0072 load_a7: lw a7, 28(t0)      # argument #8 from usp
0073 loads_done:
0074 
0075     .section __ex_table,"a"
0076     PTR_WD  load_a4, bad_stack_a4
0077     PTR_WD  load_a5, bad_stack_a5
0078     PTR_WD  load_a6, bad_stack_a6
0079     PTR_WD  load_a7, bad_stack_a7
0080     .previous
0081 
0082     li  t1, _TIF_WORK_SYSCALL_ENTRY
0083     LONG_L  t0, TI_FLAGS($28)   # syscall tracing enabled?
0084     and t0, t1, t0
0085     bnez    t0, trace_a_syscall
0086 
0087 syscall_common:
0088     dsll    t0, v0, 3       # offset into table
0089     ld  t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
0090 
0091     jalr    t2          # Do The Real Thing (TM)
0092 
0093     li  t0, -EMAXERRNO - 1  # error?
0094     sltu    t0, t0, v0
0095     sd  t0, PT_R7(sp)       # set error flag
0096     beqz    t0, 1f
0097 
0098     ld  t1, PT_R2(sp)       # syscall number
0099     dnegu   v0          # error
0100     sd  t1, PT_R0(sp)       # save it for syscall restarting
0101 1:  sd  v0, PT_R2(sp)       # result
0102 
0103 o32_syscall_exit:
0104     j   syscall_exit_partial
0105 
0106 /* ------------------------------------------------------------------------ */
0107 
0108 trace_a_syscall:
0109     SAVE_STATIC
0110     sd  a4, PT_R8(sp)       # Save argument registers
0111     sd  a5, PT_R9(sp)
0112     sd  a6, PT_R10(sp)
0113     sd  a7, PT_R11(sp)      # For indirect syscalls
0114 
0115     move    a0, sp
0116     /*
0117      * absolute syscall number is in v0 unless we called syscall(__NR_###)
0118      * where the real syscall number is in a0
0119      * note: NR_syscall is the first O32 syscall but the macro is
0120      * only defined when compiling with -mabi=32 (CONFIG_32BIT)
0121      * therefore __NR_O32_Linux is used (4000)
0122      */
0123     .set    push
0124     .set    reorder
0125     subu    t1, v0,  __NR_O32_Linux
0126     move    a1, v0
0127     bnez    t1, 1f /* __NR_syscall at offset 0 */
0128     ld  a1, PT_R4(sp) /* Arg1 for __NR_syscall case */
0129     .set    pop
0130 
0131 1:  jal syscall_trace_enter
0132 
0133     bltz    v0, 1f          # seccomp failed? Skip syscall
0134 
0135     RESTORE_STATIC
0136     ld  v0, PT_R2(sp)       # Restore syscall (maybe modified)
0137     ld  a0, PT_R4(sp)       # Restore argument registers
0138     ld  a1, PT_R5(sp)
0139     ld  a2, PT_R6(sp)
0140     ld  a3, PT_R7(sp)
0141     ld  a4, PT_R8(sp)
0142     ld  a5, PT_R9(sp)
0143     ld  a6, PT_R10(sp)
0144     ld  a7, PT_R11(sp)      # For indirect syscalls
0145 
0146     dsubu   t0, v0, __NR_O32_Linux  # check (new) syscall number
0147     sltiu   t0, t0, __NR_O32_Linux_syscalls
0148     beqz    t0, not_o32_scall
0149 
0150     j   syscall_common
0151 
0152 1:  j   syscall_exit
0153 
0154 /* ------------------------------------------------------------------------ */
0155 
0156     /*
0157      * The stackpointer for a call with more than 4 arguments is bad.
0158      */
0159 bad_stack:
0160     li  v0, EFAULT
0161     sd  v0, PT_R2(sp)
0162     li  t0, 1           # set error flag
0163     sd  t0, PT_R7(sp)
0164     j   o32_syscall_exit
0165 
0166 bad_stack_a4:
0167     li  a4, 0
0168     b   load_a5
0169 
0170 bad_stack_a5:
0171     li  a5, 0
0172     b   load_a6
0173 
0174 bad_stack_a6:
0175     li  a6, 0
0176     b   load_a7
0177 
0178 bad_stack_a7:
0179     li  a7, 0
0180     b   loads_done
0181 
0182 not_o32_scall:
0183     /*
0184      * This is not an o32 compatibility syscall, pass it on
0185      * to the 64-bit syscall handlers.
0186      */
0187 #ifdef CONFIG_MIPS32_N32
0188     j   handle_sysn32
0189 #else
0190     j   handle_sys64
0191 #endif
0192     END(handle_sys)
0193 
0194 LEAF(sys32_syscall)
0195     subu    t0, a0, __NR_O32_Linux  # check syscall number
0196     sltiu   v0, t0, __NR_O32_Linux_syscalls
0197     beqz    t0, einval      # do not recurse
0198     dsll    t1, t0, 3
0199     beqz    v0, einval
0200     ld  t2, sys32_call_table(t1)        # syscall routine
0201 
0202     move    a0, a1          # shift argument registers
0203     move    a1, a2
0204     move    a2, a3
0205     move    a3, a4
0206     move    a4, a5
0207     move    a5, a6
0208     move    a6, a7
0209     jr  t2
0210     /* Unreached */
0211 
0212 einval: li  v0, -ENOSYS
0213     jr  ra
0214     END(sys32_syscall)
0215 
0216 #define __SYSCALL_WITH_COMPAT(nr, native, compat)   __SYSCALL(nr, compat)
0217 #define __SYSCALL(nr, entry)    PTR_WD entry
0218     .align  3
0219     .type   sys32_call_table,@object
0220 EXPORT(sys32_call_table)
0221 #include <asm/syscall_table_o32.h>