mips syscall返回值与errno设置

先直接上c库代码,见  ports/mips64/syscall.S

NESTED (syscall, SZREG, ra)
	.mask 0x00010000, -SZREG
	.fmask 0x00000000, 0
	PTR_ADDIU sp, -SZREG
	REG_S s0, (sp)

	move s0, a0
	move a0, a1		/* shift arg1 - arg7.  */ 
	move a1, a2
	move a2, a3
	move a3, a4
	move a4, a5
	move a5, a6
	move a6, a7

	move v0, s0		/* Syscall number -> v0 */
	syscall			/* Do the system call.  */

	REG_L s0, (sp)
	PTR_ADDIU sp, SZREG
	bne a3, zero, L(error)  

	ret

L(error):
	SETUP_GP64 (a0, syscall)
	PTR_LA t9, __syscall_error  
	RESTORE_GP64
	jr t9

END (syscall)
line7-line14 直接寄存器传参;
line21 系统调用结束后,a3存放本次syscall是否成功,0或者1;
如果为1代表系统调用失败,需要到__syscall_error去处理;
line 23函数正常返回,v0存放系统调用正常时的返回值。


__syscall_error函数在ports/sysdeps/unix/mips/sysdep.S:

ENTRY(__syscall_error)
	REG_S	v0, V0OFF(sp)
	jal	__errno_location
	
	/* Store the error value.  */
	REG_L	t0, V0OFF(sp)
	sw	t0, 0(v0)

	li	v0, -1
	j	ra
	END(__syscall_error)
line2先保存错误码v0;
line3找到errno的地址,存放在v0里;
line6-line7把错误码写到全局的errno里;
line9强制将syscall返回值改为-1。
这样,syscall要么返回正常值,要么就返回-1了,错误原因保存在errno里。


再来看内核部分,入口在arch/mips/kernel/scall64_o32.S
NESTED(handle_sys, PT_SIZE, sp)
beqz	t0, not_o32_scall 

1:	lw	a4, 16(t0)		# argument #5 from usp
2:	lw	a5, 20(t0)		# argument #6 from usp
3:	lw	a6, 24(t0)		# argument #7 from usp
4:	lw	a7, 28(t0)		# argument #8 from usp (for indirect syscalls)

	li	t0, -EMAXERRNO - 1	# error?
	sltu	t0, t0, v0
	sd	t0, PT_R7(sp)		# set error flag  
	beqz	t0, 1f

	dnegu	v0			# error  
	sd	v0, PT_R0(sp)		# flag for syscall restarting
1:	sd	v0, PT_R2(sp)		# result  
	END(handle_sys)
line2根据系统调用号判断是不是o32的调用,o32的范围(0-6000)
line4-line7如果上层是o32应用,第5个参数开始是放在用户栈里的,拷贝到内核态寄存器。


line9:t0 =(unsigned long)(-EMAXERRNO - 1), 另v0 = (unsigned long)(-errno)
line10:if(t0<v0) t0 = 1 else t0 =0 
由于负的越少,转换成unsigned long后就越大。 所以最大的是(unsigned long)(-1)
例如,如果errno返回-11,那么一定比(unsigned long)(-1134- 1)大,所以t0为1;
而返回值如果是正数,一般不会有(unsigned long)(-1134- 1)这么大的返回值,所以t0=0


line11将0或者1放到用户栈现场的a3位置
line14将负数转换成正数
line16把返回值放到用户栈现场的v0位置


你可能感兴趣的:(mips,syscall)