aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/signal.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/s390/kernel/signal.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/s390/kernel/signal.c')
-rw-r--r--arch/s390/kernel/signal.c527
1 files changed, 527 insertions, 0 deletions
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
new file mode 100644
index 000000000000..610c1d03e975
--- /dev/null
+++ b/arch/s390/kernel/signal.c
@@ -0,0 +1,527 @@
1/*
2 * arch/s390/kernel/signal.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
7 *
8 * Based on Intel version
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 *
12 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
13 */
14
15#include <linux/config.h>
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/smp.h>
19#include <linux/smp_lock.h>
20#include <linux/kernel.h>
21#include <linux/signal.h>
22#include <linux/errno.h>
23#include <linux/wait.h>
24#include <linux/ptrace.h>
25#include <linux/unistd.h>
26#include <linux/stddef.h>
27#include <linux/tty.h>
28#include <linux/personality.h>
29#include <linux/binfmts.h>
30#include <asm/ucontext.h>
31#include <asm/uaccess.h>
32#include <asm/lowcore.h>
33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35
36
37typedef struct
38{
39 __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
40 struct sigcontext sc;
41 _sigregs sregs;
42 int signo;
43 __u8 retcode[S390_SYSCALL_SIZE];
44} sigframe;
45
46typedef struct
47{
48 __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
49 __u8 retcode[S390_SYSCALL_SIZE];
50 struct siginfo info;
51 struct ucontext uc;
52} rt_sigframe;
53
54int do_signal(struct pt_regs *regs, sigset_t *oldset);
55
56/*
57 * Atomically swap in the new signal mask, and wait for a signal.
58 */
59asmlinkage int
60sys_sigsuspend(struct pt_regs * regs, int history0, int history1,
61 old_sigset_t mask)
62{
63 sigset_t saveset;
64
65 mask &= _BLOCKABLE;
66 spin_lock_irq(&current->sighand->siglock);
67 saveset = current->blocked;
68 siginitset(&current->blocked, mask);
69 recalc_sigpending();
70 spin_unlock_irq(&current->sighand->siglock);
71 regs->gprs[2] = -EINTR;
72
73 while (1) {
74 set_current_state(TASK_INTERRUPTIBLE);
75 schedule();
76 if (do_signal(regs, &saveset))
77 return -EINTR;
78 }
79}
80
81asmlinkage long
82sys_rt_sigsuspend(struct pt_regs *regs, sigset_t __user *unewset,
83 size_t sigsetsize)
84{
85 sigset_t saveset, newset;
86
87 /* XXX: Don't preclude handling different sized sigset_t's. */
88 if (sigsetsize != sizeof(sigset_t))
89 return -EINVAL;
90
91 if (copy_from_user(&newset, unewset, sizeof(newset)))
92 return -EFAULT;
93 sigdelsetmask(&newset, ~_BLOCKABLE);
94
95 spin_lock_irq(&current->sighand->siglock);
96 saveset = current->blocked;
97 current->blocked = newset;
98 recalc_sigpending();
99 spin_unlock_irq(&current->sighand->siglock);
100 regs->gprs[2] = -EINTR;
101
102 while (1) {
103 set_current_state(TASK_INTERRUPTIBLE);
104 schedule();
105 if (do_signal(regs, &saveset))
106 return -EINTR;
107 }
108}
109
110asmlinkage long
111sys_sigaction(int sig, const struct old_sigaction __user *act,
112 struct old_sigaction __user *oact)
113{
114 struct k_sigaction new_ka, old_ka;
115 int ret;
116
117 if (act) {
118 old_sigset_t mask;
119 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
120 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
121 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
122 return -EFAULT;
123 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
124 __get_user(mask, &act->sa_mask);
125 siginitset(&new_ka.sa.sa_mask, mask);
126 }
127
128 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
129
130 if (!ret && oact) {
131 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
132 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
133 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
134 return -EFAULT;
135 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
136 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
137 }
138
139 return ret;
140}
141
142asmlinkage long
143sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
144 struct pt_regs *regs)
145{
146 return do_sigaltstack(uss, uoss, regs->gprs[15]);
147}
148
149
150
151/* Returns non-zero on fault. */
152static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
153{
154 unsigned long old_mask = regs->psw.mask;
155 int err;
156
157 save_access_regs(current->thread.acrs);
158
159 /* Copy a 'clean' PSW mask to the user to avoid leaking
160 information about whether PER is currently on. */
161 regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
162 err = __copy_to_user(&sregs->regs.psw, &regs->psw,
163 sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
164 regs->psw.mask = old_mask;
165 if (err != 0)
166 return err;
167 err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs,
168 sizeof(sregs->regs.acrs));
169 if (err != 0)
170 return err;
171 /*
172 * We have to store the fp registers to current->thread.fp_regs
173 * to merge them with the emulated registers.
174 */
175 save_fp_regs(&current->thread.fp_regs);
176 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
177 sizeof(s390_fp_regs));
178}
179
180/* Returns positive number on error */
181static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
182{
183 unsigned long old_mask = regs->psw.mask;
184 int err;
185
186 /* Alwys make any pending restarted system call return -EINTR */
187 current_thread_info()->restart_block.fn = do_no_restart_syscall;
188
189 err = __copy_from_user(&regs->psw, &sregs->regs.psw,
190 sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
191 regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask);
192 regs->psw.addr |= PSW_ADDR_AMODE;
193 if (err)
194 return err;
195 err = __copy_from_user(&current->thread.acrs, &sregs->regs.acrs,
196 sizeof(sregs->regs.acrs));
197 if (err)
198 return err;
199 restore_access_regs(current->thread.acrs);
200
201 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
202 sizeof(s390_fp_regs));
203 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
204 if (err)
205 return err;
206
207 restore_fp_regs(&current->thread.fp_regs);
208 regs->trap = -1; /* disable syscall checks */
209 return 0;
210}
211
212asmlinkage long sys_sigreturn(struct pt_regs *regs)
213{
214 sigframe __user *frame = (sigframe __user *)regs->gprs[15];
215 sigset_t set;
216
217 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
218 goto badframe;
219 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
220 goto badframe;
221
222 sigdelsetmask(&set, ~_BLOCKABLE);
223 spin_lock_irq(&current->sighand->siglock);
224 current->blocked = set;
225 recalc_sigpending();
226 spin_unlock_irq(&current->sighand->siglock);
227
228 if (restore_sigregs(regs, &frame->sregs))
229 goto badframe;
230
231 return regs->gprs[2];
232
233badframe:
234 force_sig(SIGSEGV, current);
235 return 0;
236}
237
238asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
239{
240 rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
241 sigset_t set;
242
243 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
244 goto badframe;
245 if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
246 goto badframe;
247
248 sigdelsetmask(&set, ~_BLOCKABLE);
249 spin_lock_irq(&current->sighand->siglock);
250 current->blocked = set;
251 recalc_sigpending();
252 spin_unlock_irq(&current->sighand->siglock);
253
254 if (restore_sigregs(regs, &frame->uc.uc_mcontext))
255 goto badframe;
256
257 /* It is more difficult to avoid calling this function than to
258 call it and ignore errors. */
259 do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
260 return regs->gprs[2];
261
262badframe:
263 force_sig(SIGSEGV, current);
264 return 0;
265}
266
267/*
268 * Set up a signal frame.
269 */
270
271
272/*
273 * Determine which stack to use..
274 */
275static inline void __user *
276get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
277{
278 unsigned long sp;
279
280 /* Default to using normal stack */
281 sp = regs->gprs[15];
282
283 /* This is the X/Open sanctioned signal stack switching. */
284 if (ka->sa.sa_flags & SA_ONSTACK) {
285 if (! sas_ss_flags(sp))
286 sp = current->sas_ss_sp + current->sas_ss_size;
287 }
288
289 /* This is the legacy signal stack switching. */
290 else if (!user_mode(regs) &&
291 !(ka->sa.sa_flags & SA_RESTORER) &&
292 ka->sa.sa_restorer) {
293 sp = (unsigned long) ka->sa.sa_restorer;
294 }
295
296 return (void __user *)((sp - frame_size) & -8ul);
297}
298
299static inline int map_signal(int sig)
300{
301 if (current_thread_info()->exec_domain
302 && current_thread_info()->exec_domain->signal_invmap
303 && sig < 32)
304 return current_thread_info()->exec_domain->signal_invmap[sig];
305 else
306 return sig;
307}
308
309static void setup_frame(int sig, struct k_sigaction *ka,
310 sigset_t *set, struct pt_regs * regs)
311{
312 sigframe __user *frame;
313
314 frame = get_sigframe(ka, regs, sizeof(sigframe));
315 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
316 goto give_sigsegv;
317
318 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
319 goto give_sigsegv;
320
321 if (save_sigregs(regs, &frame->sregs))
322 goto give_sigsegv;
323 if (__put_user(&frame->sregs, &frame->sc.sregs))
324 goto give_sigsegv;
325
326 /* Set up to return from userspace. If provided, use a stub
327 already in userspace. */
328 if (ka->sa.sa_flags & SA_RESTORER) {
329 regs->gprs[14] = (unsigned long)
330 ka->sa.sa_restorer | PSW_ADDR_AMODE;
331 } else {
332 regs->gprs[14] = (unsigned long)
333 frame->retcode | PSW_ADDR_AMODE;
334 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
335 (u16 __user *)(frame->retcode)))
336 goto give_sigsegv;
337 }
338
339 /* Set up backchain. */
340 if (__put_user(regs->gprs[15], (addr_t __user *) frame))
341 goto give_sigsegv;
342
343 /* Set up registers for signal handler */
344 regs->gprs[15] = (unsigned long) frame;
345 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
346
347 regs->gprs[2] = map_signal(sig);
348 regs->gprs[3] = (unsigned long) &frame->sc;
349
350 /* We forgot to include these in the sigcontext.
351 To avoid breaking binary compatibility, they are passed as args. */
352 regs->gprs[4] = current->thread.trap_no;
353 regs->gprs[5] = current->thread.prot_addr;
354
355 /* Place signal number on stack to allow backtrace from handler. */
356 if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
357 goto give_sigsegv;
358 return;
359
360give_sigsegv:
361 force_sigsegv(sig, current);
362}
363
364static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
365 sigset_t *set, struct pt_regs * regs)
366{
367 int err = 0;
368 rt_sigframe __user *frame;
369
370 frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
371 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
372 goto give_sigsegv;
373
374 if (copy_siginfo_to_user(&frame->info, info))
375 goto give_sigsegv;
376
377 /* Create the ucontext. */
378 err |= __put_user(0, &frame->uc.uc_flags);
379 err |= __put_user(0, &frame->uc.uc_link);
380 err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
381 err |= __put_user(sas_ss_flags(regs->gprs[15]),
382 &frame->uc.uc_stack.ss_flags);
383 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
384 err |= save_sigregs(regs, &frame->uc.uc_mcontext);
385 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
386 if (err)
387 goto give_sigsegv;
388
389 /* Set up to return from userspace. If provided, use a stub
390 already in userspace. */
391 if (ka->sa.sa_flags & SA_RESTORER) {
392 regs->gprs[14] = (unsigned long)
393 ka->sa.sa_restorer | PSW_ADDR_AMODE;
394 } else {
395 regs->gprs[14] = (unsigned long)
396 frame->retcode | PSW_ADDR_AMODE;
397 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
398 (u16 __user *)(frame->retcode));
399 }
400
401 /* Set up backchain. */
402 if (__put_user(regs->gprs[15], (addr_t __user *) frame))
403 goto give_sigsegv;
404
405 /* Set up registers for signal handler */
406 regs->gprs[15] = (unsigned long) frame;
407 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
408
409 regs->gprs[2] = map_signal(sig);
410 regs->gprs[3] = (unsigned long) &frame->info;
411 regs->gprs[4] = (unsigned long) &frame->uc;
412 return;
413
414give_sigsegv:
415 force_sigsegv(sig, current);
416}
417
418/*
419 * OK, we're invoking a handler
420 */
421
422static void
423handle_signal(unsigned long sig, struct k_sigaction *ka,
424 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
425{
426 /* Set up the stack frame */
427 if (ka->sa.sa_flags & SA_SIGINFO)
428 setup_rt_frame(sig, ka, info, oldset, regs);
429 else
430 setup_frame(sig, ka, oldset, regs);
431
432 if (!(ka->sa.sa_flags & SA_NODEFER)) {
433 spin_lock_irq(&current->sighand->siglock);
434 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
435 sigaddset(&current->blocked,sig);
436 recalc_sigpending();
437 spin_unlock_irq(&current->sighand->siglock);
438 }
439}
440
441/*
442 * Note that 'init' is a special process: it doesn't get signals it doesn't
443 * want to handle. Thus you cannot kill init even with a SIGKILL even by
444 * mistake.
445 *
446 * Note that we go through the signals twice: once to check the signals that
447 * the kernel can handle, and then we build all the user-level signal handling
448 * stack-frames in one go after that.
449 */
450int do_signal(struct pt_regs *regs, sigset_t *oldset)
451{
452 unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
453 siginfo_t info;
454 int signr;
455 struct k_sigaction ka;
456
457 /*
458 * We want the common case to go fast, which
459 * is why we may in certain cases get here from
460 * kernel mode. Just return without doing anything
461 * if so.
462 */
463 if (!user_mode(regs))
464 return 1;
465
466 if (!oldset)
467 oldset = &current->blocked;
468
469 /* Are we from a system call? */
470 if (regs->trap == __LC_SVC_OLD_PSW) {
471 continue_addr = regs->psw.addr;
472 restart_addr = continue_addr - regs->ilc;
473 retval = regs->gprs[2];
474
475 /* Prepare for system call restart. We do this here so that a
476 debugger will see the already changed PSW. */
477 if (retval == -ERESTARTNOHAND ||
478 retval == -ERESTARTSYS ||
479 retval == -ERESTARTNOINTR) {
480 regs->gprs[2] = regs->orig_gpr2;
481 regs->psw.addr = restart_addr;
482 } else if (retval == -ERESTART_RESTARTBLOCK) {
483 regs->gprs[2] = -EINTR;
484 }
485 }
486
487 /* Get signal to deliver. When running under ptrace, at this point
488 the debugger may change all our registers ... */
489 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
490
491 /* Depending on the signal settings we may need to revert the
492 decision to restart the system call. */
493 if (signr > 0 && regs->psw.addr == restart_addr) {
494 if (retval == -ERESTARTNOHAND
495 || (retval == -ERESTARTSYS
496 && !(current->sighand->action[signr-1].sa.sa_flags
497 & SA_RESTART))) {
498 regs->gprs[2] = -EINTR;
499 regs->psw.addr = continue_addr;
500 }
501 }
502
503 if (signr > 0) {
504 /* Whee! Actually deliver the signal. */
505#ifdef CONFIG_S390_SUPPORT
506 if (test_thread_flag(TIF_31BIT)) {
507 extern void handle_signal32(unsigned long sig,
508 struct k_sigaction *ka,
509 siginfo_t *info,
510 sigset_t *oldset,
511 struct pt_regs *regs);
512 handle_signal32(signr, &ka, &info, oldset, regs);
513 return 1;
514 }
515#endif
516 handle_signal(signr, &ka, &info, oldset, regs);
517 return 1;
518 }
519
520 /* Restart a different system call. */
521 if (retval == -ERESTART_RESTARTBLOCK
522 && regs->psw.addr == continue_addr) {
523 regs->gprs[2] = __NR_restart_syscall;
524 set_thread_flag(TIF_RESTART_SVC);
525 }
526 return 0;
527}
href='#n4040'>4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
%PDF-1.4
%äüöß
2 0 obj
<</Length 3 0 R/Filter/FlateDecode>>
stream
xMqE+Z@H@ь^=w,F}̈佑n*V(r>)~L_ks?>.?G<]yE?]_C`W䧏cO#7u׬6}%4oE0q6;}=<^Ep
=)CIsn
G'=$Ǽܤ7_O噓7>^/l%GuITG_>蔮G͚fAZ_iC{ӊ0`1b)#>Aݠi?қVkme=~(ܴ?8vg\|<T!Dc6=}W<DoRJ0C@j0-ף-P}lP!Ӯg@F>aiZgs!N8ՠ=OǛQiELpNx^'8'2`Z
zZtx16S
*X!k;*l>7-m`~-yh;