diff mbox series

[v11,19/26] linux-user: Add LoongArch signal support

Message ID 1637302410-24632-20-git-send-email-gaosong@loongson.cn (mailing list archive)
State New, archived
Headers show
Series Add LoongArch linux-user emulation support | expand

Commit Message

gaosong Nov. 19, 2021, 6:13 a.m. UTC
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 linux-user/loongarch64/signal.c        | 162 +++++++++++++++++++++++++++++++++
 linux-user/loongarch64/target_signal.h |  29 ++++++
 2 files changed, 191 insertions(+)
 create mode 100644 linux-user/loongarch64/signal.c
 create mode 100644 linux-user/loongarch64/target_signal.h

Comments

Richard Henderson Nov. 20, 2021, 10:33 a.m. UTC | #1
On 11/19/21 7:13 AM, Song Gao wrote:
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> ---
>   linux-user/loongarch64/signal.c        | 162 +++++++++++++++++++++++++++++++++
>   linux-user/loongarch64/target_signal.h |  29 ++++++
>   2 files changed, 191 insertions(+)
>   create mode 100644 linux-user/loongarch64/signal.c
>   create mode 100644 linux-user/loongarch64/target_signal.h
> 
> diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c
> new file mode 100644
> index 0000000..8fbc827
> --- /dev/null
> +++ b/linux-user/loongarch64/signal.c
> @@ -0,0 +1,162 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch emulation of Linux signals
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu.h"
> +#include "signal-common.h"
> +#include "user-internals.h"
> +#include "linux-user/trace.h"
> +
> +struct target_sigcontext {
> +    uint64_t   sc_pc;
> +    uint64_t   sc_gpr[32];
> +    uint64_t   sc_fpr[32];
> +    uint64_t   sc_fcc;
> +    uint32_t   sc_fcsr;
> +    uint32_t   sc_flags;
> +};

Does not match
https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/sigcontext.h

> +
> +struct target_ucontext {
> +    target_ulong tuc_flags;
> +    target_ulong tuc_link;
> +    target_stack_t tuc_stack;
> +    target_ulong pad0;
> +    struct target_sigcontext tuc_mcontext;
> +    target_sigset_t tuc_sigmask;
> +};

Does not match
https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/ucontext.h

> +static inline void setup_sigcontext(CPULoongArchState *env,
> +                                    struct target_sigcontext *sc)

Drop all of the the inline markers.

> +{
> +    int i;
> +
> +    __put_user(env->pc, &sc->sc_pc);
> +
> +    __put_user(0, &sc->sc_gpr[0]);
> +    for (i = 1; i < 32; ++i) {
> +        __put_user(env->gpr[i], &sc->sc_gpr[i]);
> +    }
> +
> +    for (i = 0; i < 32; ++i) {
> +        __put_user(env->fpr[i], &sc->sc_fpr[i]);
> +    }
> +}

Missing fcsr and fcc.

I'll note that the kernel is missing sets of vscr and scr[0-3].  IMO they should at least 
be zeroed in advance of supporting the vector extension.

> +static inline void
> +restore_sigcontext(CPULoongArchState *env, struct target_sigcontext *sc)
> +{
> +    int i;
> +
> +    __get_user(env->pc, &sc->sc_pc);
> +
> +    for (i = 1; i < 32; ++i) {
> +        __get_user(env->gpr[i], &sc->sc_gpr[i]);
> +    }
> +
> +    for (i = 0; i < 32; ++i) {
> +        __get_user(env->fpr[i], &sc->sc_fpr[i]);
> +    }
> +}

Similarly.

> +    return (sp - frame_size) & ~7;

include/asm/asm.h:#define ALMASK        ~15
kernel/signal.c:        return (void __user *)((sp - frame_size) & ALMASK);

> +    env->pc = env->gpr[20] = ka->_sa_handler;

There is no set of gpr[20].

