]>
Commit | Line | Data |
---|---|---|
883251dd YS |
1 | /* |
2 | * linux/arch/h8300/kernel/signal.c | |
3 | * | |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file COPYING in the main directory of this archive | |
8 | * for more details. | |
9 | */ | |
10 | ||
11 | /* | |
12 | * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp> | |
13 | * and David McCullough <davidm@snapgear.com> | |
14 | * | |
15 | * Based on | |
16 | * Linux/m68k by Hamish Macdonald | |
17 | */ | |
18 | ||
19 | /* | |
20 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | |
21 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | |
22 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | |
23 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | |
24 | * signal handlers! | |
25 | */ | |
26 | ||
27 | #include <linux/sched.h> | |
28 | #include <linux/mm.h> | |
29 | #include <linux/kernel.h> | |
30 | #include <linux/signal.h> | |
31 | #include <linux/syscalls.h> | |
32 | #include <linux/errno.h> | |
33 | #include <linux/wait.h> | |
34 | #include <linux/ptrace.h> | |
35 | #include <linux/unistd.h> | |
36 | #include <linux/stddef.h> | |
37 | #include <linux/highuid.h> | |
38 | #include <linux/personality.h> | |
39 | #include <linux/tty.h> | |
40 | #include <linux/binfmts.h> | |
41 | #include <linux/tracehook.h> | |
42 | ||
43 | #include <asm/setup.h> | |
44 | #include <asm/uaccess.h> | |
45 | #include <asm/pgtable.h> | |
46 | #include <asm/traps.h> | |
47 | #include <asm/ucontext.h> | |
48 | ||
49 | /* | |
50 | * Do a signal return; undo the signal stack. | |
51 | * | |
52 | * Keep the return code on the stack quadword aligned! | |
53 | * That makes the cache flush below easier. | |
54 | */ | |
55 | ||
56 | struct rt_sigframe { | |
57 | long dummy_er0; | |
58 | long dummy_vector; | |
59 | #if defined(CONFIG_CPU_H8S) | |
60 | short dummy_exr; | |
61 | #endif | |
62 | long dummy_pc; | |
63 | char *pretcode; | |
64 | struct siginfo *pinfo; | |
65 | void *puc; | |
66 | unsigned char retcode[8]; | |
67 | struct siginfo info; | |
68 | struct ucontext uc; | |
69 | int sig; | |
70 | } __packed __aligned(2); | |
71 | ||
72 | static inline int | |
73 | restore_sigcontext(struct sigcontext *usc, int *pd0) | |
74 | { | |
75 | struct pt_regs *regs = current_pt_regs(); | |
76 | int err = 0; | |
77 | unsigned int ccr; | |
78 | unsigned int usp; | |
79 | unsigned int er0; | |
80 | ||
81 | /* Always make any pending restarted system calls return -EINTR */ | |
21753583 | 82 | current->restart_block.fn = do_no_restart_syscall; |
883251dd YS |
83 | |
84 | /* restore passed registers */ | |
85 | #define COPY(r) do { err |= get_user(regs->r, &usc->sc_##r); } while (0) | |
86 | COPY(er1); | |
87 | COPY(er2); | |
88 | COPY(er3); | |
89 | COPY(er5); | |
90 | COPY(pc); | |
91 | ccr = regs->ccr & 0x10; | |
92 | COPY(ccr); | |
93 | #undef COPY | |
94 | regs->ccr &= 0xef; | |
95 | regs->ccr |= ccr; | |
96 | regs->orig_er0 = -1; /* disable syscall checks */ | |
97 | err |= __get_user(usp, &usc->sc_usp); | |
9ee05bb6 | 98 | regs->sp = usp; |
883251dd YS |
99 | |
100 | err |= __get_user(er0, &usc->sc_er0); | |
101 | *pd0 = er0; | |
102 | return err; | |
103 | } | |
104 | ||
105 | asmlinkage int sys_rt_sigreturn(void) | |
106 | { | |
107 | unsigned long usp = rdusp(); | |
108 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | |
109 | sigset_t set; | |
110 | int er0; | |
111 | ||
112 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | |
113 | goto badframe; | |
114 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | |
115 | goto badframe; | |
116 | ||
117 | set_current_blocked(&set); | |
118 | ||
119 | if (restore_sigcontext(&frame->uc.uc_mcontext, &er0)) | |
120 | goto badframe; | |
121 | ||
122 | if (restore_altstack(&frame->uc.uc_stack)) | |
123 | goto badframe; | |
124 | ||
125 | return er0; | |
126 | ||
127 | badframe: | |
128 | force_sig(SIGSEGV, current); | |
129 | return 0; | |
130 | } | |
131 | ||
132 | static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |
133 | unsigned long mask) | |
134 | { | |
135 | int err = 0; | |
136 | ||
137 | err |= __put_user(regs->er0, &sc->sc_er0); | |
138 | err |= __put_user(regs->er1, &sc->sc_er1); | |
139 | err |= __put_user(regs->er2, &sc->sc_er2); | |
140 | err |= __put_user(regs->er3, &sc->sc_er3); | |
141 | err |= __put_user(regs->er4, &sc->sc_er4); | |
142 | err |= __put_user(regs->er5, &sc->sc_er5); | |
143 | err |= __put_user(regs->er6, &sc->sc_er6); | |
144 | err |= __put_user(rdusp(), &sc->sc_usp); | |
145 | err |= __put_user(regs->pc, &sc->sc_pc); | |
146 | err |= __put_user(regs->ccr, &sc->sc_ccr); | |
147 | err |= __put_user(mask, &sc->sc_mask); | |
148 | ||
149 | return err; | |
150 | } | |
151 | ||
152 | static inline void __user * | |
153 | get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size) | |
154 | { | |
155 | return (void __user *)((sigsp(rdusp(), ksig) - frame_size) & -8UL); | |
156 | } | |
157 | ||
158 | static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, | |
159 | struct pt_regs *regs) | |
160 | { | |
161 | struct rt_sigframe *frame; | |
162 | int err = 0; | |
163 | unsigned char *ret; | |
164 | ||
165 | frame = get_sigframe(ksig, regs, sizeof(*frame)); | |
166 | ||
167 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
168 | return -EFAULT; | |
169 | ||
170 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) | |
171 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); | |
172 | ||
173 | /* Create the ucontext. */ | |
174 | err |= __put_user(0, &frame->uc.uc_flags); | |
175 | err |= __put_user(0, &frame->uc.uc_link); | |
176 | err |= __save_altstack(&frame->uc.uc_stack, rdusp()); | |
177 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | |
178 | err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
179 | if (err) | |
180 | return -EFAULT; | |
181 | ||
182 | /* Set up to return from userspace. */ | |
9ee05bb6 | 183 | ret = (unsigned char *)&frame->retcode; |
883251dd YS |
184 | if (ksig->ka.sa.sa_flags & SA_RESTORER) |
185 | ret = (unsigned char *)(ksig->ka.sa.sa_restorer); | |
186 | else { | |
187 | /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */ | |
188 | err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff), | |
189 | (unsigned long *)(frame->retcode + 0)); | |
190 | err |= __put_user(0x5700, | |
191 | (unsigned short *)(frame->retcode + 4)); | |
192 | } | |
193 | err |= __put_user(ret, &frame->pretcode); | |
194 | ||
195 | if (err) | |
196 | return -EFAULT; | |
197 | ||
198 | /* Set up registers for signal handler */ | |
9ee05bb6 YS |
199 | regs->sp = (unsigned long)frame; |
200 | regs->pc = (unsigned long)ksig->ka.sa.sa_handler; | |
883251dd YS |
201 | regs->er0 = ksig->sig; |
202 | regs->er1 = (unsigned long)&(frame->info); | |
203 | regs->er2 = (unsigned long)&frame->uc; | |
204 | regs->er5 = current->mm->start_data; /* GOT base */ | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
209 | static void | |
210 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka) | |
211 | { | |
212 | switch (regs->er0) { | |
213 | case -ERESTARTNOHAND: | |
214 | if (!ka) | |
215 | goto do_restart; | |
216 | regs->er0 = -EINTR; | |
217 | break; | |
218 | case -ERESTART_RESTARTBLOCK: | |
219 | if (!ka) { | |
220 | regs->er0 = __NR_restart_syscall; | |
221 | regs->pc -= 2; | |
222 | } else | |
223 | regs->er0 = -EINTR; | |
224 | break; | |
225 | case -ERESTARTSYS: | |
226 | if (!(ka->sa.sa_flags & SA_RESTART)) { | |
227 | regs->er0 = -EINTR; | |
228 | break; | |
229 | } | |
230 | /* fallthrough */ | |
231 | case -ERESTARTNOINTR: | |
232 | do_restart: | |
233 | regs->er0 = regs->orig_er0; | |
234 | regs->pc -= 2; | |
235 | break; | |
236 | } | |
237 | } | |
238 | ||
239 | /* | |
240 | * OK, we're invoking a handler | |
241 | */ | |
242 | static void | |
243 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) | |
244 | { | |
245 | sigset_t *oldset = sigmask_to_save(); | |
246 | int ret; | |
247 | /* are we from a system call? */ | |
248 | if (regs->orig_er0 >= 0) | |
249 | handle_restart(regs, &ksig->ka); | |
250 | ||
251 | ret = setup_rt_frame(ksig, oldset, regs); | |
252 | ||
253 | signal_setup_done(ret, ksig, 0); | |
254 | } | |
255 | ||
256 | /* | |
257 | * Note that 'init' is a special process: it doesn't get signals it doesn't | |
258 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | |
259 | * mistake. | |
260 | */ | |
261 | static void do_signal(struct pt_regs *regs) | |
262 | { | |
263 | struct ksignal ksig; | |
264 | ||
265 | current->thread.esp0 = (unsigned long) regs; | |
266 | ||
267 | if (get_signal(&ksig)) { | |
268 | /* Whee! Actually deliver the signal. */ | |
269 | handle_signal(&ksig, regs); | |
270 | return; | |
271 | } | |
272 | /* Did we come from a system call? */ | |
273 | if (regs->orig_er0 >= 0) | |
274 | handle_restart(regs, NULL); | |
275 | ||
276 | /* If there's no signal to deliver, we just restore the saved mask. */ | |
277 | restore_saved_sigmask(); | |
278 | } | |
279 | ||
280 | asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | |
281 | { | |
282 | if (thread_info_flags & _TIF_SIGPENDING) | |
283 | do_signal(regs); | |
284 | ||
285 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | |
286 | clear_thread_flag(TIF_NOTIFY_RESUME); | |
287 | tracehook_notify_resume(regs); | |
288 | } | |
289 | } |