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