]>
Commit | Line | Data |
---|---|---|
befb7447 LV |
1 | /* |
2 | * Emulation of Linux signals | |
3 | * | |
4 | * Copyright (c) 2003 Fabrice Bellard | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
17853172 LV |
19 | #include "qemu/osdep.h" |
20 | #include "qemu.h" | |
17853172 LV |
21 | #include "signal-common.h" |
22 | #include "linux-user/trace.h" | |
23 | ||
e8f29049 | 24 | typedef struct target_sigcontext { |
17853172 LV |
25 | struct target_pt_regs regs; |
26 | abi_ulong oldmask; | |
e8f29049 | 27 | } target_sigcontext; |
17853172 | 28 | |
e8f29049 | 29 | typedef struct target_ucontext { |
17853172 LV |
30 | abi_ulong tuc_flags; |
31 | abi_ulong tuc_link; | |
32 | target_stack_t tuc_stack; | |
e8f29049 | 33 | target_sigcontext tuc_mcontext; |
17853172 | 34 | target_sigset_t tuc_sigmask; /* mask last for extensibility */ |
e8f29049 | 35 | } target_ucontext; |
17853172 | 36 | |
e8f29049 | 37 | typedef struct target_rt_sigframe { |
17853172 | 38 | struct target_siginfo info; |
e8f29049 RH |
39 | target_ucontext uc; |
40 | uint32_t retcode[4]; /* trampoline code */ | |
41 | } target_rt_sigframe; | |
17853172 | 42 | |
e8f29049 RH |
43 | static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc) |
44 | { | |
45 | int i; | |
46 | abi_ulong v; | |
17853172 | 47 | |
e8f29049 RH |
48 | for (i = 0; i < 32; ++i) { |
49 | __get_user(v, &sc->regs.gpr[i]); | |
50 | cpu_set_gpr(env, i, v); | |
17853172 | 51 | } |
e8f29049 | 52 | __get_user(env->pc, &sc->regs.pc); |
17853172 | 53 | |
e8f29049 RH |
54 | /* Make sure the supervisor flag is clear. */ |
55 | __get_user(v, &sc->regs.sr); | |
56 | cpu_set_sr(env, v & ~SR_SM); | |
17853172 | 57 | } |
17853172 LV |
58 | |
59 | /* Set up a signal frame. */ | |
60 | ||
e8f29049 | 61 | static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env) |
17853172 | 62 | { |
e8f29049 | 63 | int i; |
17853172 | 64 | |
e8f29049 RH |
65 | for (i = 0; i < 32; ++i) { |
66 | __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]); | |
67 | } | |
17853172 | 68 | |
e8f29049 RH |
69 | __put_user(env->pc, &sc->regs.pc); |
70 | __put_user(cpu_get_sr(env), &sc->regs.sr); | |
17853172 LV |
71 | } |
72 | ||
73 | static inline abi_ulong get_sigframe(struct target_sigaction *ka, | |
e8f29049 | 74 | CPUOpenRISCState *env, |
17853172 LV |
75 | size_t frame_size) |
76 | { | |
e8f29049 | 77 | target_ulong sp = get_sp_from_cpustate(env); |
17853172 | 78 | |
e8f29049 RH |
79 | /* Honor redzone now. If we swap to signal stack, no need to waste |
80 | * the 128 bytes by subtracting afterward. | |
17853172 | 81 | */ |
e8f29049 | 82 | sp -= 128; |
17853172 | 83 | |
e8f29049 RH |
84 | sp = target_sigsp(sp, ka); |
85 | sp -= frame_size; | |
86 | sp = QEMU_ALIGN_DOWN(sp, 4); | |
17853172 LV |
87 | |
88 | return sp; | |
89 | } | |
90 | ||
91 | void setup_rt_frame(int sig, struct target_sigaction *ka, | |
92 | target_siginfo_t *info, | |
93 | target_sigset_t *set, CPUOpenRISCState *env) | |
94 | { | |
17853172 | 95 | abi_ulong frame_addr; |
e8f29049 RH |
96 | target_rt_sigframe *frame; |
97 | int i; | |
17853172 LV |
98 | |
99 | frame_addr = get_sigframe(ka, env, sizeof(*frame)); | |
100 | trace_user_setup_rt_frame(env, frame_addr); | |
101 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { | |
102 | goto give_sigsegv; | |
103 | } | |
104 | ||
17853172 LV |
105 | if (ka->sa_flags & SA_SIGINFO) { |
106 | tswap_siginfo(&frame->info, info); | |
107 | } | |
108 | ||
17853172 LV |
109 | __put_user(0, &frame->uc.tuc_flags); |
110 | __put_user(0, &frame->uc.tuc_link); | |
17853172 | 111 | |
e8f29049 RH |
112 | target_save_altstack(&frame->uc.tuc_stack, env); |
113 | setup_sigcontext(&frame->uc.tuc_mcontext, env); | |
114 | for (i = 0; i < TARGET_NSIG_WORDS; ++i) { | |
115 | __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); | |
17853172 LV |
116 | } |
117 | ||
e8f29049 RH |
118 | /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */ |
119 | __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0); | |
120 | __put_user(0x20000001, frame->retcode + 1); | |
121 | __put_user(0x15000000, frame->retcode + 2); | |
122 | __put_user(0x15000000, frame->retcode + 3); | |
17853172 LV |
123 | |
124 | /* Set up registers for signal handler */ | |
e8f29049 RH |
125 | cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode)); |
126 | cpu_set_gpr(env, 3, sig); | |
127 | cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info)); | |
128 | cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc)); | |
129 | cpu_set_gpr(env, 1, frame_addr); | |
130 | ||
131 | /* For debugging convenience, set ppc to the insn that faulted. */ | |
132 | env->ppc = env->pc; | |
133 | /* When setting the PC for the signal handler, exit delay slot. */ | |
134 | env->pc = ka->_sa_handler; | |
135 | env->dflag = 0; | |
17853172 LV |
136 | return; |
137 | ||
138 | give_sigsegv: | |
139 | unlock_user_struct(frame, frame_addr, 1); | |
140 | force_sigsegv(sig); | |
141 | } | |
142 | ||
17853172 LV |
143 | long do_rt_sigreturn(CPUOpenRISCState *env) |
144 | { | |
e8f29049 RH |
145 | abi_ulong frame_addr = get_sp_from_cpustate(env); |
146 | target_rt_sigframe *frame; | |
147 | sigset_t set; | |
148 | ||
17853172 | 149 | trace_user_do_rt_sigreturn(env, 0); |
e8f29049 RH |
150 | if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { |
151 | goto badframe; | |
152 | } | |
153 | if (frame_addr & 3) { | |
154 | goto badframe; | |
155 | } | |
156 | ||
157 | target_to_host_sigset(&set, &frame->uc.tuc_sigmask); | |
158 | set_sigmask(&set); | |
159 | ||
160 | restore_sigcontext(env, &frame->uc.tuc_mcontext); | |
161 | if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack), | |
162 | 0, frame_addr) == -EFAULT) { | |
163 | goto badframe; | |
164 | } | |
165 | ||
166 | unlock_user_struct(frame, frame_addr, 0); | |
167 | return cpu_get_gpr(env, 11); | |
168 | ||
169 | badframe: | |
170 | unlock_user_struct(frame, frame_addr, 0); | |
171 | force_sig(TARGET_SIGSEGV); | |
172 | return 0; | |
17853172 | 173 | } |