diff options
Diffstat (limited to 'arch/arm64/kernel/signal.c')
-rw-r--r-- | arch/arm64/kernel/signal.c | 49 |
1 files changed, 22 insertions, 27 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 8807ba2cf262..abd756315cb5 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c | |||
@@ -41,6 +41,8 @@ | |||
41 | struct rt_sigframe { | 41 | struct rt_sigframe { |
42 | struct siginfo info; | 42 | struct siginfo info; |
43 | struct ucontext uc; | 43 | struct ucontext uc; |
44 | u64 fp; | ||
45 | u64 lr; | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) | 48 | static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) |
@@ -175,6 +177,10 @@ static int setup_sigframe(struct rt_sigframe __user *sf, | |||
175 | struct aux_context __user *aux = | 177 | struct aux_context __user *aux = |
176 | (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; | 178 | (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; |
177 | 179 | ||
180 | /* set up the stack frame for unwinding */ | ||
181 | __put_user_error(regs->regs[29], &sf->fp, err); | ||
182 | __put_user_error(regs->regs[30], &sf->lr, err); | ||
183 | |||
178 | for (i = 0; i < 31; i++) | 184 | for (i = 0; i < 31; i++) |
179 | __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], | 185 | __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], |
180 | err); | 186 | err); |
@@ -196,11 +202,11 @@ static int setup_sigframe(struct rt_sigframe __user *sf, | |||
196 | return err; | 202 | return err; |
197 | } | 203 | } |
198 | 204 | ||
199 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 205 | static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka, |
200 | int framesize) | 206 | struct pt_regs *regs) |
201 | { | 207 | { |
202 | unsigned long sp, sp_top; | 208 | unsigned long sp, sp_top; |
203 | void __user *frame; | 209 | struct rt_sigframe __user *frame; |
204 | 210 | ||
205 | sp = sp_top = regs->sp; | 211 | sp = sp_top = regs->sp; |
206 | 212 | ||
@@ -210,11 +216,8 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
210 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | 216 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) |
211 | sp = sp_top = current->sas_ss_sp + current->sas_ss_size; | 217 | sp = sp_top = current->sas_ss_sp + current->sas_ss_size; |
212 | 218 | ||
213 | /* room for stack frame (FP, LR) */ | 219 | sp = (sp - sizeof(struct rt_sigframe)) & ~15; |
214 | sp -= 16; | 220 | frame = (struct rt_sigframe __user *)sp; |
215 | |||
216 | sp = (sp - framesize) & ~15; | ||
217 | frame = (void __user *)sp; | ||
218 | 221 | ||
219 | /* | 222 | /* |
220 | * Check that we can actually write to the signal frame. | 223 | * Check that we can actually write to the signal frame. |
@@ -225,20 +228,14 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
225 | return frame; | 228 | return frame; |
226 | } | 229 | } |
227 | 230 | ||
228 | static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, | 231 | static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, |
229 | void __user *frame, int usig) | 232 | void __user *frame, int usig) |
230 | { | 233 | { |
231 | int err = 0; | ||
232 | __sigrestore_t sigtramp; | 234 | __sigrestore_t sigtramp; |
233 | unsigned long __user *sp = (unsigned long __user *)regs->sp; | ||
234 | |||
235 | /* set up the stack frame */ | ||
236 | __put_user_error(regs->regs[29], sp - 2, err); | ||
237 | __put_user_error(regs->regs[30], sp - 1, err); | ||
238 | 235 | ||
239 | regs->regs[0] = usig; | 236 | regs->regs[0] = usig; |
240 | regs->regs[29] = regs->sp - 16; | ||
241 | regs->sp = (unsigned long)frame; | 237 | regs->sp = (unsigned long)frame; |
238 | regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp); | ||
242 | regs->pc = (unsigned long)ka->sa.sa_handler; | 239 | regs->pc = (unsigned long)ka->sa.sa_handler; |
243 | 240 | ||
244 | if (ka->sa.sa_flags & SA_RESTORER) | 241 | if (ka->sa.sa_flags & SA_RESTORER) |
@@ -247,8 +244,6 @@ static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
247 | sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); | 244 | sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); |
248 | 245 | ||
249 | regs->regs[30] = (unsigned long)sigtramp; | 246 | regs->regs[30] = (unsigned long)sigtramp; |
250 | |||
251 | return err; | ||
252 | } | 247 | } |
253 | 248 | ||
254 | static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | 249 | static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, |
@@ -258,7 +253,7 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | |||
258 | stack_t stack; | 253 | stack_t stack; |
259 | int err = 0; | 254 | int err = 0; |
260 | 255 | ||
261 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 256 | frame = get_sigframe(ka, regs); |
262 | if (!frame) | 257 | if (!frame) |
263 | return 1; | 258 | return 1; |
264 | 259 | ||
@@ -272,13 +267,13 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | |||
272 | err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); | 267 | err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); |
273 | 268 | ||
274 | err |= setup_sigframe(frame, regs, set); | 269 | err |= setup_sigframe(frame, regs, set); |
275 | if (err == 0) | 270 | if (err == 0) { |
276 | err = setup_return(regs, ka, frame, usig); | 271 | setup_return(regs, ka, frame, usig); |
277 | 272 | if (ka->sa.sa_flags & SA_SIGINFO) { | |
278 | if (err == 0 && ka->sa.sa_flags & SA_SIGINFO) { | 273 | err |= copy_siginfo_to_user(&frame->info, info); |
279 | err |= copy_siginfo_to_user(&frame->info, info); | 274 | regs->regs[1] = (unsigned long)&frame->info; |
280 | regs->regs[1] = (unsigned long)&frame->info; | 275 | regs->regs[2] = (unsigned long)&frame->uc; |
281 | regs->regs[2] = (unsigned long)&frame->uc; | 276 | } |
282 | } | 277 | } |
283 | 278 | ||
284 | return err; | 279 | return err; |