> +void setup_sigtramp(abi_ulong sigtramp_page)
> +{
> +    uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
> +    assert(tramp != NULL);
> +
> +    __put_user(0x03822c0b, tramp + 0);  /* ori     a7, a7, 0x8b */

The comment is incorrect: "ori a7, zero, 0x8b", but the hex is right.

> +/* this struct defines a stack used during syscall handling */
> +typedef struct target_sigaltstack {
> +        abi_long ss_sp;
> +        abi_int ss_flags;
> +        abi_ulong ss_size;
> +} target_stack_t;
> +
> +/*
> + * sigaltstack controls
> + */
> +#define TARGET_SS_ONSTACK     1
> +#define TARGET_SS_DISABLE     2
> +
> +#define TARGET_MINSIGSTKSZ    2048
> +#define TARGET_SIGSTKSZ       8192

We should move these to generic/signal.h.


r~
gaosong Nov. 22, 2021, 11:41 a.m. UTC | #2
Hi Richard,

On 2021/11/20 下午6:33, Richard Henderson wrote:
>
> Drop all of the the inline markers.
>
>> +{
>> +    int i;
>> +
>> +    __put_user(env->pc, &sc->sc_pc);
>> +
>> +    __put_user(0, &sc->sc_gpr[0]);
>> +    for (i = 1; i < 32; ++i) {
>> +        __put_user(env->gpr[i], &sc->sc_gpr[i]);
>> +    }
>> +
>> +    for (i = 0; i < 32; ++i) {
>> +        __put_user(env->fpr[i], &sc->sc_fpr[i]);
>> +    }
>> +}
>
> Missing fcsr and fcc.
>
> I'll note that the kernel is missing sets of vscr and scr[0-3]. IMO 
> they should at least be zeroed in advance of supporting the vector 
> extension.

I see that vcsr set at [1]:178.
[1]
https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/kernel/signal.c

and I also see that the kernel is missing sets of scr[0-3],  Huacai is that right?

Thanks
Song Gao
chen huacai Nov. 22, 2021, 11:44 a.m. UTC | #3
Hi, all,

On Mon, Nov 22, 2021 at 7:41 PM gaosong <gaosong@loongson.cn> wrote:
>
> Hi Richard,
>
> On 2021/11/20 下午6:33, Richard Henderson wrote:
>
>
> Drop all of the the inline markers.
>
> +{
> +    int i;
> +
> +    __put_user(env->pc, &sc->sc_pc);
> +
> +    __put_user(0, &sc->sc_gpr[0]);
> +    for (i = 1; i < 32; ++i) {
> +        __put_user(env->gpr[i], &sc->sc_gpr[i]);
> +    }
> +
> +    for (i = 0; i < 32; ++i) {
> +        __put_user(env->fpr[i], &sc->sc_fpr[i]);
> +    }
> +}
>
>
> Missing fcsr and fcc.
>
> I'll note that the kernel is missing sets of vscr and scr[0-3].  IMO they should at least be zeroed in advance of supporting the vector extension.
>
> I see that vcsr set at [1]:178.
> [1]
> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/kernel/signal.c
>
> and I also see that the kernel is missing sets of scr[0-3],  Huacai is that right?
scr[0-3] is reserved for binary translation, it doesn't need to be set now.

Huacai
>
> Thanks
> Song Gao
Richard Henderson Nov. 22, 2021, 12:31 p.m. UTC | #4
On 11/22/21 12:41 PM, gaosong wrote:
> Hi Richard,
> 
> On 2021/11/20 下午6:33, Richard Henderson wrote:
>>
>> Drop all of the the inline markers.
>>
>>> +{
>>> +    int i;
>>> +
>>> +    __put_user(env->pc, &sc->sc_pc);
>>> +
>>> +    __put_user(0, &sc->sc_gpr[0]);
>>> +    for (i = 1; i < 32; ++i) {
>>> +        __put_user(env->gpr[i], &sc->sc_gpr[i]);
>>> +    }
>>> +
>>> +    for (i = 0; i < 32; ++i) {
>>> +        __put_user(env->fpr[i], &sc->sc_fpr[i]);
>>> +    }
>>> +}
>>
>> Missing fcsr and fcc.
>>
>> I'll note that the kernel is missing sets of vscr and scr[0-3]. IMO they should at least 
>> be zeroed in advance of supporting the vector extension.
> 
> I see that vcsr set at [1]:178.
> [1]
> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/kernel/signal.c

That happens after line 171:

		if (likely(!err))
			break;

It seems most unlikely that there would be an error...

There is a macro for sc_save_vcsr in fpu.S, but it isn't used.


r~
gaosong Nov. 24, 2021, 2:46 a.m. UTC | #5
Hi Richard,

On 2021/11/20 下午6:33, Richard Henderson wrote:
> On 11/19/21 7:13 AM, Song Gao wrote:
>>
>> +
>> +struct target_sigcontext {
>> +    uint64_t   sc_pc;
>> +    uint64_t   sc_gpr[32];
>> +    uint64_t   sc_fpr[32];
>> +    uint64_t   sc_fcc;
>> +    uint32_t   sc_fcsr;
>> +    uint32_t   sc_flags;
>> +};
>
> Does not match
> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/sigcontext.h 
>
>
#define FPU_REG_WIDTH   256
union fpureg {
     uint32_t   val32[FPU_REG_WIDTH / 32];
     uint64_t   val64[FPU_REG_WIDTH / 64];
};

struct target_sigcontext {
     uint64_t   sc_pc;
     uint64_t   sc_regs[32];
     uint32_t   sc_flags;

     uint32_t   sc_fcsr;
     uint32_t   sc_vcsr;
     uint64_t   sc_fcc;
     uint64_t   scr[4];
     union fpureg    sc_fpregs[32] __attribute__((aligned(32)));

     uint32_t   sc_reserved;
};

Is this OK?

>> +
>> +struct target_ucontext {
>> +    target_ulong tuc_flags;
>> +    target_ulong tuc_link;
>> +    target_stack_t tuc_stack;
>> +    target_ulong pad0;
>> +    struct target_sigcontext tuc_mcontext;
>> +    target_sigset_t tuc_sigmask;
>> +};
>
> Does not match
> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/ucontext.h 
>
>
struct target_ucontext {
     target_ulong tuc_flags;
     target_ulong tuc_link;
     target_stack_t tuc_stack;
     target_sigset_t tuc_sigmask;
     target_ulong pad0;
     struct target_sigcontext tuc_mcontext;
};

Is this OK?

Thanks
Song Gao
Richard Henderson Nov. 24, 2021, 7:27 a.m. UTC | #6
On 11/24/21 3:46 AM, gaosong wrote:
> Hi Richard,
> 
> On 2021/11/20 下午6:33, Richard Henderson wrote:
>> On 11/19/21 7:13 AM, Song Gao wrote:
>>>
>>> +
>>> +struct target_sigcontext {
>>> +    uint64_t   sc_pc;
>>> +    uint64_t   sc_gpr[32];
>>> +    uint64_t   sc_fpr[32];
>>> +    uint64_t   sc_fcc;
>>> +    uint32_t   sc_fcsr;
>>> +    uint32_t   sc_flags;
>>> +};
>>
>> Does not match
>> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/sigcontext.h 
>>
>>
> #define FPU_REG_WIDTH   256
> union fpureg {
>      uint32_t   val32[FPU_REG_WIDTH / 32];
>      uint64_t   val64[FPU_REG_WIDTH / 64];
> };
> 
> struct target_sigcontext {
>      uint64_t   sc_pc;
>      uint64_t   sc_regs[32];
>      uint32_t   sc_flags;
> 
>      uint32_t   sc_fcsr;
>      uint32_t   sc_vcsr;
>      uint64_t   sc_fcc;
>      uint64_t   scr[4];
>      union fpureg    sc_fpregs[32] __attribute__((aligned(32)));
> 
>      uint32_t   sc_reserved;
> };
> 
> Is this OK?

No, sc_reserved does not match.

> 
>>> +
>>> +struct target_ucontext {
>>> +    target_ulong tuc_flags;
>>> +    target_ulong tuc_link;
>>> +    target_stack_t tuc_stack;
>>> +    target_ulong pad0;
>>> +    struct target_sigcontext tuc_mcontext;
>>> +    target_sigset_t tuc_sigmask;
>>> +};
>>
>> Does not match
>> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/ucontext.h 
>>
>>
> struct target_ucontext {
>      target_ulong tuc_flags;
>      target_ulong tuc_link;
>      target_stack_t tuc_stack;
>      target_sigset_t tuc_sigmask;
>      target_ulong pad0;
>      struct target_sigcontext tuc_mcontext;
> };
> 
> Is this OK?

No, pad0 does not match __unused.


r~
gaosong Nov. 24, 2021, 7:50 a.m. UTC | #7
Hi Richard,

On 2021/11/24 下午3:27, Richard Henderson wrote:
> On 11/24/21 3:46 AM, gaosong wrote:
>> Hi Richard,
>>
>> On 2021/11/20 下午6:33, Richard Henderson wrote:
>>> On 11/19/21 7:13 AM, Song Gao wrote:
>>>>
>>>> +
>>>> +struct target_sigcontext {
>>>> +    uint64_t   sc_pc;
>>>> +    uint64_t   sc_gpr[32];
>>>> +    uint64_t   sc_fpr[32];
>>>> +    uint64_t   sc_fcc;
>>>> +    uint32_t   sc_fcsr;
>>>> +    uint32_t   sc_flags;
>>>> +};
>>>
>>> Does not match
>>> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/sigcontext.h 
>>>
>>>
>> #define FPU_REG_WIDTH   256
>> union fpureg {
>>      uint32_t   val32[FPU_REG_WIDTH / 32];
>>      uint64_t   val64[FPU_REG_WIDTH / 64];
>> };
>>
>> struct target_sigcontext {
>>      uint64_t   sc_pc;
>>      uint64_t   sc_regs[32];
>>      uint32_t   sc_flags;
>>
>>      uint32_t   sc_fcsr;
>>      uint32_t   sc_vcsr;
>>      uint64_t   sc_fcc;
>>      uint64_t   scr[4];
>>      union fpureg    sc_fpregs[32] __attribute__((aligned(32)));
>>
>>      uint32_t   sc_reserved;
>> };
>>
>> Is this OK?
>
> No, sc_reserved does not match.
>
uint8   sc_reserved[4096] __attribute__((aligned(16)));

BTW,  should we set scr[0-3] as 0 ?

>>
>>>> +
>>>> +struct target_ucontext {
>>>> +    target_ulong tuc_flags;
>>>> +    target_ulong tuc_link;
>>>> +    target_stack_t tuc_stack;
>>>> +    target_ulong pad0;
>>>> +    struct target_sigcontext tuc_mcontext;
>>>> +    target_sigset_t tuc_sigmask;
>>>> +};
>>>
>>> Does not match
>>> https://github.com/loongson/linux/blob/loongarch-next/arch/loongarch/include/uapi/asm/ucontext.h 
>>>
>>>
>> struct target_ucontext {
>>      target_ulong tuc_flags;
>>      target_ulong tuc_link;
>>      target_stack_t tuc_stack;
>>      target_sigset_t tuc_sigmask;
>>      target_ulong pad0;
>>      struct target_sigcontext tuc_mcontext;
>> };
>>
>> Is this OK?
>
> No, pad0 does not match __unused.
>
uint8  unused[1024 / 8 - sizeof(target_sigset_t)];
Is this right?

Thanks
Song Gao

>
> r~
Richard Henderson Nov. 24, 2021, 9:40 a.m. UTC | #8
On 11/24/21 8:50 AM, gaosong wrote:
>> No, sc_reserved does not match.
>>
> uint8   sc_reserved[4096] __attribute__((aligned(16)));

Yes.

> BTW,  should we set scr[0-3] as 0 ?

I think so.  The LoongArch Reference Manual, Volume 3: Virtualization and Binary 
Translation Extensions, v1.00, is empty.  But I do not imagine a world in which 0 is not a 
safe indication of "this field is empty/unused".

>> No, pad0 does not match __unused.
>>
> uint8  unused[1024 / 8 - sizeof(target_sigset_t)];
> Is this right?

Yes.


r~
gaosong Nov. 24, 2021, 10:22 a.m. UTC | #9
Hi Richard,
On 2021/11/20 下午6:33, Richard Henderson wrote:
>> +{
>> +    int i;
>> +
>> +    __put_user(env->pc, &sc->sc_pc);
>> +
>> +    __put_user(0, &sc->sc_gpr[0]);
>> +    for (i = 1; i < 32; ++i) {
>> +        __put_user(env->gpr[i], &sc->sc_gpr[i]);
>> +    }
>> +
>> +    for (i = 0; i < 32; ++i) {
>> +        __put_user(env->fpr[i], &sc->sc_fpr[i]);
>> +    }
>> +}
>
> Missing fcsr and fcc. 
I see that  kernel  define  the fcc used type uint64_t,   and  used 
movgr2cf/movcf2gr  save and restore the fcc0-fcc7.
but  qemu define  fcc0-fcc7 as  bool cf[8] at target/loongarch/cpu.h,   
how qemu can  save/restore fcc,  Do you have any idea?
Does we can define the fcc   as   bool cf[8]  at  struct target_sigcontext?

Thanks
Song Gao
Richard Henderson Nov. 24, 2021, 10:44 a.m. UTC | #10
On 11/24/21 11:22 AM, gaosong wrote:
> I see that  kernel  define  the fcc used type uint64_t,   and  used movgr2cf/movcf2gr  
> save and restore the fcc0-fcc7.
> but  qemu define  fcc0-fcc7 as  bool cf[8] at target/loongarch/cpu.h,   how qemu can  
> save/restore fcc,  Do you have any idea?
> Does we can define the fcc   as   bool cf[8]  at  struct target_sigcontext?

No, you need to leave the declaration the same.

To create the uint64_t, you do what the kernel does in sc_save_fcc: insert each bit into 
the first bit of each byte.

static uint64_t read_all_fcc(CPULoongArchState *env)
{
     uint64_t ret = 0;

     for (int i = 0; i < 8; ++i) {
         ret |= (uint64_t)env->cf[i] << (i * 8);
     }
     return ret;
}

And similarly from sc_restore_fcc:

static void write_all_fcc(CPULoongArchState *env, uint64_t val)
{
     for (int i = 0; i < 8; ++i) {
         env->cf[i] = (val >> (i * 8)) & 1;
     }
}

Remembering that movcf2gr copies the least significant bit.


r~
gaosong Nov. 25, 2021, 3:03 a.m. UTC | #11
Hi  Richard,
On 2021/11/20 下午6:33, Richard Henderson wrote:
>> +/* this struct defines a stack used during syscall handling */
>> +typedef struct target_sigaltstack {
>> +        abi_long ss_sp;
>> +        abi_int ss_flags;
>> +        abi_ulong ss_size;
>> +} target_stack_t;
>> +
>> +/*
>> + * sigaltstack controls
>> + */
>> +#define TARGET_SS_ONSTACK     1
>> +#define TARGET_SS_DISABLE     2
>> +
>> +#define TARGET_MINSIGSTKSZ    2048
>> +#define TARGET_SIGSTKSZ       8192
>
> We should move these to generic/signal.h. 
Yes.
I also see that TARGET_SIGSTKSZ is not used.  I think  we should delete it.

Thanks
Song Gao
Richard Henderson Nov. 25, 2021, 10:11 a.m. UTC | #12
On 11/25/21 4:03 AM, gaosong wrote:
> I also see that TARGET_SIGSTKSZ is not used.  I think  we should delete it.

Agreed.  This constant will have been baked into the guest executable.


r~
diff mbox series

Patch

diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c
new file mode 100644
index 0000000..8fbc827
--- /dev/null
+++ b/linux-user/loongarch64/signal.c
@@ -0,0 +1,162 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch emulation of Linux signals
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "signal-common.h"
+#include "user-internals.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+    uint64_t   sc_pc;
+    uint64_t   sc_gpr[32];
+    uint64_t   sc_fpr[32];
+    uint64_t   sc_fcc;
+    uint32_t   sc_fcsr;
+    uint32_t   sc_flags;
+};
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    target_ulong tuc_link;
+    target_stack_t tuc_stack;
+    target_ulong pad0;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+    struct target_siginfo rs_info;
+    struct target_ucontext rs_uc;
+};
+
+static inline void setup_sigcontext(CPULoongArchState *env,
+                                    struct target_sigcontext *sc)
+{
+    int i;
+
+    __put_user(env->pc, &sc->sc_pc);
+
+    __put_user(0, &sc->sc_gpr[0]);
+    for (i = 1; i < 32; ++i) {
+        __put_user(env->gpr[i], &sc->sc_gpr[i]);
+    }
+
+    for (i = 0; i < 32; ++i) {
+        __put_user(env->fpr[i], &sc->sc_fpr[i]);
+    }
+}
+
+static inline void
+restore_sigcontext(CPULoongArchState *env, struct target_sigcontext *sc)
+{
+    int i;
+
+    __get_user(env->pc, &sc->sc_pc);
+
+    for (i = 1; i < 32; ++i) {
+        __get_user(env->gpr[i], &sc->sc_gpr[i]);
+    }
+
+    for (i = 0; i < 32; ++i) {
+        __get_user(env->fpr[i], &sc->sc_fpr[i]);
+    }
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPULoongArchState *env,
+             size_t frame_size)
+{
+    unsigned long sp;
+
+    sp = target_sigsp(get_sp_from_cpustate(env) - 32, ka);
+
+    return (sp - frame_size) & ~7;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+                    target_siginfo_t *info,
+                    target_sigset_t *set, CPULoongArchState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    trace_user_setup_rt_frame(env, frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    tswap_siginfo(&frame->rs_info, info);
+
+    __put_user(0, &frame->rs_uc.tuc_flags);
+    __put_user(0, &frame->rs_uc.tuc_link);
+    target_save_altstack(&frame->rs_uc.tuc_stack, env);
+
+    setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
+    }
+
+    env->gpr[4] = sig;
+    env->gpr[5] = frame_addr + offsetof(struct target_rt_sigframe, rs_info);
+    env->gpr[6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc);
+    env->gpr[3] = frame_addr;
+    env->gpr[1] = default_rt_sigreturn;
+
+    env->pc = env->gpr[20] = ka->_sa_handler;
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPULoongArchState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+
+    frame_addr = env->gpr[3];
+    trace_user_do_rt_sigreturn(env, frame_addr);
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+
+    target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+    set_sigmask(&blocked);
+
+    restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+    target_restore_altstack(&frame->rs_uc.tuc_stack, env);
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_QEMU_ESIGRETURN;
+}
+
+void setup_sigtramp(abi_ulong sigtramp_page)
+{
+    uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
+    assert(tramp != NULL);
+
+    __put_user(0x03822c0b, tramp + 0);  /* ori     a7, a7, 0x8b */
+    __put_user(0x002b0000, tramp + 1);  /* syscall 0 */
+
+    default_rt_sigreturn = sigtramp_page;
+    unlock_user(tramp, sigtramp_page, 8);
+}
diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h
new file mode 100644
index 0000000..c5f467b
--- /dev/null
+++ b/linux-user/loongarch64/target_signal.h
@@ -0,0 +1,29 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef LOONGARCH_TARGET_SIGNAL_H
+#define LOONGARCH_TARGET_SIGNAL_H
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+        abi_long ss_sp;
+        abi_int ss_flags;
+        abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+#include "../generic/signal.h"
+
+#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
+
+#endif /* LOONGARCH_TARGET_SIGNAL_H */