xref: /qemu/linux-user/alpha/signal.c (revision 654d6b04)
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  */
19 #include "qemu/osdep.h"
20 #include "qemu.h"
21 #include "user-internals.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
24 
25 struct target_sigcontext {
26     abi_long sc_onstack;
27     abi_long sc_mask;
28     abi_long sc_pc;
29     abi_long sc_ps;
30     abi_long sc_regs[32];
31     abi_long sc_ownedfp;
32     abi_long sc_fpregs[32];
33     abi_ulong sc_fpcr;
34     abi_ulong sc_fp_control;
35     abi_ulong sc_reserved1;
36     abi_ulong sc_reserved2;
37     abi_ulong sc_ssize;
38     abi_ulong sc_sbase;
39     abi_ulong sc_traparg_a0;
40     abi_ulong sc_traparg_a1;
41     abi_ulong sc_traparg_a2;
42     abi_ulong sc_fp_trap_pc;
43     abi_ulong sc_fp_trigger_sum;
44     abi_ulong sc_fp_trigger_inst;
45 };
46 
47 struct target_ucontext {
48     abi_ulong tuc_flags;
49     abi_ulong tuc_link;
50     abi_ulong tuc_osf_sigmask;
51     target_stack_t tuc_stack;
52     struct target_sigcontext tuc_mcontext;
53     target_sigset_t tuc_sigmask;
54 };
55 
56 struct target_sigframe {
57     struct target_sigcontext sc;
58 };
59 
60 struct target_rt_sigframe {
61     target_siginfo_t info;
62     struct target_ucontext uc;
63 };
64 
65 #define INSN_MOV_R30_R16        0x47fe0410
66 #define INSN_LDI_R0             0x201f0000
67 #define INSN_CALLSYS            0x00000083
68 
69 static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
70                              abi_ulong frame_addr, target_sigset_t *set)
71 {
72     int i;
73 
74     __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
75     __put_user(set->sig[0], &sc->sc_mask);
76     __put_user(env->pc, &sc->sc_pc);
77     __put_user(8, &sc->sc_ps);
78 
79     for (i = 0; i < 31; ++i) {
80         __put_user(env->ir[i], &sc->sc_regs[i]);
81     }
82     __put_user(0, &sc->sc_regs[31]);
83 
84     for (i = 0; i < 31; ++i) {
85         __put_user(env->fir[i], &sc->sc_fpregs[i]);
86     }
87     __put_user(0, &sc->sc_fpregs[31]);
88     __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
89 
90     __put_user(0, &sc->sc_traparg_a0); /* FIXME */
91     __put_user(0, &sc->sc_traparg_a1); /* FIXME */
92     __put_user(0, &sc->sc_traparg_a2); /* FIXME */
93 }
94 
95 static void restore_sigcontext(CPUAlphaState *env,
96                                struct target_sigcontext *sc)
97 {
98     uint64_t fpcr;
99     int i;
100 
101     __get_user(env->pc, &sc->sc_pc);
102 
103     for (i = 0; i < 31; ++i) {
104         __get_user(env->ir[i], &sc->sc_regs[i]);
105     }
106     for (i = 0; i < 31; ++i) {
107         __get_user(env->fir[i], &sc->sc_fpregs[i]);
108     }
109 
110     __get_user(fpcr, &sc->sc_fpcr);
111     cpu_alpha_store_fpcr(env, fpcr);
112 }
113 
114 static inline abi_ulong get_sigframe(struct target_sigaction *sa,
115                                      CPUAlphaState *env,
116                                      unsigned long framesize)
117 {
118     abi_ulong sp;
119 
120     sp = target_sigsp(get_sp_from_cpustate(env), sa);
121 
122     return (sp - framesize) & -32;
123 }
124 
125 void setup_frame(int sig, struct target_sigaction *ka,
126                  target_sigset_t *set, CPUAlphaState *env)
127 {
128     abi_ulong frame_addr, r26;
129     struct target_sigframe *frame;
130     int err = 0;
131 
132     frame_addr = get_sigframe(ka, env, sizeof(*frame));
133     trace_user_setup_frame(env, frame_addr);
134     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
135         goto give_sigsegv;
136     }
137 
138     setup_sigcontext(&frame->sc, env, frame_addr, set);
139 
140     if (ka->ka_restorer) {
141         r26 = ka->ka_restorer;
142     } else {
143         r26 = default_sigreturn;
144     }
145 
146     unlock_user_struct(frame, frame_addr, 1);
147 
148     if (err) {
149 give_sigsegv:
150         force_sigsegv(sig);
151         return;
152     }
153 
154     env->ir[IR_RA] = r26;
155     env->ir[IR_PV] = env->pc = ka->_sa_handler;
156     env->ir[IR_A0] = sig;
157     env->ir[IR_A1] = 0;
158     env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
159     env->ir[IR_SP] = frame_addr;
160 }
161 
162 void setup_rt_frame(int sig, struct target_sigaction *ka,
163                     target_siginfo_t *info,
164                     target_sigset_t *set, CPUAlphaState *env)
165 {
166     abi_ulong frame_addr, r26;
167     struct target_rt_sigframe *frame;
168     int i, err = 0;
169 
170     frame_addr = get_sigframe(ka, env, sizeof(*frame));
171     trace_user_setup_rt_frame(env, frame_addr);
172     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
173         goto give_sigsegv;
174     }
175 
176     tswap_siginfo(&frame->info, info);
177 
178     __put_user(0, &frame->uc.tuc_flags);
179     __put_user(0, &frame->uc.tuc_link);
180     __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
181 
182     target_save_altstack(&frame->uc.tuc_stack, env);
183 
184     setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
185     for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
186         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
187     }
188 
189     if (ka->ka_restorer) {
190         r26 = ka->ka_restorer;
191     } else {
192         r26 = default_rt_sigreturn;
193     }
194 
195     if (err) {
196 give_sigsegv:
197         force_sigsegv(sig);
198         return;
199     }
200 
201     env->ir[IR_RA] = r26;
202     env->ir[IR_PV] = env->pc = ka->_sa_handler;
203     env->ir[IR_A0] = sig;
204     env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
205     env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
206     env->ir[IR_SP] = frame_addr;
207 }
208 
209 long do_sigreturn(CPUAlphaState *env)
210 {
211     struct target_sigcontext *sc;
212     abi_ulong sc_addr = env->ir[IR_A0];
213     target_sigset_t target_set;
214     sigset_t set;
215 
216     if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
217         goto badframe;
218     }
219 
220     target_sigemptyset(&target_set);
221     __get_user(target_set.sig[0], &sc->sc_mask);
222 
223     target_to_host_sigset_internal(&set, &target_set);
224     set_sigmask(&set);
225 
226     restore_sigcontext(env, sc);
227     unlock_user_struct(sc, sc_addr, 0);
228     return -TARGET_QEMU_ESIGRETURN;
229 
230 badframe:
231     force_sig(TARGET_SIGSEGV);
232     return -TARGET_QEMU_ESIGRETURN;
233 }
234 
235 long do_rt_sigreturn(CPUAlphaState *env)
236 {
237     abi_ulong frame_addr = env->ir[IR_A0];
238     struct target_rt_sigframe *frame;
239     sigset_t set;
240 
241     trace_user_do_rt_sigreturn(env, frame_addr);
242     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
243         goto badframe;
244     }
245     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
246     set_sigmask(&set);
247 
248     restore_sigcontext(env, &frame->uc.tuc_mcontext);
249     target_restore_altstack(&frame->uc.tuc_stack, env);
250 
251     unlock_user_struct(frame, frame_addr, 0);
252     return -TARGET_QEMU_ESIGRETURN;
253 
254 
255 badframe:
256     unlock_user_struct(frame, frame_addr, 0);
257     force_sig(TARGET_SIGSEGV);
258     return -TARGET_QEMU_ESIGRETURN;
259 }
260 
261 void setup_sigtramp(abi_ulong sigtramp_page)
262 {
263     uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0);
264     assert(tramp != NULL);
265 
266     default_sigreturn = sigtramp_page;
267     __put_user(INSN_MOV_R30_R16, &tramp[0]);
268     __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]);
269     __put_user(INSN_CALLSYS, &tramp[2]);
270 
271     default_rt_sigreturn = sigtramp_page + 3 * 4;
272     __put_user(INSN_MOV_R30_R16, &tramp[3]);
273     __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]);
274     __put_user(INSN_CALLSYS, &tramp[5]);
275 
276     unlock_user(tramp, sigtramp_page, 6 * 4);
277 }
278