linux/arch/mips/kernel/scall32-o32.S
<<
>>
Prefs
   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-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
   7 * Copyright (C) 2001 MIPS Technologies, Inc.
   8 * Copyright (C) 2004 Thiemo Seufer
   9 * Copyright (C) 2014 Imagination Technologies Ltd.
  10 */
  11#include <linux/errno.h>
  12#include <asm/asm.h>
  13#include <asm/asmmacro.h>
  14#include <asm/irqflags.h>
  15#include <asm/mipsregs.h>
  16#include <asm/regdef.h>
  17#include <asm/stackframe.h>
  18#include <asm/isadep.h>
  19#include <asm/sysmips.h>
  20#include <asm/thread_info.h>
  21#include <asm/unistd.h>
  22#include <asm/war.h>
  23#include <asm/asm-offsets.h>
  24
  25        .align  5
  26NESTED(handle_sys, PT_SIZE, sp)
  27        .set    noat
  28        SAVE_SOME
  29        TRACE_IRQS_ON_RELOAD
  30        STI
  31        .set    at
  32
  33        lw      t1, PT_EPC(sp)          # skip syscall on return
  34
  35        addiu   t1, 4                   # skip to next instruction
  36        sw      t1, PT_EPC(sp)
  37
  38        sw      a3, PT_R26(sp)          # save a3 for syscall restarting
  39
  40        /*
  41         * More than four arguments.  Try to deal with it by copying the
  42         * stack arguments from the user stack to the kernel stack.
  43         * This Sucks (TM).
  44         */
  45        lw      t0, PT_R29(sp)          # get old user stack pointer
  46
  47        /*
  48         * We intentionally keep the kernel stack a little below the top of
  49         * userspace so we don't have to do a slower byte accurate check here.
  50         */
  51        lw      t5, TI_ADDR_LIMIT($28)
  52        addu    t4, t0, 32
  53        and     t5, t4
  54        bltz    t5, bad_stack           # -> sp is bad
  55
  56        /*
  57         * Ok, copy the args from the luser stack to the kernel stack.
  58         */
  59
  60        .set    push
  61        .set    noreorder
  62        .set    nomacro
  63
  64load_a4: user_lw(t5, 16(t0))            # argument #5 from usp
  65load_a5: user_lw(t6, 20(t0))            # argument #6 from usp
  66load_a6: user_lw(t7, 24(t0))            # argument #7 from usp
  67load_a7: user_lw(t8, 28(t0))            # argument #8 from usp
  68loads_done:
  69
  70        sw      t5, 16(sp)              # argument #5 to ksp
  71        sw      t6, 20(sp)              # argument #6 to ksp
  72        sw      t7, 24(sp)              # argument #7 to ksp
  73        sw      t8, 28(sp)              # argument #8 to ksp
  74        .set    pop
  75
  76        .section __ex_table,"a"
  77        PTR     load_a4, bad_stack_a4
  78        PTR     load_a5, bad_stack_a5
  79        PTR     load_a6, bad_stack_a6
  80        PTR     load_a7, bad_stack_a7
  81        .previous
  82
  83        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
  84        li      t1, _TIF_WORK_SYSCALL_ENTRY
  85        and     t0, t1
  86        bnez    t0, syscall_trace_entry # -> yes
  87syscall_common:
  88        subu    v0, v0, __NR_O32_Linux  # check syscall number
  89        sltiu   t0, v0, __NR_O32_Linux_syscalls
  90        beqz    t0, illegal_syscall
  91
  92        sll     t0, v0, 2
  93        la      t1, sys_call_table
  94        addu    t1, t0
  95        lw      t2, (t1)                # syscall routine
  96
  97        beqz    t2, illegal_syscall
  98
  99        jalr    t2                      # Do The Real Thing (TM)
 100
 101        li      t0, -EMAXERRNO - 1      # error?
 102        sltu    t0, t0, v0
 103        sw      t0, PT_R7(sp)           # set error flag
 104        beqz    t0, 1f
 105
 106        lw      t1, PT_R2(sp)           # syscall number
 107        negu    v0                      # error
 108        sw      t1, PT_R0(sp)           # save it for syscall restarting
 1091:      sw      v0, PT_R2(sp)           # result
 110
 111o32_syscall_exit:
 112        j       syscall_exit_partial
 113
 114/* ------------------------------------------------------------------------ */
 115
 116syscall_trace_entry:
 117        SAVE_STATIC
 118        move    a0, sp
 119
 120        /*
 121         * syscall number is in v0 unless we called syscall(__NR_###)
 122         * where the real syscall number is in a0
 123         */
 124        move    a1, v0
 125        subu    t2, v0,  __NR_O32_Linux
 126        bnez    t2, 1f /* __NR_syscall at offset 0 */
 127        lw      a1, PT_R4(sp)
 128
 1291:      jal     syscall_trace_enter
 130
 131        bltz    v0, 1f                  # seccomp failed? Skip syscall
 132
 133        RESTORE_STATIC
 134        lw      v0, PT_R2(sp)           # Restore syscall (maybe modified)
 135        lw      a0, PT_R4(sp)           # Restore argument registers
 136        lw      a1, PT_R5(sp)
 137        lw      a2, PT_R6(sp)
 138        lw      a3, PT_R7(sp)
 139        j       syscall_common
 140
 1411:      j       syscall_exit
 142
 143/* ------------------------------------------------------------------------ */
 144
 145        /*
 146         * Our open-coded access area sanity test for the stack pointer
 147         * failed. We probably should handle this case a bit more drastic.
 148         */
 149bad_stack:
 150        li      v0, EFAULT
 151        sw      v0, PT_R2(sp)
 152        li      t0, 1                           # set error flag
 153        sw      t0, PT_R7(sp)
 154        j       o32_syscall_exit
 155
 156bad_stack_a4:
 157        li      t5, 0
 158        b       load_a5
 159
 160bad_stack_a5:
 161        li      t6, 0
 162        b       load_a6
 163
 164bad_stack_a6:
 165        li      t7, 0
 166        b       load_a7
 167
 168bad_stack_a7:
 169        li      t8, 0
 170        b       loads_done
 171
 172        /*
 173         * The system call does not exist in this kernel
 174         */
 175illegal_syscall:
 176        li      v0, ENOSYS                      # error
 177        sw      v0, PT_R2(sp)
 178        li      t0, 1                           # set error flag
 179        sw      t0, PT_R7(sp)
 180        j       o32_syscall_exit
 181        END(handle_sys)
 182
 183        LEAF(sys_syscall)
 184        subu    t0, a0, __NR_O32_Linux  # check syscall number
 185        sltiu   v0, t0, __NR_O32_Linux_syscalls
 186        beqz    t0, einval              # do not recurse
 187        sll     t1, t0, 2
 188        beqz    v0, einval
 189        lw      t2, sys_call_table(t1)          # syscall routine
 190
 191        move    a0, a1                          # shift argument registers
 192        move    a1, a2
 193        move    a2, a3
 194        lw      a3, 16(sp)
 195        lw      t4, 20(sp)
 196        lw      t5, 24(sp)
 197        lw      t6, 28(sp)
 198        sw      t4, 16(sp)
 199        sw      t5, 20(sp)
 200        sw      t6, 24(sp)
 201        jr      t2
 202        /* Unreached */
 203
 204einval: li      v0, -ENOSYS
 205        jr      ra
 206        END(sys_syscall)
 207
 208#ifdef CONFIG_MIPS_MT_FPAFF
 209        /*
 210         * For FPU affinity scheduling on MIPS MT processors, we need to
 211         * intercept sys_sched_xxxaffinity() calls until we get a proper hook
 212         * in kernel/sched/core.c.  Considered only temporary we only support
 213         * these hooks for the 32-bit kernel - there is no MIPS64 MT processor
 214         * atm.
 215         */
 216#define sys_sched_setaffinity   mipsmt_sys_sched_setaffinity
 217#define sys_sched_getaffinity   mipsmt_sys_sched_getaffinity
 218#endif /* CONFIG_MIPS_MT_FPAFF */
 219
 220#define __SYSCALL(nr, entry)    PTR entry
 221        .align  2
 222        .type   sys_call_table, @object
 223EXPORT(sys_call_table)
 224#include <asm/syscall_table_32_o32.h>
 225#undef __SYSCALL
 226