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 "user-internals.h"
22#include "signal-common.h"
23#include "linux-user/trace.h"
24
25# if defined(TARGET_ABI_MIPSO32)
26struct target_sigcontext {
27 uint32_t sc_regmask;
28 uint32_t sc_status;
29 uint64_t sc_pc;
30 uint64_t sc_regs[32];
31 uint64_t sc_fpregs[32];
32 uint32_t sc_ownedfp;
33 uint32_t sc_fpc_csr;
34 uint32_t sc_fpc_eir;
35 uint32_t sc_used_math;
36 uint32_t sc_dsp;
37 uint32_t pad0;
38 uint64_t sc_mdhi;
39 uint64_t sc_mdlo;
40 target_ulong sc_hi1;
41 target_ulong sc_lo1;
42 target_ulong sc_hi2;
43 target_ulong sc_lo2;
44 target_ulong sc_hi3;
45 target_ulong sc_lo3;
46};
47# else
48struct target_sigcontext {
49 uint64_t sc_regs[32];
50 uint64_t sc_fpregs[32];
51 uint64_t sc_mdhi;
52 uint64_t sc_hi1;
53 uint64_t sc_hi2;
54 uint64_t sc_hi3;
55 uint64_t sc_mdlo;
56 uint64_t sc_lo1;
57 uint64_t sc_lo2;
58 uint64_t sc_lo3;
59 uint64_t sc_pc;
60 uint32_t sc_fpc_csr;
61 uint32_t sc_used_math;
62 uint32_t sc_dsp;
63 uint32_t sc_reserved;
64};
65# endif
66
67struct sigframe {
68 uint32_t sf_ass[4];
69 uint32_t sf_code[2];
70 struct target_sigcontext sf_sc;
71 target_sigset_t sf_mask;
72};
73
74struct target_ucontext {
75 abi_ulong tuc_flags;
76 abi_ulong tuc_link;
77 target_stack_t tuc_stack;
78 struct target_sigcontext tuc_mcontext;
79 target_sigset_t tuc_sigmask;
80};
81
82struct target_rt_sigframe {
83 uint32_t rs_ass[4];
84 uint32_t rs_code[2];
85 struct target_siginfo rs_info;
86 struct target_ucontext rs_uc;
87};
88
89
90static void install_sigtramp(uint32_t *tramp, unsigned int syscall)
91{
92
93
94
95
96
97
98
99 __put_user(0x24020000 + syscall, tramp + 0);
100 __put_user(0x0000000c , tramp + 1);
101}
102
103static inline void setup_sigcontext(CPUMIPSState *regs,
104 struct target_sigcontext *sc)
105{
106 int i;
107
108 __put_user(exception_resume_pc(regs), &sc->sc_pc);
109 regs->hflags &= ~MIPS_HFLAG_BMASK;
110
111 __put_user(0, &sc->sc_regs[0]);
112 for (i = 1; i < 32; ++i) {
113 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
114 }
115
116 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
117 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
118
119
120
121 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
122 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
123 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
124 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
125 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
126 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
127 {
128 uint32_t dsp = cpu_rddsp(0x3ff, regs);
129 __put_user(dsp, &sc->sc_dsp);
130 }
131
132 __put_user(1, &sc->sc_used_math);
133
134 for (i = 0; i < 32; ++i) {
135 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
136 }
137}
138
139static inline void
140restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
141{
142 int i;
143
144 __get_user(regs->CP0_EPC, &sc->sc_pc);
145
146 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
147 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
148
149 for (i = 1; i < 32; ++i) {
150 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
151 }
152
153 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
154 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
155 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
156 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
157 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
158 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
159 {
160 uint32_t dsp;
161 __get_user(dsp, &sc->sc_dsp);
162 cpu_wrdsp(dsp, 0x3ff, regs);
163 }
164
165 for (i = 0; i < 32; ++i) {
166 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
167 }
168}
169
170
171
172
173static inline abi_ulong
174get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
175{
176 unsigned long sp;
177
178
179
180
181
182
183 sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka);
184
185 return (sp - frame_size) & ~7;
186}
187
188static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
189{
190 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
191 env->hflags &= ~MIPS_HFLAG_M16;
192 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
193 env->active_tc.PC &= ~(target_ulong) 1;
194 }
195}
196
197# if defined(TARGET_ABI_MIPSO32)
198
199void setup_frame(int sig, struct target_sigaction * ka,
200 target_sigset_t *set, CPUMIPSState *regs)
201{
202 struct sigframe *frame;
203 abi_ulong frame_addr;
204 int i;
205
206 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
207 trace_user_setup_frame(regs, frame_addr);
208 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
209 goto give_sigsegv;
210 }
211
212 setup_sigcontext(regs, &frame->sf_sc);
213
214 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
215 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
216 }
217
218
219
220
221
222
223
224
225
226
227
228 regs->active_tc.gpr[ 4] = sig;
229 regs->active_tc.gpr[ 5] = 0;
230 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
231 regs->active_tc.gpr[29] = frame_addr;
232 regs->active_tc.gpr[31] = default_sigreturn;
233
234
235
236 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
237 mips_set_hflags_isa_mode_from_pc(regs);
238 unlock_user_struct(frame, frame_addr, 1);
239 return;
240
241give_sigsegv:
242 force_sigsegv(sig);
243}
244
245long do_sigreturn(CPUMIPSState *regs)
246{
247 struct sigframe *frame;
248 abi_ulong frame_addr;
249 sigset_t blocked;
250 target_sigset_t target_set;
251 int i;
252
253 frame_addr = regs->active_tc.gpr[29];
254 trace_user_do_sigreturn(regs, frame_addr);
255 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
256 goto badframe;
257
258 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
259 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
260 }
261
262 target_to_host_sigset_internal(&blocked, &target_set);
263 set_sigmask(&blocked);
264
265 restore_sigcontext(regs, &frame->sf_sc);
266
267#if 0
268
269
270
271 __asm__ __volatile__(
272 "move\t$29, %0\n\t"
273 "j\tsyscall_exit"
274 :
275 :"r" (®s));
276
277#endif
278
279 regs->active_tc.PC = regs->CP0_EPC;
280 mips_set_hflags_isa_mode_from_pc(regs);
281
282
283 regs->CP0_EPC = 0;
284 return -TARGET_QEMU_ESIGRETURN;
285
286badframe:
287 force_sig(TARGET_SIGSEGV);
288 return -TARGET_QEMU_ESIGRETURN;
289}
290# endif
291
292void setup_rt_frame(int sig, struct target_sigaction *ka,
293 target_siginfo_t *info,
294 target_sigset_t *set, CPUMIPSState *env)
295{
296 struct target_rt_sigframe *frame;
297 abi_ulong frame_addr;
298 int i;
299
300 frame_addr = get_sigframe(ka, env, sizeof(*frame));
301 trace_user_setup_rt_frame(env, frame_addr);
302 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
303 goto give_sigsegv;
304 }
305
306 tswap_siginfo(&frame->rs_info, info);
307
308 __put_user(0, &frame->rs_uc.tuc_flags);
309 __put_user(0, &frame->rs_uc.tuc_link);
310 target_save_altstack(&frame->rs_uc.tuc_stack, env);
311
312 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
313
314 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
315 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
316 }
317
318
319
320
321
322
323
324
325
326
327
328 env->active_tc.gpr[ 4] = sig;
329 env->active_tc.gpr[ 5] = frame_addr
330 + offsetof(struct target_rt_sigframe, rs_info);
331 env->active_tc.gpr[ 6] = frame_addr
332 + offsetof(struct target_rt_sigframe, rs_uc);
333 env->active_tc.gpr[29] = frame_addr;
334 env->active_tc.gpr[31] = default_rt_sigreturn;
335
336
337
338
339
340
341 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
342 mips_set_hflags_isa_mode_from_pc(env);
343 unlock_user_struct(frame, frame_addr, 1);
344 return;
345
346give_sigsegv:
347 unlock_user_struct(frame, frame_addr, 1);
348 force_sigsegv(sig);
349}
350
351long do_rt_sigreturn(CPUMIPSState *env)
352{
353 struct target_rt_sigframe *frame;
354 abi_ulong frame_addr;
355 sigset_t blocked;
356
357 frame_addr = env->active_tc.gpr[29];
358 trace_user_do_rt_sigreturn(env, frame_addr);
359 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
360 goto badframe;
361 }
362
363 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
364 set_sigmask(&blocked);
365
366 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
367 target_restore_altstack(&frame->rs_uc.tuc_stack, env);
368
369 env->active_tc.PC = env->CP0_EPC;
370 mips_set_hflags_isa_mode_from_pc(env);
371
372
373 env->CP0_EPC = 0;
374 return -TARGET_QEMU_ESIGRETURN;
375
376badframe:
377 force_sig(TARGET_SIGSEGV);
378 return -TARGET_QEMU_ESIGRETURN;
379}
380
381void setup_sigtramp(abi_ulong sigtramp_page)
382{
383 uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
384 assert(tramp != NULL);
385
386#ifdef TARGET_ARCH_HAS_SETUP_FRAME
387 default_sigreturn = sigtramp_page;
388 install_sigtramp(tramp, TARGET_NR_sigreturn);
389#endif
390
391 default_rt_sigreturn = sigtramp_page + 8;
392 install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
393
394 unlock_user(tramp, sigtramp_page, 2 * 8);
395}
396