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-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
0007  * Copyright (C) 2001 MIPS Technologies, Inc.
0008  * Copyright (C) 2004 Thiemo Seufer
0009  * Copyright (C) 2014 Imagination Technologies Ltd.
0010  */
0011 #include <linux/errno.h>
0012 #include <asm/asm.h>
0013 #include <asm/asmmacro.h>
0014 #include <asm/irqflags.h>
0015 #include <asm/mipsregs.h>
0016 #include <asm/regdef.h>
0017 #include <asm/stackframe.h>
0018 #include <asm/isadep.h>
0019 #include <asm/sysmips.h>
0020 #include <asm/thread_info.h>
0021 #include <asm/unistd.h>
0022 #include <asm/asm-offsets.h>
0023 
0024     .align  5
0025 NESTED(handle_sys, PT_SIZE, sp)
0026     .set    noat
0027     SAVE_SOME
0028     TRACE_IRQS_ON_RELOAD
0029     STI
0030     .set    at
0031 
0032     lw  t1, PT_EPC(sp)      # skip syscall on return
0033 
0034     addiu   t1, 4           # skip to next instruction
0035     sw  t1, PT_EPC(sp)
0036 
0037     sw  a3, PT_R26(sp)      # save a3 for syscall restarting
0038 
0039     /*
0040      * More than four arguments.  Try to deal with it by copying the
0041      * stack arguments from the user stack to the kernel stack.
0042      * This Sucks (TM).
0043      */
0044     lw  t0, PT_R29(sp)      # get old user stack pointer
0045 
0046     /*
0047      * We intentionally keep the kernel stack a little below the top of
0048      * userspace so we don't have to do a slower byte accurate check here.
0049      */
0050     addu    t4, t0, 32
0051     bltz    t4, bad_stack       # -> sp is bad
0052 
0053     /*
0054      * Ok, copy the args from the luser stack to the kernel stack.
0055      */
0056 
0057     .set    push
0058     .set    noreorder
0059     .set    nomacro
0060 
0061 load_a4: user_lw(t5, 16(t0))        # argument #5 from usp
0062 load_a5: user_lw(t6, 20(t0))        # argument #6 from usp
0063 load_a6: user_lw(t7, 24(t0))        # argument #7 from usp
0064 load_a7: user_lw(t8, 28(t0))        # argument #8 from usp
0065 loads_done:
0066 
0067     sw  t5, 16(sp)      # argument #5 to ksp
0068     sw  t6, 20(sp)      # argument #6 to ksp
0069     sw  t7, 24(sp)      # argument #7 to ksp
0070     sw  t8, 28(sp)      # argument #8 to ksp
0071     .set    pop
0072 
0073     .section __ex_table,"a"
0074     PTR_WD  load_a4, bad_stack_a4
0075     PTR_WD  load_a5, bad_stack_a5
0076     PTR_WD  load_a6, bad_stack_a6
0077     PTR_WD  load_a7, bad_stack_a7
0078     .previous
0079 
0080     lw  t0, TI_FLAGS($28)   # syscall tracing enabled?
0081     li  t1, _TIF_WORK_SYSCALL_ENTRY
0082     and t0, t1
0083     bnez    t0, syscall_trace_entry # -> yes
0084 syscall_common:
0085     subu    v0, v0, __NR_O32_Linux  # check syscall number
0086     sltiu   t0, v0, __NR_O32_Linux_syscalls
0087     beqz    t0, illegal_syscall
0088 
0089     sll t0, v0, 2
0090     la  t1, sys_call_table
0091     addu    t1, t0
0092     lw  t2, (t1)        # syscall routine
0093 
0094     beqz    t2, illegal_syscall
0095 
0096     jalr    t2          # Do The Real Thing (TM)
0097 
0098     li  t0, -EMAXERRNO - 1  # error?
0099     sltu    t0, t0, v0
0100     sw  t0, PT_R7(sp)       # set error flag
0101     beqz    t0, 1f
0102 
0103     lw  t1, PT_R2(sp)       # syscall number
0104     negu    v0          # error
0105     sw  t1, PT_R0(sp)       # save it for syscall restarting
0106 1:  sw  v0, PT_R2(sp)       # result
0107 
0108 o32_syscall_exit:
0109     j   syscall_exit_partial
0110 
0111 /* ------------------------------------------------------------------------ */
0112 
0113 syscall_trace_entry:
0114     SAVE_STATIC
0115     move    a0, sp
0116 
0117     /*
0118      * syscall number is in v0 unless we called syscall(__NR_###)
0119      * where the real syscall number is in a0
0120      */
0121     move    a1, v0
0122     subu    t2, v0,  __NR_O32_Linux
0123     bnez    t2, 1f /* __NR_syscall at offset 0 */
0124     lw  a1, PT_R4(sp)
0125 
0126 1:  jal syscall_trace_enter
0127 
0128     bltz    v0, 1f          # seccomp failed? Skip syscall
0129 
0130     RESTORE_STATIC
0131     lw  v0, PT_R2(sp)       # Restore syscall (maybe modified)
0132     lw  a0, PT_R4(sp)       # Restore argument registers
0133     lw  a1, PT_R5(sp)
0134     lw  a2, PT_R6(sp)
0135     lw  a3, PT_R7(sp)
0136     j   syscall_common
0137 
0138 1:  j   syscall_exit
0139 
0140 /* ------------------------------------------------------------------------ */
0141 
0142     /*
0143      * Our open-coded access area sanity test for the stack pointer
0144      * failed. We probably should handle this case a bit more drastic.
0145      */
0146 bad_stack:
0147     li  v0, EFAULT
0148     sw  v0, PT_R2(sp)
0149     li  t0, 1               # set error flag
0150     sw  t0, PT_R7(sp)
0151     j   o32_syscall_exit
0152 
0153 bad_stack_a4:
0154     li  t5, 0
0155     b   load_a5
0156 
0157 bad_stack_a5:
0158     li  t6, 0
0159     b   load_a6
0160 
0161 bad_stack_a6:
0162     li  t7, 0
0163     b   load_a7
0164 
0165 bad_stack_a7:
0166     li  t8, 0
0167     b   loads_done
0168 
0169     /*
0170      * The system call does not exist in this kernel
0171      */
0172 illegal_syscall:
0173     li  v0, ENOSYS          # error
0174     sw  v0, PT_R2(sp)
0175     li  t0, 1               # set error flag
0176     sw  t0, PT_R7(sp)
0177     j   o32_syscall_exit
0178     END(handle_sys)
0179 
0180     LEAF(sys_syscall)
0181     subu    t0, a0, __NR_O32_Linux  # check syscall number
0182     sltiu   v0, t0, __NR_O32_Linux_syscalls
0183     beqz    t0, einval      # do not recurse
0184     sll t1, t0, 2
0185     beqz    v0, einval
0186     lw  t2, sys_call_table(t1)      # syscall routine
0187 
0188     move    a0, a1              # shift argument registers
0189     move    a1, a2
0190     move    a2, a3
0191     lw  a3, 16(sp)
0192     lw  t4, 20(sp)
0193     lw  t5, 24(sp)
0194     lw  t6, 28(sp)
0195     sw  t4, 16(sp)
0196     sw  t5, 20(sp)
0197     sw  t6, 24(sp)
0198     jr  t2
0199     /* Unreached */
0200 
0201 einval: li  v0, -ENOSYS
0202     jr  ra
0203     END(sys_syscall)
0204 
0205 #ifdef CONFIG_MIPS_MT_FPAFF
0206     /*
0207      * For FPU affinity scheduling on MIPS MT processors, we need to
0208      * intercept sys_sched_xxxaffinity() calls until we get a proper hook
0209      * in kernel/sched/core.c.  Considered only temporary we only support
0210      * these hooks for the 32-bit kernel - there is no MIPS64 MT processor
0211      * atm.
0212      */
0213 #define sys_sched_setaffinity   mipsmt_sys_sched_setaffinity
0214 #define sys_sched_getaffinity   mipsmt_sys_sched_getaffinity
0215 #endif /* CONFIG_MIPS_MT_FPAFF */
0216 
0217 #define __SYSCALL_WITH_COMPAT(nr, native, compat)   __SYSCALL(nr, native)
0218 #define __SYSCALL(nr, entry)    PTR_WD entry
0219     .align  2
0220     .type   sys_call_table, @object
0221 EXPORT(sys_call_table)
0222 #include <asm/syscall_table_o32.h>