1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "qemu.h"
21#include "signal-common.h"
22#include "linux-user/trace.h"
23
24
25
26
27
28
29
30struct target_sigcontext {
31 target_ulong oldmask;
32
33
34 target_ulong sc_gregs[16];
35 target_ulong sc_pc;
36 target_ulong sc_pr;
37 target_ulong sc_sr;
38 target_ulong sc_gbr;
39 target_ulong sc_mach;
40 target_ulong sc_macl;
41
42
43 target_ulong sc_fpregs[16];
44 target_ulong sc_xfpregs[16];
45 unsigned int sc_fpscr;
46 unsigned int sc_fpul;
47 unsigned int sc_ownedfp;
48};
49
50struct target_sigframe
51{
52 struct target_sigcontext sc;
53 target_ulong extramask[TARGET_NSIG_WORDS-1];
54 uint16_t retcode[3];
55};
56
57
58struct target_ucontext {
59 target_ulong tuc_flags;
60 struct target_ucontext *tuc_link;
61 target_stack_t tuc_stack;
62 struct target_sigcontext tuc_mcontext;
63 target_sigset_t tuc_sigmask;
64};
65
66struct target_rt_sigframe
67{
68 struct target_siginfo info;
69 struct target_ucontext uc;
70 uint16_t retcode[3];
71};
72
73
74#define MOVW(n) (0x9300|((n)-2))
75#define TRAP_NOARG 0xc310
76
77static abi_ulong get_sigframe(struct target_sigaction *ka,
78 unsigned long sp, size_t frame_size)
79{
80 sp = target_sigsp(sp, ka);
81
82 return (sp - frame_size) & -8ul;
83}
84
85
86
87
88static void unwind_gusa(CPUSH4State *regs)
89{
90
91
92
93
94
95
96
97
98 if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
99
100
101
102 regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
103
104
105 regs->gregs[15] = regs->gregs[1];
106 }
107}
108
109static void setup_sigcontext(struct target_sigcontext *sc,
110 CPUSH4State *regs, unsigned long mask)
111{
112 int i;
113
114#define COPY(x) __put_user(regs->x, &sc->sc_##x)
115 COPY(gregs[0]); COPY(gregs[1]);
116 COPY(gregs[2]); COPY(gregs[3]);
117 COPY(gregs[4]); COPY(gregs[5]);
118 COPY(gregs[6]); COPY(gregs[7]);
119 COPY(gregs[8]); COPY(gregs[9]);
120 COPY(gregs[10]); COPY(gregs[11]);
121 COPY(gregs[12]); COPY(gregs[13]);
122 COPY(gregs[14]); COPY(gregs[15]);
123 COPY(gbr); COPY(mach);
124 COPY(macl); COPY(pr);
125 COPY(sr); COPY(pc);
126#undef COPY
127
128 for (i=0; i<16; i++) {
129 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
130 }
131 __put_user(regs->fpscr, &sc->sc_fpscr);
132 __put_user(regs->fpul, &sc->sc_fpul);
133
134
135 __put_user(mask, &sc->oldmask);
136}
137
138static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
139{
140 int i;
141
142#define COPY(x) __get_user(regs->x, &sc->sc_##x)
143 COPY(gregs[0]); COPY(gregs[1]);
144 COPY(gregs[2]); COPY(gregs[3]);
145 COPY(gregs[4]); COPY(gregs[5]);
146 COPY(gregs[6]); COPY(gregs[7]);
147 COPY(gregs[8]); COPY(gregs[9]);
148 COPY(gregs[10]); COPY(gregs[11]);
149 COPY(gregs[12]); COPY(gregs[13]);
150 COPY(gregs[14]); COPY(gregs[15]);
151 COPY(gbr); COPY(mach);
152 COPY(macl); COPY(pr);
153 COPY(sr); COPY(pc);
154#undef COPY
155
156 for (i=0; i<16; i++) {
157 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
158 }
159 __get_user(regs->fpscr, &sc->sc_fpscr);
160 __get_user(regs->fpul, &sc->sc_fpul);
161
162 regs->tra = -1;
163 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
164}
165
166void setup_frame(int sig, struct target_sigaction *ka,
167 target_sigset_t *set, CPUSH4State *regs)
168{
169 struct target_sigframe *frame;
170 abi_ulong frame_addr;
171 int i;
172
173 unwind_gusa(regs);
174
175 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
176 trace_user_setup_frame(regs, frame_addr);
177 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
178 goto give_sigsegv;
179 }
180
181 setup_sigcontext(&frame->sc, regs, set->sig[0]);
182
183 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
184 __put_user(set->sig[i + 1], &frame->extramask[i]);
185 }
186
187
188
189 if (ka->sa_flags & TARGET_SA_RESTORER) {
190 regs->pr = (unsigned long) ka->sa_restorer;
191 } else {
192
193 abi_ulong retcode_addr = frame_addr +
194 offsetof(struct target_sigframe, retcode);
195 __put_user(MOVW(2), &frame->retcode[0]);
196 __put_user(TRAP_NOARG, &frame->retcode[1]);
197 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
198 regs->pr = (unsigned long) retcode_addr;
199 }
200
201
202 regs->gregs[15] = frame_addr;
203 regs->gregs[4] = sig;
204 regs->gregs[5] = 0;
205 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
206 regs->pc = (unsigned long) ka->_sa_handler;
207 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
208
209 unlock_user_struct(frame, frame_addr, 1);
210 return;
211
212give_sigsegv:
213 unlock_user_struct(frame, frame_addr, 1);
214 force_sigsegv(sig);
215}
216
217void setup_rt_frame(int sig, struct target_sigaction *ka,
218 target_siginfo_t *info,
219 target_sigset_t *set, CPUSH4State *regs)
220{
221 struct target_rt_sigframe *frame;
222 abi_ulong frame_addr;
223 int i;
224
225 unwind_gusa(regs);
226
227 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
228 trace_user_setup_rt_frame(regs, frame_addr);
229 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
230 goto give_sigsegv;
231 }
232
233 tswap_siginfo(&frame->info, info);
234
235
236 __put_user(0, &frame->uc.tuc_flags);
237 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
238 target_save_altstack(&frame->uc.tuc_stack, regs);
239 setup_sigcontext(&frame->uc.tuc_mcontext,
240 regs, set->sig[0]);
241 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
242 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
243 }
244
245
246
247 if (ka->sa_flags & TARGET_SA_RESTORER) {
248 regs->pr = (unsigned long) ka->sa_restorer;
249 } else {
250
251 abi_ulong retcode_addr = frame_addr +
252 offsetof(struct target_rt_sigframe, retcode);
253 __put_user(MOVW(2), &frame->retcode[0]);
254 __put_user(TRAP_NOARG, &frame->retcode[1]);
255 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
256 regs->pr = (unsigned long) retcode_addr;
257 }
258
259
260 regs->gregs[15] = frame_addr;
261 regs->gregs[4] = sig;
262 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
263 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
264 regs->pc = (unsigned long) ka->_sa_handler;
265 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
266
267 unlock_user_struct(frame, frame_addr, 1);
268 return;
269
270give_sigsegv:
271 unlock_user_struct(frame, frame_addr, 1);
272 force_sigsegv(sig);
273}
274
275long do_sigreturn(CPUSH4State *regs)
276{
277 struct target_sigframe *frame;
278 abi_ulong frame_addr;
279 sigset_t blocked;
280 target_sigset_t target_set;
281 int i;
282
283 frame_addr = regs->gregs[15];
284 trace_user_do_sigreturn(regs, frame_addr);
285 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
286 goto badframe;
287 }
288
289 __get_user(target_set.sig[0], &frame->sc.oldmask);
290 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
291 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
292 }
293
294 target_to_host_sigset_internal(&blocked, &target_set);
295 set_sigmask(&blocked);
296
297 restore_sigcontext(regs, &frame->sc);
298
299 unlock_user_struct(frame, frame_addr, 0);
300 return -TARGET_QEMU_ESIGRETURN;
301
302badframe:
303 unlock_user_struct(frame, frame_addr, 0);
304 force_sig(TARGET_SIGSEGV);
305 return -TARGET_QEMU_ESIGRETURN;
306}
307
308long do_rt_sigreturn(CPUSH4State *regs)
309{
310 struct target_rt_sigframe *frame;
311 abi_ulong frame_addr;
312 sigset_t blocked;
313
314 frame_addr = regs->gregs[15];
315 trace_user_do_rt_sigreturn(regs, frame_addr);
316 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
317 goto badframe;
318 }
319
320 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
321 set_sigmask(&blocked);
322
323 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
324
325 if (do_sigaltstack(frame_addr +
326 offsetof(struct target_rt_sigframe, uc.tuc_stack),
327 0, get_sp_from_cpustate(regs)) == -EFAULT) {
328 goto badframe;
329 }
330
331 unlock_user_struct(frame, frame_addr, 0);
332 return -TARGET_QEMU_ESIGRETURN;
333
334badframe:
335 unlock_user_struct(frame, frame_addr, 0);
336 force_sig(TARGET_SIGSEGV);
337 return -TARGET_QEMU_ESIGRETURN;
338}
339