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#define __NUM_GPRS 16
25#define __NUM_FPRS 16
26#define __NUM_ACRS 16
27
28#define S390_SYSCALL_SIZE 2
29#define __SIGNAL_FRAMESIZE 160
30
31#define _SIGCONTEXT_NSIG 64
32#define _SIGCONTEXT_NSIG_BPW 64
33#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
34#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
35#define PSW_ADDR_AMODE 0x0000000000000000UL
36#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
37
38typedef struct {
39 target_psw_t psw;
40 target_ulong gprs[__NUM_GPRS];
41 unsigned int acrs[__NUM_ACRS];
42} target_s390_regs_common;
43
44typedef struct {
45 unsigned int fpc;
46 double fprs[__NUM_FPRS];
47} target_s390_fp_regs;
48
49typedef struct {
50 target_s390_regs_common regs;
51 target_s390_fp_regs fpregs;
52} target_sigregs;
53
54struct target_sigcontext {
55 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
56 target_sigregs *sregs;
57};
58
59typedef struct {
60 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
61 struct target_sigcontext sc;
62 target_sigregs sregs;
63 int signo;
64 uint8_t retcode[S390_SYSCALL_SIZE];
65} sigframe;
66
67struct target_ucontext {
68 target_ulong tuc_flags;
69 struct target_ucontext *tuc_link;
70 target_stack_t tuc_stack;
71 target_sigregs tuc_mcontext;
72 target_sigset_t tuc_sigmask;
73};
74
75typedef struct {
76 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
77 uint8_t retcode[S390_SYSCALL_SIZE];
78 struct target_siginfo info;
79 struct target_ucontext uc;
80} rt_sigframe;
81
82static inline abi_ulong
83get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
84{
85 abi_ulong sp;
86
87
88 sp = get_sp_from_cpustate(env);
89
90
91 if (ka->sa_flags & TARGET_SA_ONSTACK) {
92 sp = target_sigsp(sp, ka);
93 }
94
95
96 else if ( 0 &&
97 !(ka->sa_flags & TARGET_SA_RESTORER) &&
98 ka->sa_restorer) {
99 sp = (abi_ulong) ka->sa_restorer;
100 }
101
102 return (sp - frame_size) & -8ul;
103}
104
105static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
106{
107 int i;
108
109
110
111
112 __put_user(env->psw.mask, &sregs->regs.psw.mask);
113 __put_user(env->psw.addr, &sregs->regs.psw.addr);
114 for (i = 0; i < 16; i++) {
115 __put_user(env->regs[i], &sregs->regs.gprs[i]);
116 }
117 for (i = 0; i < 16; i++) {
118 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
119 }
120
121
122
123
124
125 for (i = 0; i < 16; i++) {
126 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
127 }
128}
129
130void setup_frame(int sig, struct target_sigaction *ka,
131 target_sigset_t *set, CPUS390XState *env)
132{
133 sigframe *frame;
134 abi_ulong frame_addr;
135
136 frame_addr = get_sigframe(ka, env, sizeof(*frame));
137 trace_user_setup_frame(env, frame_addr);
138 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
139 goto give_sigsegv;
140 }
141
142 __put_user(set->sig[0], &frame->sc.oldmask[0]);
143
144 save_sigregs(env, &frame->sregs);
145
146 __put_user((abi_ulong)(unsigned long)&frame->sregs,
147 (abi_ulong *)&frame->sc.sregs);
148
149
150
151 if (ka->sa_flags & TARGET_SA_RESTORER) {
152 env->regs[14] = (unsigned long)
153 ka->sa_restorer | PSW_ADDR_AMODE;
154 } else {
155 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
156 | PSW_ADDR_AMODE;
157 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
158 (uint16_t *)(frame->retcode));
159 }
160
161
162 __put_user(env->regs[15], (abi_ulong *) frame);
163
164
165 env->regs[15] = frame_addr;
166 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
167
168 env->regs[2] = sig;
169 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
170
171
172
173 env->regs[4] = 0;
174 env->regs[5] = 0;
175
176
177 __put_user(env->regs[2], &frame->signo);
178 unlock_user_struct(frame, frame_addr, 1);
179 return;
180
181give_sigsegv:
182 force_sigsegv(sig);
183}
184
185void setup_rt_frame(int sig, struct target_sigaction *ka,
186 target_siginfo_t *info,
187 target_sigset_t *set, CPUS390XState *env)
188{
189 int i;
190 rt_sigframe *frame;
191 abi_ulong frame_addr;
192
193 frame_addr = get_sigframe(ka, env, sizeof *frame);
194 trace_user_setup_rt_frame(env, frame_addr);
195 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
196 goto give_sigsegv;
197 }
198
199 tswap_siginfo(&frame->info, info);
200
201
202 __put_user(0, &frame->uc.tuc_flags);
203 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
204 target_save_altstack(&frame->uc.tuc_stack, env);
205 save_sigregs(env, &frame->uc.tuc_mcontext);
206 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
207 __put_user((abi_ulong)set->sig[i],
208 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
209 }
210
211
212
213 if (ka->sa_flags & TARGET_SA_RESTORER) {
214 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
215 } else {
216 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
217 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
218 (uint16_t *)(frame->retcode));
219 }
220
221
222 __put_user(env->regs[15], (abi_ulong *) frame);
223
224
225 env->regs[15] = frame_addr;
226 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
227
228 env->regs[2] = sig;
229 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
230 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
231 return;
232
233give_sigsegv:
234 force_sigsegv(sig);
235}
236
237static int
238restore_sigregs(CPUS390XState *env, target_sigregs *sc)
239{
240 int err = 0;
241 int i;
242
243 for (i = 0; i < 16; i++) {
244 __get_user(env->regs[i], &sc->regs.gprs[i]);
245 }
246
247 __get_user(env->psw.mask, &sc->regs.psw.mask);
248 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
249 (unsigned long long)env->psw.addr);
250 __get_user(env->psw.addr, &sc->regs.psw.addr);
251
252
253 for (i = 0; i < 16; i++) {
254 __get_user(env->aregs[i], &sc->regs.acrs[i]);
255 }
256 for (i = 0; i < 16; i++) {
257 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
258 }
259
260 return err;
261}
262
263long do_sigreturn(CPUS390XState *env)
264{
265 sigframe *frame;
266 abi_ulong frame_addr = env->regs[15];
267 target_sigset_t target_set;
268 sigset_t set;
269
270 trace_user_do_sigreturn(env, frame_addr);
271 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
272 goto badframe;
273 }
274 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
275
276 target_to_host_sigset_internal(&set, &target_set);
277 set_sigmask(&set);
278
279 if (restore_sigregs(env, &frame->sregs)) {
280 goto badframe;
281 }
282
283 unlock_user_struct(frame, frame_addr, 0);
284 return -TARGET_QEMU_ESIGRETURN;
285
286badframe:
287 force_sig(TARGET_SIGSEGV);
288 return -TARGET_QEMU_ESIGRETURN;
289}
290
291long do_rt_sigreturn(CPUS390XState *env)
292{
293 rt_sigframe *frame;
294 abi_ulong frame_addr = env->regs[15];
295 sigset_t set;
296
297 trace_user_do_rt_sigreturn(env, frame_addr);
298 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
299 goto badframe;
300 }
301 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
302
303 set_sigmask(&set);
304
305 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
306 goto badframe;
307 }
308
309 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
310 get_sp_from_cpustate(env)) == -EFAULT) {
311 goto badframe;
312 }
313 unlock_user_struct(frame, frame_addr, 0);
314 return -TARGET_QEMU_ESIGRETURN;
315
316badframe:
317 unlock_user_struct(frame, frame_addr, 0);
318 force_sig(TARGET_SIGSEGV);
319 return -TARGET_QEMU_ESIGRETURN;
320}
321