diff options
Diffstat (limited to 'arch/hexagon/kernel/signal.c')
-rw-r--r-- | arch/hexagon/kernel/signal.c | 57 |
1 files changed, 20 insertions, 37 deletions
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index d7c73874b515..eadd70e47e7e 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c | |||
@@ -36,18 +36,10 @@ struct rt_sigframe { | |||
36 | struct ucontext uc; | 36 | struct ucontext uc; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 39 | static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, |
40 | size_t frame_size) | 40 | size_t frame_size) |
41 | { | 41 | { |
42 | unsigned long sp = regs->r29; | 42 | unsigned long sp = sigsp(regs->r29, ksig); |
43 | |||
44 | /* check if we would overflow the alt stack */ | ||
45 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) | ||
46 | return (void __user __force *)-1UL; | ||
47 | |||
48 | /* Switch to signal stack if appropriate */ | ||
49 | if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) | ||
50 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
51 | 43 | ||
52 | return (void __user *)((sp - frame_size) & ~(sizeof(long long) - 1)); | 44 | return (void __user *)((sp - frame_size) & ~(sizeof(long long) - 1)); |
53 | } | 45 | } |
@@ -112,20 +104,20 @@ static int restore_sigcontext(struct pt_regs *regs, | |||
112 | /* | 104 | /* |
113 | * Setup signal stack frame with siginfo structure | 105 | * Setup signal stack frame with siginfo structure |
114 | */ | 106 | */ |
115 | static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | 107 | static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, |
116 | sigset_t *set, struct pt_regs *regs) | 108 | struct pt_regs *regs) |
117 | { | 109 | { |
118 | int err = 0; | 110 | int err = 0; |
119 | struct rt_sigframe __user *frame; | 111 | struct rt_sigframe __user *frame; |
120 | struct hexagon_vdso *vdso = current->mm->context.vdso; | 112 | struct hexagon_vdso *vdso = current->mm->context.vdso; |
121 | 113 | ||
122 | frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe)); | 114 | frame = get_sigframe(ksig, regs, sizeof(struct rt_sigframe)); |
123 | 115 | ||
124 | if (!access_ok(VERIFY_WRITE, frame, sizeof(struct rt_sigframe))) | 116 | if (!access_ok(VERIFY_WRITE, frame, sizeof(struct rt_sigframe))) |
125 | goto sigsegv; | 117 | return -EFAULT; |
126 | 118 | ||
127 | if (copy_siginfo_to_user(&frame->info, info)) | 119 | if (copy_siginfo_to_user(&frame->info, &ksig->info)) |
128 | goto sigsegv; | 120 | return -EFAULT; |
129 | 121 | ||
130 | /* The on-stack signal trampoline is no longer executed; | 122 | /* The on-stack signal trampoline is no longer executed; |
131 | * however, the libgcc signal frame unwinding code checks for | 123 | * however, the libgcc signal frame unwinding code checks for |
@@ -137,29 +129,26 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
137 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 129 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
138 | err |= __save_altstack(&frame->uc.uc_stack, user_stack_pointer(regs)); | 130 | err |= __save_altstack(&frame->uc.uc_stack, user_stack_pointer(regs)); |
139 | if (err) | 131 | if (err) |
140 | goto sigsegv; | 132 | return -EFAULT; |
141 | 133 | ||
142 | /* Load r0/r1 pair with signumber/siginfo pointer... */ | 134 | /* Load r0/r1 pair with signumber/siginfo pointer... */ |
143 | regs->r0100 = ((unsigned long long)((unsigned long)&frame->info) << 32) | 135 | regs->r0100 = ((unsigned long long)((unsigned long)&frame->info) << 32) |
144 | | (unsigned long long)signr; | 136 | | (unsigned long long)ksig->sig; |
145 | regs->r02 = (unsigned long) &frame->uc; | 137 | regs->r02 = (unsigned long) &frame->uc; |
146 | regs->r31 = (unsigned long) vdso->rt_signal_trampoline; | 138 | regs->r31 = (unsigned long) vdso->rt_signal_trampoline; |
147 | pt_psp(regs) = (unsigned long) frame; | 139 | pt_psp(regs) = (unsigned long) frame; |
148 | pt_set_elr(regs, (unsigned long)ka->sa.sa_handler); | 140 | pt_set_elr(regs, (unsigned long)ksig->ka.sa.sa_handler); |
149 | 141 | ||
150 | return 0; | 142 | return 0; |
151 | |||
152 | sigsegv: | ||
153 | force_sigsegv(signr, current); | ||
154 | return -EFAULT; | ||
155 | } | 143 | } |
156 | 144 | ||
157 | /* | 145 | /* |
158 | * Setup invocation of signal handler | 146 | * Setup invocation of signal handler |
159 | */ | 147 | */ |
160 | static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, | 148 | static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
161 | struct pt_regs *regs) | ||
162 | { | 149 | { |
150 | int ret; | ||
151 | |||
163 | /* | 152 | /* |
164 | * If we're handling a signal that aborted a system call, | 153 | * If we're handling a signal that aborted a system call, |
165 | * set up the error return value before adding the signal | 154 | * set up the error return value before adding the signal |
@@ -173,7 +162,7 @@ static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, | |||
173 | regs->r00 = -EINTR; | 162 | regs->r00 = -EINTR; |
174 | break; | 163 | break; |
175 | case -ERESTARTSYS: | 164 | case -ERESTARTSYS: |
176 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 165 | if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { |
177 | regs->r00 = -EINTR; | 166 | regs->r00 = -EINTR; |
178 | break; | 167 | break; |
179 | } | 168 | } |
@@ -193,11 +182,9 @@ static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, | |||
193 | * only set up the rt_frame flavor. | 182 | * only set up the rt_frame flavor. |
194 | */ | 183 | */ |
195 | /* If there was an error on setup, no signal was delivered. */ | 184 | /* If there was an error on setup, no signal was delivered. */ |
196 | if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0) | 185 | ret = setup_rt_frame(ksig, sigmask_to_save(), regs); |
197 | return; | ||
198 | 186 | ||
199 | signal_delivered(sig, info, ka, regs, | 187 | signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); |
200 | test_thread_flag(TIF_SINGLESTEP)); | ||
201 | } | 188 | } |
202 | 189 | ||
203 | /* | 190 | /* |
@@ -205,17 +192,13 @@ static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, | |||
205 | */ | 192 | */ |
206 | void do_signal(struct pt_regs *regs) | 193 | void do_signal(struct pt_regs *regs) |
207 | { | 194 | { |
208 | struct k_sigaction sigact; | 195 | struct ksignal ksig; |
209 | siginfo_t info; | ||
210 | int signo; | ||
211 | 196 | ||
212 | if (!user_mode(regs)) | 197 | if (!user_mode(regs)) |
213 | return; | 198 | return; |
214 | 199 | ||
215 | signo = get_signal_to_deliver(&info, &sigact, regs, NULL); | 200 | if (get_signal(&ksig)) { |
216 | 201 | handle_signal(&ksig, regs); | |
217 | if (signo > 0) { | ||
218 | handle_signal(signo, &info, &sigact, regs); | ||
219 | return; | 202 | return; |
220 | } | 203 | } |
221 | 204 | ||