diff options
author | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-01-15 05:20:01 -0500 |
---|---|---|
committer | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-03-16 21:19:10 -0400 |
commit | f864d2f8304e6be90b4c4e4ac615edc6fcefd4c1 (patch) | |
tree | 97842fb75f099cfc183b9f63b0d8e6ef61d8bea1 /arch/unicore32/kernel | |
parent | 752bcb4d02ccfd5e7a8d810424154169b4cca8ae (diff) |
unicore32 core architecture: signals handling
This patch implements signals.
Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Diffstat (limited to 'arch/unicore32/kernel')
-rw-r--r-- | arch/unicore32/kernel/signal.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c new file mode 100644 index 000000000000..b163fca56789 --- /dev/null +++ b/arch/unicore32/kernel/signal.c | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/kernel/signal.c | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/signal.h> | ||
14 | #include <linux/personality.h> | ||
15 | #include <linux/freezer.h> | ||
16 | #include <linux/uaccess.h> | ||
17 | #include <linux/tracehook.h> | ||
18 | #include <linux/elf.h> | ||
19 | #include <linux/unistd.h> | ||
20 | |||
21 | #include <asm/cacheflush.h> | ||
22 | #include <asm/ucontext.h> | ||
23 | |||
24 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
25 | |||
26 | /* | ||
27 | * For UniCore syscalls, we encode the syscall number into the instruction. | ||
28 | */ | ||
29 | #define SWI_SYS_SIGRETURN (0xff000000) /* error number for new abi */ | ||
30 | #define SWI_SYS_RT_SIGRETURN (0xff000000 | (__NR_rt_sigreturn)) | ||
31 | #define SWI_SYS_RESTART (0xff000000 | (__NR_restart_syscall)) | ||
32 | |||
33 | #define KERN_SIGRETURN_CODE (KUSER_VECPAGE_BASE + 0x00000500) | ||
34 | #define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) | ||
35 | |||
36 | const unsigned long sigreturn_codes[3] = { | ||
37 | SWI_SYS_SIGRETURN, SWI_SYS_RT_SIGRETURN, | ||
38 | }; | ||
39 | |||
40 | const unsigned long syscall_restart_code[2] = { | ||
41 | SWI_SYS_RESTART, /* swi __NR_restart_syscall */ | ||
42 | 0x69efc004, /* ldr pc, [sp], #4 */ | ||
43 | }; | ||
44 | |||
45 | /* | ||
46 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. | ||
47 | */ | ||
48 | struct sigframe { | ||
49 | struct ucontext uc; | ||
50 | unsigned long retcode[2]; | ||
51 | }; | ||
52 | |||
53 | struct rt_sigframe { | ||
54 | struct siginfo info; | ||
55 | struct sigframe sig; | ||
56 | }; | ||
57 | |||
58 | static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) | ||
59 | { | ||
60 | sigset_t set; | ||
61 | int err; | ||
62 | |||
63 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); | ||
64 | if (err == 0) { | ||
65 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
66 | spin_lock_irq(¤t->sighand->siglock); | ||
67 | current->blocked = set; | ||
68 | recalc_sigpending(); | ||
69 | spin_unlock_irq(¤t->sighand->siglock); | ||
70 | } | ||
71 | |||
72 | err |= __get_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00); | ||
73 | err |= __get_user(regs->UCreg_01, &sf->uc.uc_mcontext.regs.UCreg_01); | ||
74 | err |= __get_user(regs->UCreg_02, &sf->uc.uc_mcontext.regs.UCreg_02); | ||
75 | err |= __get_user(regs->UCreg_03, &sf->uc.uc_mcontext.regs.UCreg_03); | ||
76 | err |= __get_user(regs->UCreg_04, &sf->uc.uc_mcontext.regs.UCreg_04); | ||
77 | err |= __get_user(regs->UCreg_05, &sf->uc.uc_mcontext.regs.UCreg_05); | ||
78 | err |= __get_user(regs->UCreg_06, &sf->uc.uc_mcontext.regs.UCreg_06); | ||
79 | err |= __get_user(regs->UCreg_07, &sf->uc.uc_mcontext.regs.UCreg_07); | ||
80 | err |= __get_user(regs->UCreg_08, &sf->uc.uc_mcontext.regs.UCreg_08); | ||
81 | err |= __get_user(regs->UCreg_09, &sf->uc.uc_mcontext.regs.UCreg_09); | ||
82 | err |= __get_user(regs->UCreg_10, &sf->uc.uc_mcontext.regs.UCreg_10); | ||
83 | err |= __get_user(regs->UCreg_11, &sf->uc.uc_mcontext.regs.UCreg_11); | ||
84 | err |= __get_user(regs->UCreg_12, &sf->uc.uc_mcontext.regs.UCreg_12); | ||
85 | err |= __get_user(regs->UCreg_13, &sf->uc.uc_mcontext.regs.UCreg_13); | ||
86 | err |= __get_user(regs->UCreg_14, &sf->uc.uc_mcontext.regs.UCreg_14); | ||
87 | err |= __get_user(regs->UCreg_15, &sf->uc.uc_mcontext.regs.UCreg_15); | ||
88 | err |= __get_user(regs->UCreg_16, &sf->uc.uc_mcontext.regs.UCreg_16); | ||
89 | err |= __get_user(regs->UCreg_17, &sf->uc.uc_mcontext.regs.UCreg_17); | ||
90 | err |= __get_user(regs->UCreg_18, &sf->uc.uc_mcontext.regs.UCreg_18); | ||
91 | err |= __get_user(regs->UCreg_19, &sf->uc.uc_mcontext.regs.UCreg_19); | ||
92 | err |= __get_user(regs->UCreg_20, &sf->uc.uc_mcontext.regs.UCreg_20); | ||
93 | err |= __get_user(regs->UCreg_21, &sf->uc.uc_mcontext.regs.UCreg_21); | ||
94 | err |= __get_user(regs->UCreg_22, &sf->uc.uc_mcontext.regs.UCreg_22); | ||
95 | err |= __get_user(regs->UCreg_23, &sf->uc.uc_mcontext.regs.UCreg_23); | ||
96 | err |= __get_user(regs->UCreg_24, &sf->uc.uc_mcontext.regs.UCreg_24); | ||
97 | err |= __get_user(regs->UCreg_25, &sf->uc.uc_mcontext.regs.UCreg_25); | ||
98 | err |= __get_user(regs->UCreg_26, &sf->uc.uc_mcontext.regs.UCreg_26); | ||
99 | err |= __get_user(regs->UCreg_fp, &sf->uc.uc_mcontext.regs.UCreg_fp); | ||
100 | err |= __get_user(regs->UCreg_ip, &sf->uc.uc_mcontext.regs.UCreg_ip); | ||
101 | err |= __get_user(regs->UCreg_sp, &sf->uc.uc_mcontext.regs.UCreg_sp); | ||
102 | err |= __get_user(regs->UCreg_lr, &sf->uc.uc_mcontext.regs.UCreg_lr); | ||
103 | err |= __get_user(regs->UCreg_pc, &sf->uc.uc_mcontext.regs.UCreg_pc); | ||
104 | err |= __get_user(regs->UCreg_asr, &sf->uc.uc_mcontext.regs.UCreg_asr); | ||
105 | |||
106 | err |= !valid_user_regs(regs); | ||
107 | |||
108 | return err; | ||
109 | } | ||
110 | |||
111 | asmlinkage int __sys_rt_sigreturn(struct pt_regs *regs) | ||
112 | { | ||
113 | struct rt_sigframe __user *frame; | ||
114 | |||
115 | /* Always make any pending restarted system calls return -EINTR */ | ||
116 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
117 | |||
118 | /* | ||
119 | * Since we stacked the signal on a 64-bit boundary, | ||
120 | * then 'sp' should be word aligned here. If it's | ||
121 | * not, then the user is trying to mess with us. | ||
122 | */ | ||
123 | if (regs->UCreg_sp & 7) | ||
124 | goto badframe; | ||
125 | |||
126 | frame = (struct rt_sigframe __user *)regs->UCreg_sp; | ||
127 | |||
128 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
129 | goto badframe; | ||
130 | |||
131 | if (restore_sigframe(regs, &frame->sig)) | ||
132 | goto badframe; | ||
133 | |||
134 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->UCreg_sp) | ||
135 | == -EFAULT) | ||
136 | goto badframe; | ||
137 | |||
138 | return regs->UCreg_00; | ||
139 | |||
140 | badframe: | ||
141 | force_sig(SIGSEGV, current); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, | ||
146 | sigset_t *set) | ||
147 | { | ||
148 | int err = 0; | ||
149 | |||
150 | err |= __put_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00); | ||
151 | err |= __put_user(regs->UCreg_01, &sf->uc.uc_mcontext.regs.UCreg_01); | ||
152 | err |= __put_user(regs->UCreg_02, &sf->uc.uc_mcontext.regs.UCreg_02); | ||
153 | err |= __put_user(regs->UCreg_03, &sf->uc.uc_mcontext.regs.UCreg_03); | ||
154 | err |= __put_user(regs->UCreg_04, &sf->uc.uc_mcontext.regs.UCreg_04); | ||
155 | err |= __put_user(regs->UCreg_05, &sf->uc.uc_mcontext.regs.UCreg_05); | ||
156 | err |= __put_user(regs->UCreg_06, &sf->uc.uc_mcontext.regs.UCreg_06); | ||
157 | err |= __put_user(regs->UCreg_07, &sf->uc.uc_mcontext.regs.UCreg_07); | ||
158 | err |= __put_user(regs->UCreg_08, &sf->uc.uc_mcontext.regs.UCreg_08); | ||
159 | err |= __put_user(regs->UCreg_09, &sf->uc.uc_mcontext.regs.UCreg_09); | ||
160 | err |= __put_user(regs->UCreg_10, &sf->uc.uc_mcontext.regs.UCreg_10); | ||
161 | err |= __put_user(regs->UCreg_11, &sf->uc.uc_mcontext.regs.UCreg_11); | ||
162 | err |= __put_user(regs->UCreg_12, &sf->uc.uc_mcontext.regs.UCreg_12); | ||
163 | err |= __put_user(regs->UCreg_13, &sf->uc.uc_mcontext.regs.UCreg_13); | ||
164 | err |= __put_user(regs->UCreg_14, &sf->uc.uc_mcontext.regs.UCreg_14); | ||
165 | err |= __put_user(regs->UCreg_15, &sf->uc.uc_mcontext.regs.UCreg_15); | ||
166 | err |= __put_user(regs->UCreg_16, &sf->uc.uc_mcontext.regs.UCreg_16); | ||
167 | err |= __put_user(regs->UCreg_17, &sf->uc.uc_mcontext.regs.UCreg_17); | ||
168 | err |= __put_user(regs->UCreg_18, &sf->uc.uc_mcontext.regs.UCreg_18); | ||
169 | err |= __put_user(regs->UCreg_19, &sf->uc.uc_mcontext.regs.UCreg_19); | ||
170 | err |= __put_user(regs->UCreg_20, &sf->uc.uc_mcontext.regs.UCreg_20); | ||
171 | err |= __put_user(regs->UCreg_21, &sf->uc.uc_mcontext.regs.UCreg_21); | ||
172 | err |= __put_user(regs->UCreg_22, &sf->uc.uc_mcontext.regs.UCreg_22); | ||
173 | err |= __put_user(regs->UCreg_23, &sf->uc.uc_mcontext.regs.UCreg_23); | ||
174 | err |= __put_user(regs->UCreg_24, &sf->uc.uc_mcontext.regs.UCreg_24); | ||
175 | err |= __put_user(regs->UCreg_25, &sf->uc.uc_mcontext.regs.UCreg_25); | ||
176 | err |= __put_user(regs->UCreg_26, &sf->uc.uc_mcontext.regs.UCreg_26); | ||
177 | err |= __put_user(regs->UCreg_fp, &sf->uc.uc_mcontext.regs.UCreg_fp); | ||
178 | err |= __put_user(regs->UCreg_ip, &sf->uc.uc_mcontext.regs.UCreg_ip); | ||
179 | err |= __put_user(regs->UCreg_sp, &sf->uc.uc_mcontext.regs.UCreg_sp); | ||
180 | err |= __put_user(regs->UCreg_lr, &sf->uc.uc_mcontext.regs.UCreg_lr); | ||
181 | err |= __put_user(regs->UCreg_pc, &sf->uc.uc_mcontext.regs.UCreg_pc); | ||
182 | err |= __put_user(regs->UCreg_asr, &sf->uc.uc_mcontext.regs.UCreg_asr); | ||
183 | |||
184 | err |= __put_user(current->thread.trap_no, | ||
185 | &sf->uc.uc_mcontext.trap_no); | ||
186 | err |= __put_user(current->thread.error_code, | ||
187 | &sf->uc.uc_mcontext.error_code); | ||
188 | err |= __put_user(current->thread.address, | ||
189 | &sf->uc.uc_mcontext.fault_address); | ||
190 | err |= __put_user(set->sig[0], &sf->uc.uc_mcontext.oldmask); | ||
191 | |||
192 | err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); | ||
193 | |||
194 | return err; | ||
195 | } | ||
196 | |||
197 | static inline void __user *get_sigframe(struct k_sigaction *ka, | ||
198 | struct pt_regs *regs, int framesize) | ||
199 | { | ||
200 | unsigned long sp = regs->UCreg_sp; | ||
201 | void __user *frame; | ||
202 | |||
203 | /* | ||
204 | * This is the X/Open sanctioned signal stack switching. | ||
205 | */ | ||
206 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | ||
207 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
208 | |||
209 | /* | ||
210 | * ATPCS B01 mandates 8-byte alignment | ||
211 | */ | ||
212 | frame = (void __user *)((sp - framesize) & ~7); | ||
213 | |||
214 | /* | ||
215 | * Check that we can actually write to the signal frame. | ||
216 | */ | ||
217 | if (!access_ok(VERIFY_WRITE, frame, framesize)) | ||
218 | frame = NULL; | ||
219 | |||
220 | return frame; | ||
221 | } | ||
222 | |||
223 | static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, | ||
224 | unsigned long __user *rc, void __user *frame, int usig) | ||
225 | { | ||
226 | unsigned long handler = (unsigned long)ka->sa.sa_handler; | ||
227 | unsigned long retcode; | ||
228 | unsigned long asr = regs->UCreg_asr & ~PSR_f; | ||
229 | |||
230 | unsigned int idx = 0; | ||
231 | |||
232 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
233 | idx += 1; | ||
234 | |||
235 | if (__put_user(sigreturn_codes[idx], rc) || | ||
236 | __put_user(sigreturn_codes[idx+1], rc+1)) | ||
237 | return 1; | ||
238 | |||
239 | retcode = KERN_SIGRETURN_CODE + (idx << 2); | ||
240 | |||
241 | regs->UCreg_00 = usig; | ||
242 | regs->UCreg_sp = (unsigned long)frame; | ||
243 | regs->UCreg_lr = retcode; | ||
244 | regs->UCreg_pc = handler; | ||
245 | regs->UCreg_asr = asr; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int setup_frame(int usig, struct k_sigaction *ka, | ||
251 | sigset_t *set, struct pt_regs *regs) | ||
252 | { | ||
253 | struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
254 | int err = 0; | ||
255 | |||
256 | if (!frame) | ||
257 | return 1; | ||
258 | |||
259 | /* | ||
260 | * Set uc.uc_flags to a value which sc.trap_no would never have. | ||
261 | */ | ||
262 | err |= __put_user(0x5ac3c35a, &frame->uc.uc_flags); | ||
263 | |||
264 | err |= setup_sigframe(frame, regs, set); | ||
265 | if (err == 0) | ||
266 | err |= setup_return(regs, ka, frame->retcode, frame, usig); | ||
267 | |||
268 | return err; | ||
269 | } | ||
270 | |||
271 | static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | ||
272 | sigset_t *set, struct pt_regs *regs) | ||
273 | { | ||
274 | struct rt_sigframe __user *frame = | ||
275 | get_sigframe(ka, regs, sizeof(*frame)); | ||
276 | stack_t stack; | ||
277 | int err = 0; | ||
278 | |||
279 | if (!frame) | ||
280 | return 1; | ||
281 | |||
282 | err |= copy_siginfo_to_user(&frame->info, info); | ||
283 | |||
284 | err |= __put_user(0, &frame->sig.uc.uc_flags); | ||
285 | err |= __put_user(NULL, &frame->sig.uc.uc_link); | ||
286 | |||
287 | memset(&stack, 0, sizeof(stack)); | ||
288 | stack.ss_sp = (void __user *)current->sas_ss_sp; | ||
289 | stack.ss_flags = sas_ss_flags(regs->UCreg_sp); | ||
290 | stack.ss_size = current->sas_ss_size; | ||
291 | err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); | ||
292 | |||
293 | err |= setup_sigframe(&frame->sig, regs, set); | ||
294 | if (err == 0) | ||
295 | err |= setup_return(regs, ka, frame->sig.retcode, frame, usig); | ||
296 | |||
297 | if (err == 0) { | ||
298 | /* | ||
299 | * For realtime signals we must also set the second and third | ||
300 | * arguments for the signal handler. | ||
301 | */ | ||
302 | regs->UCreg_01 = (unsigned long)&frame->info; | ||
303 | regs->UCreg_02 = (unsigned long)&frame->sig.uc; | ||
304 | } | ||
305 | |||
306 | return err; | ||
307 | } | ||
308 | |||
309 | static inline void setup_syscall_restart(struct pt_regs *regs) | ||
310 | { | ||
311 | regs->UCreg_00 = regs->UCreg_ORIG_00; | ||
312 | regs->UCreg_pc -= 4; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * OK, we're invoking a handler | ||
317 | */ | ||
318 | static int handle_signal(unsigned long sig, struct k_sigaction *ka, | ||
319 | siginfo_t *info, sigset_t *oldset, | ||
320 | struct pt_regs *regs, int syscall) | ||
321 | { | ||
322 | struct thread_info *thread = current_thread_info(); | ||
323 | struct task_struct *tsk = current; | ||
324 | int usig = sig; | ||
325 | int ret; | ||
326 | |||
327 | /* | ||
328 | * If we were from a system call, check for system call restarting... | ||
329 | */ | ||
330 | if (syscall) { | ||
331 | switch (regs->UCreg_00) { | ||
332 | case -ERESTART_RESTARTBLOCK: | ||
333 | case -ERESTARTNOHAND: | ||
334 | regs->UCreg_00 = -EINTR; | ||
335 | break; | ||
336 | case -ERESTARTSYS: | ||
337 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
338 | regs->UCreg_00 = -EINTR; | ||
339 | break; | ||
340 | } | ||
341 | /* fallthrough */ | ||
342 | case -ERESTARTNOINTR: | ||
343 | setup_syscall_restart(regs); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * translate the signal | ||
349 | */ | ||
350 | if (usig < 32 && thread->exec_domain | ||
351 | && thread->exec_domain->signal_invmap) | ||
352 | usig = thread->exec_domain->signal_invmap[usig]; | ||
353 | |||
354 | /* | ||
355 | * Set up the stack frame | ||
356 | */ | ||
357 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
358 | ret = setup_rt_frame(usig, ka, info, oldset, regs); | ||
359 | else | ||
360 | ret = setup_frame(usig, ka, oldset, regs); | ||
361 | |||
362 | /* | ||
363 | * Check that the resulting registers are actually sane. | ||
364 | */ | ||
365 | ret |= !valid_user_regs(regs); | ||
366 | |||
367 | if (ret != 0) { | ||
368 | force_sigsegv(sig, tsk); | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Block the signal if we were successful. | ||
374 | */ | ||
375 | spin_lock_irq(&tsk->sighand->siglock); | ||
376 | sigorsets(&tsk->blocked, &tsk->blocked, | ||
377 | &ka->sa.sa_mask); | ||
378 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
379 | sigaddset(&tsk->blocked, sig); | ||
380 | recalc_sigpending(); | ||
381 | spin_unlock_irq(&tsk->sighand->siglock); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
388 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
389 | * mistake. | ||
390 | * | ||
391 | * Note that we go through the signals twice: once to check the signals that | ||
392 | * the kernel can handle, and then we build all the user-level signal handling | ||
393 | * stack-frames in one go after that. | ||
394 | */ | ||
395 | static void do_signal(struct pt_regs *regs, int syscall) | ||
396 | { | ||
397 | struct k_sigaction ka; | ||
398 | siginfo_t info; | ||
399 | int signr; | ||
400 | |||
401 | /* | ||
402 | * We want the common case to go fast, which | ||
403 | * is why we may in certain cases get here from | ||
404 | * kernel mode. Just return without doing anything | ||
405 | * if so. | ||
406 | */ | ||
407 | if (!user_mode(regs)) | ||
408 | return; | ||
409 | |||
410 | if (try_to_freeze()) | ||
411 | goto no_signal; | ||
412 | |||
413 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
414 | if (signr > 0) { | ||
415 | sigset_t *oldset; | ||
416 | |||
417 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
418 | oldset = ¤t->saved_sigmask; | ||
419 | else | ||
420 | oldset = ¤t->blocked; | ||
421 | if (handle_signal(signr, &ka, &info, oldset, regs, syscall) | ||
422 | == 0) { | ||
423 | /* | ||
424 | * A signal was successfully delivered; the saved | ||
425 | * sigmask will have been stored in the signal frame, | ||
426 | * and will be restored by sigreturn, so we can simply | ||
427 | * clear the TIF_RESTORE_SIGMASK flag. | ||
428 | */ | ||
429 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
430 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
431 | } | ||
432 | return; | ||
433 | } | ||
434 | |||
435 | no_signal: | ||
436 | /* | ||
437 | * No signal to deliver to the process - restart the syscall. | ||
438 | */ | ||
439 | if (syscall) { | ||
440 | if (regs->UCreg_00 == -ERESTART_RESTARTBLOCK) { | ||
441 | u32 __user *usp; | ||
442 | |||
443 | regs->UCreg_sp -= 4; | ||
444 | usp = (u32 __user *)regs->UCreg_sp; | ||
445 | |||
446 | if (put_user(regs->UCreg_pc, usp) == 0) { | ||
447 | regs->UCreg_pc = KERN_RESTART_CODE; | ||
448 | } else { | ||
449 | regs->UCreg_sp += 4; | ||
450 | force_sigsegv(0, current); | ||
451 | } | ||
452 | } | ||
453 | if (regs->UCreg_00 == -ERESTARTNOHAND || | ||
454 | regs->UCreg_00 == -ERESTARTSYS || | ||
455 | regs->UCreg_00 == -ERESTARTNOINTR) { | ||
456 | setup_syscall_restart(regs); | ||
457 | } | ||
458 | |||
459 | /* If there's no signal to deliver, we just put the saved | ||
460 | * sigmask back. | ||
461 | */ | ||
462 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
463 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
464 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | asmlinkage void do_notify_resume(struct pt_regs *regs, | ||
470 | unsigned int thread_flags, int syscall) | ||
471 | { | ||
472 | if (thread_flags & _TIF_SIGPENDING) | ||
473 | do_signal(regs, syscall); | ||
474 | |||
475 | if (thread_flags & _TIF_NOTIFY_RESUME) { | ||
476 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
477 | tracehook_notify_resume(regs); | ||
478 | if (current->replacement_session_keyring) | ||
479 | key_replace_session_keyring(); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * Copy signal return handlers into the vector page, and | ||
485 | * set sigreturn to be a pointer to these. | ||
486 | */ | ||
487 | void __init early_signal_init(void) | ||
488 | { | ||
489 | memcpy((void *)kuser_vecpage_to_vectors(KERN_SIGRETURN_CODE), | ||
490 | sigreturn_codes, sizeof(sigreturn_codes)); | ||
491 | memcpy((void *)kuser_vecpage_to_vectors(KERN_RESTART_CODE), | ||
492 | syscall_restart_code, sizeof(syscall_restart_code)); | ||
493 | /* Need not to flush icache, since early_trap_init will do it last. */ | ||
494 | } | ||