xref: /qemu/common-user/host/loongarch64/safe-syscall.inc.S (revision 8c5f94cd4182753959c8be8de415120dc879d8f0)
1*6016b7b4SWANG Xuerui/*
2*6016b7b4SWANG Xuerui * safe-syscall.inc.S : host-specific assembly fragment
3*6016b7b4SWANG Xuerui * to handle signals occurring at the same time as system calls.
4*6016b7b4SWANG Xuerui * This is intended to be included by common-user/safe-syscall.S
5*6016b7b4SWANG Xuerui *
6*6016b7b4SWANG Xuerui * Ported to LoongArch by WANG Xuerui <git@xen0n.name>
7*6016b7b4SWANG Xuerui *
8*6016b7b4SWANG Xuerui * Based on safe-syscall.inc.S code for RISC-V,
9*6016b7b4SWANG Xuerui * originally written by Richard Henderson <rth@twiddle.net>
10*6016b7b4SWANG Xuerui * Copyright (C) 2018 Linaro, Inc.
11*6016b7b4SWANG Xuerui *
12*6016b7b4SWANG Xuerui * This work is licensed under the terms of the GNU GPL, version 2 or later.
13*6016b7b4SWANG Xuerui * See the COPYING file in the top-level directory.
14*6016b7b4SWANG Xuerui */
15*6016b7b4SWANG Xuerui
16*6016b7b4SWANG Xuerui        .global safe_syscall_base
17*6016b7b4SWANG Xuerui        .global safe_syscall_start
18*6016b7b4SWANG Xuerui        .global safe_syscall_end
19*6016b7b4SWANG Xuerui        .type   safe_syscall_base, @function
20*6016b7b4SWANG Xuerui        .type   safe_syscall_start, @function
21*6016b7b4SWANG Xuerui        .type   safe_syscall_end, @function
22*6016b7b4SWANG Xuerui
23*6016b7b4SWANG Xuerui        /*
24*6016b7b4SWANG Xuerui         * This is the entry point for making a system call. The calling
25*6016b7b4SWANG Xuerui         * convention here is that of a C varargs function with the
26*6016b7b4SWANG Xuerui         * first argument an 'int *' to the signal_pending flag, the
27*6016b7b4SWANG Xuerui         * second one the system call number (as a 'long'), and all further
28*6016b7b4SWANG Xuerui         * arguments being syscall arguments (also 'long').
29*6016b7b4SWANG Xuerui         */
30*6016b7b4SWANG Xueruisafe_syscall_base:
31*6016b7b4SWANG Xuerui        .cfi_startproc
32*6016b7b4SWANG Xuerui        /*
33*6016b7b4SWANG Xuerui         * The syscall calling convention is nearly the same as C:
34*6016b7b4SWANG Xuerui         * we enter with a0 == &signal_pending
35*6016b7b4SWANG Xuerui         *               a1 == syscall number
36*6016b7b4SWANG Xuerui         *               a2 ... a7 == syscall arguments
37*6016b7b4SWANG Xuerui         *               and return the result in a0
38*6016b7b4SWANG Xuerui         * and the syscall instruction needs
39*6016b7b4SWANG Xuerui         *               a7 == syscall number
40*6016b7b4SWANG Xuerui         *               a0 ... a5 == syscall arguments
41*6016b7b4SWANG Xuerui         *               and returns the result in a0
42*6016b7b4SWANG Xuerui         * Shuffle everything around appropriately.
43*6016b7b4SWANG Xuerui         */
44*6016b7b4SWANG Xuerui        move    $t0, $a0        /* signal_pending pointer */
45*6016b7b4SWANG Xuerui        move    $t1, $a1        /* syscall number */
46*6016b7b4SWANG Xuerui        move    $a0, $a2        /* syscall arguments */
47*6016b7b4SWANG Xuerui        move    $a1, $a3
48*6016b7b4SWANG Xuerui        move    $a2, $a4
49*6016b7b4SWANG Xuerui        move    $a3, $a5
50*6016b7b4SWANG Xuerui        move    $a4, $a6
51*6016b7b4SWANG Xuerui        move    $a5, $a7
52*6016b7b4SWANG Xuerui        move    $a7, $t1
53*6016b7b4SWANG Xuerui
54*6016b7b4SWANG Xuerui        /*
55*6016b7b4SWANG Xuerui         * We need to preserve the signal_pending pointer but t0 is
56*6016b7b4SWANG Xuerui         * clobbered by syscalls on LoongArch, so we need to move it
57*6016b7b4SWANG Xuerui         * somewhere else, ideally both preserved across syscalls and
58*6016b7b4SWANG Xuerui         * clobbered by procedure calls so we don't have to allocate a
59*6016b7b4SWANG Xuerui         * stack frame; a6 is just the register we want here.
60*6016b7b4SWANG Xuerui         */
61*6016b7b4SWANG Xuerui        move    $a6, $t0
62*6016b7b4SWANG Xuerui
63*6016b7b4SWANG Xuerui        /*
64*6016b7b4SWANG Xuerui         * This next sequence of code works in conjunction with the
65*6016b7b4SWANG Xuerui         * rewind_if_safe_syscall_function(). If a signal is taken
66*6016b7b4SWANG Xuerui         * and the interrupted PC is anywhere between 'safe_syscall_start'
67*6016b7b4SWANG Xuerui         * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
68*6016b7b4SWANG Xuerui         * The code sequence must therefore be able to cope with this, and
69*6016b7b4SWANG Xuerui         * the syscall instruction must be the final one in the sequence.
70*6016b7b4SWANG Xuerui         */
71*6016b7b4SWANG Xueruisafe_syscall_start:
72*6016b7b4SWANG Xuerui        /* If signal_pending is non-zero, don't do the call */
73*6016b7b4SWANG Xuerui        ld.w    $t1, $a6, 0
74*6016b7b4SWANG Xuerui        bnez    $t1, 2f
75*6016b7b4SWANG Xuerui        syscall 0
76*6016b7b4SWANG Xueruisafe_syscall_end:
77*6016b7b4SWANG Xuerui        /* code path for having successfully executed the syscall */
78*6016b7b4SWANG Xuerui        li.w    $t2, -4096
79*6016b7b4SWANG Xuerui        bgtu    $a0, $t2, 0f
80*6016b7b4SWANG Xuerui        jr      $ra
81*6016b7b4SWANG Xuerui
82*6016b7b4SWANG Xuerui        /* code path setting errno */
83*6016b7b4SWANG Xuerui0:      sub.d   $a0, $zero, $a0
84*6016b7b4SWANG Xuerui        b       safe_syscall_set_errno_tail
85*6016b7b4SWANG Xuerui
86*6016b7b4SWANG Xuerui        /* code path when we didn't execute the syscall */
87*6016b7b4SWANG Xuerui2:      li.w    $a0, QEMU_ERESTARTSYS
88*6016b7b4SWANG Xuerui        b       safe_syscall_set_errno_tail
89*6016b7b4SWANG Xuerui        .cfi_endproc
90*6016b7b4SWANG Xuerui        .size   safe_syscall_base, .-safe_syscall_base
91