linux-user/host/mips: Add safe-syscall.inc.S
Reviewed-by: Warner Losh <imp@bsdimp.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
a3310c0397
commit
4542adef5b
@ -12,4 +12,7 @@
|
||||
#ifndef MIPS_HOSTDEP_H
|
||||
#define MIPS_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#endif
|
||||
|
148
linux-user/host/mips/safe-syscall.inc.S
Normal file
148
linux-user/host/mips/safe-syscall.inc.S
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <richard.henderson@linaro.org>
|
||||
* Copyright (C) 2021 Linaro, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "sys/regdef.h"
|
||||
#include "sys/asm.h"
|
||||
|
||||
.text
|
||||
.set nomips16
|
||||
.set reorder
|
||||
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_start, @function
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
/* 8 * 4 = 32 for outgoing parameters; 1 * 4 for s0 save; 1 * 4 for align. */
|
||||
#define FRAME 40
|
||||
#define OFS_S0 32
|
||||
#else
|
||||
/* 1 * 8 for s0 save; 1 * 8 for align. */
|
||||
#define FRAME 16
|
||||
#define OFS_S0 0
|
||||
#endif
|
||||
|
||||
|
||||
NESTED(safe_syscall_base, FRAME, ra)
|
||||
.cfi_startproc
|
||||
PTR_ADDIU sp, sp, -FRAME
|
||||
.cfi_adjust_cfa_offset FRAME
|
||||
REG_S s0, OFS_S0(sp)
|
||||
.cfi_rel_offset s0, OFS_S0
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2, a3, stack == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* v0 == syscall number
|
||||
* a0 ... a3, stack == syscall arguments
|
||||
* and returns the result in v0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
move s0, a0 /* signal_pending pointer */
|
||||
move v0, a1 /* syscall number */
|
||||
move a0, a2 /* syscall arguments */
|
||||
move a1, a3
|
||||
lw a2, FRAME+16(sp)
|
||||
lw a3, FRAME+20(sp)
|
||||
lw t4, FRAME+24(sp)
|
||||
lw t5, FRAME+28(sp)
|
||||
lw t6, FRAME+32(sp)
|
||||
lw t7, FRAME+40(sp)
|
||||
sw t4, 16(sp)
|
||||
sw t5, 20(sp)
|
||||
sw t6, 24(sp)
|
||||
sw t7, 28(sp)
|
||||
#else
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2 ... a7 == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* v0 == syscall number
|
||||
* a0 ... a5 == syscall arguments
|
||||
* and returns the result in v0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
move s0, a0 /* signal_pending pointer */
|
||||
move v0, a1 /* syscall number */
|
||||
move a0, a2 /* syscall arguments */
|
||||
move a1, a3
|
||||
move a2, a4
|
||||
move a3, a5
|
||||
move a4, a6
|
||||
move a5, a7
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* If signal_pending is non-zero, don't do the call */
|
||||
lw t1, 0(s0)
|
||||
bnez t1, 2f
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
REG_L s0, OFS_S0(sp)
|
||||
PTR_ADDIU sp, sp, FRAME
|
||||
.cfi_remember_state
|
||||
.cfi_adjust_cfa_offset -FRAME
|
||||
.cfi_restore s0
|
||||
bnez a3, 1f
|
||||
jr ra
|
||||
.cfi_restore_state
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: REG_L s0, OFS_S0(sp)
|
||||
PTR_ADDIU sp, sp, FRAME
|
||||
.cfi_adjust_cfa_offset -FRAME
|
||||
.cfi_restore s0
|
||||
li v0, TARGET_ERESTARTSYS
|
||||
|
||||
/* code path setting errno */
|
||||
/*
|
||||
* We didn't setup GP on entry, optimistic of the syscall success.
|
||||
* We must do so now to load the address of the helper, as required
|
||||
* by the ABI, into t9.
|
||||
*
|
||||
* Note that SETUP_GPX and SETUP_GPX64 are themselves conditional,
|
||||
* so we can simply let the one that's not empty succeed.
|
||||
*/
|
||||
1: USE_ALT_CP(t0)
|
||||
SETUP_GPX(t1)
|
||||
SETUP_GPX64(t0, t1)
|
||||
PTR_LA t9, safe_syscall_set_errno_tail
|
||||
jr t9
|
||||
|
||||
.cfi_endproc
|
||||
END(safe_syscall_base)
|
Loading…
x
Reference in New Issue
Block a user