📄 scall32-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) 1995-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org> * Copyright (C) 2001 MIPS Technologies, Inc. * Copyright (C) 2004 Thiemo Seufer */#include <linux/errno.h>#include <asm/asm.h>#include <asm/asmmacro.h>#include <asm/irqflags.h>#include <asm/mipsregs.h>#include <asm/regdef.h>#include <asm/stackframe.h>#include <asm/isadep.h>#include <asm/sysmips.h>#include <asm/thread_info.h>#include <asm/unistd.h>#include <asm/war.h>#include <asm/asm-offsets.h>/* Highest syscall used of any syscall flavour */#define MAX_SYSCALL_NO __NR_O32_Linux + __NR_O32_Linux_syscalls .align 5NESTED(handle_sys, PT_SIZE, sp) .set noat SAVE_SOME TRACE_IRQS_ON_RELOAD STI .set at lw t1, PT_EPC(sp) # skip syscall on return#if defined(CONFIG_BINFMT_IRIX) sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number#else subu v0, v0, __NR_O32_Linux # check syscall number sltiu t0, v0, __NR_O32_Linux_syscalls + 1#endif addiu t1, 4 # skip to next instruction sw t1, PT_EPC(sp) beqz t0, illegal_syscall sll t0, v0, 3 la t1, sys_call_table addu t1, t0 lw t2, (t1) # syscall routine lw t3, 4(t1) # >= 0 if we need stack arguments beqz t2, illegal_syscall sw a3, PT_R26(sp) # save a3 for syscall restarting bgez t3, stackargsstack_done: lw t0, TI_FLAGS($28) # syscall tracing enabled? li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT and t0, t1 bnez t0, syscall_trace_entry # -> yes 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) # resulto32_syscall_exit: local_irq_disable # make sure need_resched and # signals dont change between # sampling and return lw a2, TI_FLAGS($28) # current->work li t0, _TIF_ALLWORK_MASK and t0, a2 bnez t0, o32_syscall_exit_work j restore_partialo32_syscall_exit_work: j syscall_exit_work_partial/* ------------------------------------------------------------------------ */syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp li a1, 0 jal do_syscall_trace move t0, s0 RESTORE_STATIC lw a0, PT_R4(sp) # Restore argument registers lw a1, PT_R5(sp) lw a2, PT_R6(sp) lw a3, PT_R7(sp) jalr t0 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) # result j syscall_exit/* ------------------------------------------------------------------------ */ /* * 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 /* * We intentionally keep the kernel stack a little below the top of * userspace so we don't have to do a slower byte accurate check here. */ lw t5, TI_ADDR_LIMIT($28) addu t4, t0, 32 and t5, t4 bltz t5, bad_stack # -> sp is bad /* Ok, copy the args from the luser stack to the kernel stack. * t3 is the precomputed number of instruction bytes needed to * load or store arguments 6-8. */ la t1, 5f # load up to 3 arguments subu t1, t31: lw t5, 16(t0) # argument #5 from usp .set push .set noreorder .set nomacro jr t1 addiu t1, 6f - 5f2: lw t8, 28(t0) # argument #8 from usp3: lw t7, 24(t0) # argument #7 from usp4: lw t6, 20(t0) # argument #6 from usp5: jr t1 sw t5, 16(sp) # argument #5 to ksp sw t8, 28(sp) # argument #8 to ksp sw t7, 24(sp) # argument #7 to ksp sw t6, 20(sp) # argument #6 to ksp6: j stack_done # go back nop .set pop .section __ex_table,"a" PTR 1b,bad_stack PTR 2b,bad_stack PTR 3b,bad_stack PTR 4b,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 o32_syscall_exit /* * The system call does not exist in this kernel */illegal_syscall: li v0, -ENOSYS # error sw v0, PT_R2(sp) li t0, 1 # set error flag sw t0, PT_R7(sp) j o32_syscall_exit END(handle_sys) LEAF(mips_atomic_set) andi v0, a1, 3 # must be word aligned bnez v0, bad_alignment lw v1, TI_ADDR_LIMIT($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)#if R10000_LLSC_WAR beqzl a0, 1b#else beqz a0, 1b#endif .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 j o32_syscall_exit # continue like a normal syscallno_mem: li v0, -ENOMEM jr rabad_address: li v0, -EFAULT jr rabad_alignment: li v0, -EINVAL jr ra END(mips_atomic_set) LEAF(sys_sysmips) beq a0, MIPS_ATOMIC_SET, mips_atomic_set j _sys_sysmips END(sys_sysmips) LEAF(sys_syscall)#if defined(CONFIG_BINFMT_IRIX) sltiu v0, a0, MAX_SYSCALL_NO + 1 # check syscall number#else subu t0, a0, __NR_O32_Linux # check syscall number sltiu v0, t0, __NR_O32_Linux_syscalls + 1#endif sll t1, t0, 3 beqz v0, einval lw t2, sys_call_table(t1) # syscall routine#if defined(CONFIG_BINFMT_IRIX) li v1, 4000 # nr of sys_syscall#else li v1, 4000 - __NR_O32_Linux # index of sys_syscall#endif beq t0, v1, einval # do not recurse /* Some syscalls like execve get their arguments from struct pt_regs and claim zero arguments in the syscall table. Thus we have to assume the worst case and shuffle around all potential arguments. If you want performance, don't use indirect syscalls. */ move a0, a1 # shift argument registers move a1, a2 move a2, a3 lw a3, 16(sp) lw t4, 20(sp) lw t5, 24(sp) lw t6, 28(sp) sw t4, 16(sp) sw t5, 20(sp) sw t6, 24(sp) sw a0, PT_R4(sp) # .. and push back a0 - a3, some sw a1, PT_R5(sp) # syscalls expect them there sw a2, PT_R6(sp) sw a3, PT_R7(sp) sw a3, PT_R26(sp) # update a3 for syscall restarting jr t2 /* Unreached */einval: li v0, -EINVAL jr ra END(sys_syscall) .macro fifty ptr, nargs, from=1, to=50 sys \ptr \nargs .if \to-\from fifty \ptr,\nargs,"(\from+1)",\to .endif .endm .macro mille ptr, nargs, from=1, to=20 fifty \ptr,\nargs .if \to-\from mille \ptr,\nargs,"(\from+1)",\to .endif .endm .macro syscalltable#if defined(CONFIG_BINFMT_IRIX) mille sys_ni_syscall 0 /* 0 - 999 SVR4 flavour */ mille sys_ni_syscall 0 /* 1000 - 1999 32-bit IRIX */ mille sys_ni_syscall 0 /* 2000 - 2999 BSD43 flavour */ mille sys_ni_syscall 0 /* 3000 - 3999 POSIX flavour */#endif sys sys_syscall 8 /* 4000 */ sys sys_exit 1 sys sys_fork 0 sys sys_read 3 sys sys_write 3 sys sys_open 3 /* 4005 */ sys sys_close 1 sys sys_waitpid 3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -