📄 scall_o32.s
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1997, 1998, 1999, 2000, 2001 by Ralf Baechle * Copyright (C) 2001 MIPS Technologies, Inc. */#include <linux/config.h>#include <linux/errno.h>#include <asm/asm.h>#include <asm/current.h>#include <asm/mipsregs.h>#include <asm/regdef.h>#include <asm/stackframe.h>#include <asm/isadep.h>#include <asm/sysmips.h>#include <asm/unistd.h>/* Highest syscall used of any syscall flavour */#define MAX_SYSCALL_NO __NR_Linux + __NR_Linux_syscalls .align 5NESTED(handle_sys, PT_SIZE, sp) .set noat SAVE_SOME STI .set at lw t1, PT_EPC(sp) # skip syscall on return sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number addiu t1, 4 # skip to next instruction beqz t0, illegal_syscall sw t1, PT_EPC(sp) /* XXX Put both in one cacheline, should save a bit. */ sll t0, v0, 2 lw t2, sys_call_table(t0) # syscall routine lbu t3, sys_narg_table(v0) # number of arguments beqz t2, illegal_syscall subu t0, t3, 5 # 5 or more arguments? sw a3, PT_R26(sp) # save a3 for syscall restarting bgez t0, stackargsstack_done: sw a3, PT_R26(sp) # save for syscall restart lw t0, TASK_PTRACE($28) # syscall tracing enabled? andi t0, _PT_TRACESYS bnez t0, trace_a_syscall jalr t2 # Do The Real Thing (TM) li t0, -EMAXERRNO - 1 # error? sltu t0, t0, v0 sw t0, PT_R7(sp) # set error flag beqz t0, 1f negu v0 # error sw v0, PT_R0(sp) # set flag for syscall restarting1: sw v0, PT_R2(sp) # resultfast_ret_from_sys_call:ret_from_schedule: mfc0 t0, CP0_STATUS # need_resched and signals atomic test ori t0, t0, 1 xori t0, t0, 1 mtc0 t0, CP0_STATUS SSNOP; SSNOP; SSNOP lw t2, TASK_NEED_RESCHED($28) lw v0, TASK_SIGPENDING($28) bnez t2, reschedule bnez v0, signal_returnrestore_all: RESTORE_SOME RESTORE_SP_AND_RET/* ------------------------------------------------------------------------ */FEXPORT(ret_from_fork) move a0, v0 # prev jal schedule_tail lw t0, TASK_PTRACE($28) # syscall tracing enabled? andi t0, _PT_TRACESYS bnez t0, tracesys_exitstatic_ret_from_sys_call: RESTORE_STATIC j fast_ret_from_sys_call/* ------------------------------------------------------------------------ *//* ret_from_sys_call should be here but is in entry.S. *//* ------------------------------------------------------------------------ *//* Put this behind restore_all for the sake of the branch prediction. */signal_return: .type signal_return, @function mfc0 t0, CP0_STATUS ori t0, t0, 1 mtc0 t0, CP0_STATUS SAVE_STATIC move a0, zero move a1, sp jal do_signal RESTORE_STATIC b restore_all/* ------------------------------------------------------------------------ */reschedule: jal schedule b ret_from_schedule/* ------------------------------------------------------------------------ */trace_a_syscall: SAVE_STATIC sw t2, PT_R1(sp) jal syscall_trace lw t2, PT_R1(sp) lw a0, PT_R4(sp) # Restore argument registers lw a1, PT_R5(sp) lw a2, PT_R6(sp) lw a3, PT_R7(sp) jalr t2 li t0, -EMAXERRNO - 1 # error? sltu t0, t0, v0 sw t0, PT_R7(sp) # set error flag beqz t0, 1f negu v0 # error sw v0, PT_R0(sp) # set flag for syscall restarting1: sw v0, PT_R2(sp) # resulttracesys_exit: jal syscall_trace j static_ret_from_sys_call/* ------------------------------------------------------------------------ */ /* * More than four arguments. Try to deal with it by copying the * stack arguments from the user stack to the kernel stack. * This Sucks (TM). */stackargs: lw t0, PT_R29(sp) # get old user stack pointer subu t3, 4 sll t1, t3, 2 # stack valid? addu t1, t0 # end address or t0, t1 bltz t0, bad_stack # -> sp is bad lw t0, PT_R29(sp) # get old user stack pointer PTR_LA t1, 3f # copy 1 to 2 arguments sll t3, t3, 4 subu t1, t3 jr t1 /* Ok, copy the args from the luser stack to the kernel stack */ /* * I know Ralf doesn't like nops but this avoids code * duplication for R3000 targets (and this is the * only place where ".set reorder" doesn't help). * Harald. */ .set push .set noreorder .set nomacro1: lw t1, 20(t0) # argument #6 from usp nop sw t1, 20(sp) nop2: lw t1, 16(t0) # argument #5 from usp nop sw t1, 16(sp) nop3: .set pop j stack_done # go back .section __ex_table,"a" PTR 1b,bad_stack PTR 2b,bad_stack .previous/* ------------------------------------------------------------------------ */ /* * The stackpointer for a call with more than 4 arguments is bad. * We probably should handle this case a bit more drastic. */bad_stack: negu v0 # error sw v0, PT_R0(sp) sw v0, PT_R2(sp) li t0, 1 # set error flag sw t0, PT_R7(sp) j fast_ret_from_sys_call/* ------------------------------------------------------------------------ */ /* * The system call does not exist in this kernel */illegal_syscall: lw t0, TASK_PTRACE($28) # syscall tracing enabled? andi t0, _PT_TRACESYS beqz t0, 1f SAVE_STATIC jal syscall_trace li t0, _PT_TRACESYS1: li v0, ENOSYS # error sw v0, PT_R0(sp) # set flag for syscall restarting sw v0, PT_R2(sp) li t1, 1 # set error flag sw t1, PT_R7(sp) bnez t0, tracesys_exit j fast_ret_from_sys_callEND(handle_sys)LEAF(mips_atomic_set) andi v0, a1, 3 # must be word aligned bnez v0, bad_alignment lw v1, THREAD_CURDS($28) # in legal address range? addiu a0, a1, 4 or a0, a0, a1 and a0, a0, v1 bltz a0, bad_address#ifdef CONFIG_CPU_HAS_LLSC /* Ok, this is the ll/sc case. World is sane :-) */1: ll v0, (a1) move a0, a22: sc a0, (a1) beqz a0, 1b .section __ex_table,"a" PTR 1b, bad_stack PTR 2b, bad_stack .previous#else sw a1, 16(sp) sw a2, 20(sp) move a0, sp move a2, a1 li a1, 1 jal do_page_fault lw a1, 16(sp) lw a2, 20(sp) /* * At this point the page should be readable and writable unless * there was no more memory available. */1: lw v0, (a1)2: sw a2, (a1) .section __ex_table,"a" PTR 1b, no_mem PTR 2b, no_mem .previous#endif sw zero, PT_R7(sp) # success sw v0, PT_R2(sp) # result /* Success, so skip usual error handling garbage. */ lw t0, TASK_PTRACE($28) # syscall tracing enabled? andi t0, _PT_TRACESYS beqz t0, fast_ret_from_sys_call SAVE_STATIC jal syscall_trace j static_ret_from_sys_callno_mem: li v0, -ENOMEM jr rabad_address: li v0, -EFAULT jr rabad_alignment: li v0, -EINVAL jr raEND(mips_atomic_set)LEAF(sys_sysmips) beq a0, MIPS_ATOMIC_SET, mips_atomic_set j _sys_sysmipsEND(sys_sysmips)LEAF(sys_syscall) lw t0, PT_R29(sp) # user sp sltu v0, a0, __NR_Linux + __NR_Linux_syscalls + 1 beqz v0, enosys sll v0, a0, 2 la v1, sys_syscall lw t2, sys_call_table(v0) # function pointer lbu t4, sys_narg_table(a0) # number of arguments li v0, -EINVAL beq t2, v1, out # do not recurse beqz t2, enosys # null function pointer? andi v0, t0, 0x3 # unaligned stack pointer? bnez v0, sigsegv addu v0, t0, 16 # v0 = usp + 16 addu t1, v0, 12 # 3 32-bit arguments lw v1, THREAD_CURDS($28) or v0, v0, t1 and v1, v1, v0 bltz v1, efault move a0, a1 # shift argument registers move a1, a2 move a2, a31: lw a3, 16(t0)2: lw t3, 20(t0)3: lw t4, 24(t0) .section __ex_table, "a" .word 1b, efault .word 2b, efault .word 3b, efault .previous sw t3, 16(sp) # put into new stackframe sw t4, 20(sp) bnez t4, 1f # zero arguments? addu a0, sp, 32 # then pass sp in a01: sw t3, 16(sp) sw v1, 20(sp) jr t2 /* Unreached */enosys: li v0, -ENOSYS b outsigsegv: li a0, _SIGSEGV move a1, $28 jal force_sig /* Fall through */efault: li v0, -EFAULTout: jr raEND(sys_syscall)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -