.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Signal handling for 32bit PPC and 32bit tasks on 64bit PPC |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * Derived from "arch/i386/kernel/signal.c" |
---|
11 | 12 | * Copyright (C) 1991, 1992 Linus Torvalds |
---|
12 | 13 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson |
---|
13 | | - * |
---|
14 | | - * This program is free software; you can redistribute it and/or |
---|
15 | | - * modify it under the terms of the GNU General Public License |
---|
16 | | - * as published by the Free Software Foundation; either version |
---|
17 | | - * 2 of the License, or (at your option) any later version. |
---|
18 | 14 | */ |
---|
19 | 15 | |
---|
20 | 16 | #include <linux/sched.h> |
---|
.. | .. |
---|
51 | 47 | #include <asm/unistd.h> |
---|
52 | 48 | #else |
---|
53 | 49 | #include <asm/ucontext.h> |
---|
54 | | -#include <asm/pgtable.h> |
---|
55 | 50 | #endif |
---|
56 | 51 | |
---|
57 | 52 | #include "signal.h" |
---|
.. | .. |
---|
107 | 102 | struct mcontext __user *frame) |
---|
108 | 103 | { |
---|
109 | 104 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; |
---|
110 | | - int i; |
---|
111 | | - /* Force usr to alway see softe as 1 (interrupts enabled) */ |
---|
112 | | - elf_greg_t64 softe = 0x1; |
---|
| 105 | + int val, i; |
---|
113 | 106 | |
---|
114 | 107 | WARN_ON(!FULL_REGS(regs)); |
---|
115 | 108 | |
---|
116 | 109 | for (i = 0; i <= PT_RESULT; i ++) { |
---|
117 | | - if (i == 14 && !FULL_REGS(regs)) |
---|
118 | | - i = 32; |
---|
119 | | - if ( i == PT_SOFTE) { |
---|
120 | | - if(__put_user((unsigned int)softe, &frame->mc_gregs[i])) |
---|
121 | | - return -EFAULT; |
---|
122 | | - else |
---|
123 | | - continue; |
---|
124 | | - } |
---|
125 | | - if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) |
---|
| 110 | + /* Force usr to alway see softe as 1 (interrupts enabled) */ |
---|
| 111 | + if (i == PT_SOFTE) |
---|
| 112 | + val = 1; |
---|
| 113 | + else |
---|
| 114 | + val = gregs[i]; |
---|
| 115 | + |
---|
| 116 | + if (__put_user(val, &frame->mc_gregs[i])) |
---|
126 | 117 | return -EFAULT; |
---|
127 | 118 | } |
---|
128 | 119 | return 0; |
---|
.. | .. |
---|
239 | 230 | int abigap[56]; |
---|
240 | 231 | }; |
---|
241 | 232 | |
---|
242 | | -#ifdef CONFIG_VSX |
---|
243 | | -unsigned long copy_fpr_to_user(void __user *to, |
---|
244 | | - struct task_struct *task) |
---|
245 | | -{ |
---|
246 | | - u64 buf[ELF_NFPREG]; |
---|
247 | | - int i; |
---|
248 | | - |
---|
249 | | - /* save FPR copy to local buffer then write to the thread_struct */ |
---|
250 | | - for (i = 0; i < (ELF_NFPREG - 1) ; i++) |
---|
251 | | - buf[i] = task->thread.TS_FPR(i); |
---|
252 | | - buf[i] = task->thread.fp_state.fpscr; |
---|
253 | | - return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double)); |
---|
254 | | -} |
---|
255 | | - |
---|
256 | | -unsigned long copy_fpr_from_user(struct task_struct *task, |
---|
257 | | - void __user *from) |
---|
258 | | -{ |
---|
259 | | - u64 buf[ELF_NFPREG]; |
---|
260 | | - int i; |
---|
261 | | - |
---|
262 | | - if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double))) |
---|
263 | | - return 1; |
---|
264 | | - for (i = 0; i < (ELF_NFPREG - 1) ; i++) |
---|
265 | | - task->thread.TS_FPR(i) = buf[i]; |
---|
266 | | - task->thread.fp_state.fpscr = buf[i]; |
---|
267 | | - |
---|
268 | | - return 0; |
---|
269 | | -} |
---|
270 | | - |
---|
271 | | -unsigned long copy_vsx_to_user(void __user *to, |
---|
272 | | - struct task_struct *task) |
---|
273 | | -{ |
---|
274 | | - u64 buf[ELF_NVSRHALFREG]; |
---|
275 | | - int i; |
---|
276 | | - |
---|
277 | | - /* save FPR copy to local buffer then write to the thread_struct */ |
---|
278 | | - for (i = 0; i < ELF_NVSRHALFREG; i++) |
---|
279 | | - buf[i] = task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; |
---|
280 | | - return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double)); |
---|
281 | | -} |
---|
282 | | - |
---|
283 | | -unsigned long copy_vsx_from_user(struct task_struct *task, |
---|
284 | | - void __user *from) |
---|
285 | | -{ |
---|
286 | | - u64 buf[ELF_NVSRHALFREG]; |
---|
287 | | - int i; |
---|
288 | | - |
---|
289 | | - if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double))) |
---|
290 | | - return 1; |
---|
291 | | - for (i = 0; i < ELF_NVSRHALFREG ; i++) |
---|
292 | | - task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; |
---|
293 | | - return 0; |
---|
294 | | -} |
---|
295 | | - |
---|
296 | | -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
---|
297 | | -unsigned long copy_ckfpr_to_user(void __user *to, |
---|
298 | | - struct task_struct *task) |
---|
299 | | -{ |
---|
300 | | - u64 buf[ELF_NFPREG]; |
---|
301 | | - int i; |
---|
302 | | - |
---|
303 | | - /* save FPR copy to local buffer then write to the thread_struct */ |
---|
304 | | - for (i = 0; i < (ELF_NFPREG - 1) ; i++) |
---|
305 | | - buf[i] = task->thread.TS_CKFPR(i); |
---|
306 | | - buf[i] = task->thread.ckfp_state.fpscr; |
---|
307 | | - return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double)); |
---|
308 | | -} |
---|
309 | | - |
---|
310 | | -unsigned long copy_ckfpr_from_user(struct task_struct *task, |
---|
311 | | - void __user *from) |
---|
312 | | -{ |
---|
313 | | - u64 buf[ELF_NFPREG]; |
---|
314 | | - int i; |
---|
315 | | - |
---|
316 | | - if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double))) |
---|
317 | | - return 1; |
---|
318 | | - for (i = 0; i < (ELF_NFPREG - 1) ; i++) |
---|
319 | | - task->thread.TS_CKFPR(i) = buf[i]; |
---|
320 | | - task->thread.ckfp_state.fpscr = buf[i]; |
---|
321 | | - |
---|
322 | | - return 0; |
---|
323 | | -} |
---|
324 | | - |
---|
325 | | -unsigned long copy_ckvsx_to_user(void __user *to, |
---|
326 | | - struct task_struct *task) |
---|
327 | | -{ |
---|
328 | | - u64 buf[ELF_NVSRHALFREG]; |
---|
329 | | - int i; |
---|
330 | | - |
---|
331 | | - /* save FPR copy to local buffer then write to the thread_struct */ |
---|
332 | | - for (i = 0; i < ELF_NVSRHALFREG; i++) |
---|
333 | | - buf[i] = task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET]; |
---|
334 | | - return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double)); |
---|
335 | | -} |
---|
336 | | - |
---|
337 | | -unsigned long copy_ckvsx_from_user(struct task_struct *task, |
---|
338 | | - void __user *from) |
---|
339 | | -{ |
---|
340 | | - u64 buf[ELF_NVSRHALFREG]; |
---|
341 | | - int i; |
---|
342 | | - |
---|
343 | | - if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double))) |
---|
344 | | - return 1; |
---|
345 | | - for (i = 0; i < ELF_NVSRHALFREG ; i++) |
---|
346 | | - task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; |
---|
347 | | - return 0; |
---|
348 | | -} |
---|
349 | | -#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ |
---|
350 | | -#else |
---|
351 | | -inline unsigned long copy_fpr_to_user(void __user *to, |
---|
352 | | - struct task_struct *task) |
---|
353 | | -{ |
---|
354 | | - return __copy_to_user(to, task->thread.fp_state.fpr, |
---|
355 | | - ELF_NFPREG * sizeof(double)); |
---|
356 | | -} |
---|
357 | | - |
---|
358 | | -inline unsigned long copy_fpr_from_user(struct task_struct *task, |
---|
359 | | - void __user *from) |
---|
360 | | -{ |
---|
361 | | - return __copy_from_user(task->thread.fp_state.fpr, from, |
---|
362 | | - ELF_NFPREG * sizeof(double)); |
---|
363 | | -} |
---|
364 | | - |
---|
365 | | -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
---|
366 | | -inline unsigned long copy_ckfpr_to_user(void __user *to, |
---|
367 | | - struct task_struct *task) |
---|
368 | | -{ |
---|
369 | | - return __copy_to_user(to, task->thread.ckfp_state.fpr, |
---|
370 | | - ELF_NFPREG * sizeof(double)); |
---|
371 | | -} |
---|
372 | | - |
---|
373 | | -inline unsigned long copy_ckfpr_from_user(struct task_struct *task, |
---|
374 | | - void __user *from) |
---|
375 | | -{ |
---|
376 | | - return __copy_from_user(task->thread.ckfp_state.fpr, from, |
---|
377 | | - ELF_NFPREG * sizeof(double)); |
---|
378 | | -} |
---|
379 | | -#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ |
---|
380 | | -#endif |
---|
381 | | - |
---|
382 | 233 | /* |
---|
383 | 234 | * Save the current user registers on the user stack. |
---|
384 | 235 | * We only save the altivec/spe registers if the process has used |
---|
.. | .. |
---|
470 | 321 | return 1; |
---|
471 | 322 | |
---|
472 | 323 | if (sigret) { |
---|
473 | | - /* Set up the sigreturn trampoline: li r0,sigret; sc */ |
---|
474 | | - if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) |
---|
475 | | - || __put_user(0x44000002UL, &frame->tramp[1])) |
---|
| 324 | + /* Set up the sigreturn trampoline: li 0,sigret; sc */ |
---|
| 325 | + if (__put_user(PPC_INST_ADDI + sigret, &frame->tramp[0]) |
---|
| 326 | + || __put_user(PPC_INST_SC, &frame->tramp[1])) |
---|
476 | 327 | return 1; |
---|
477 | 328 | flush_icache_range((unsigned long) &frame->tramp[0], |
---|
478 | 329 | (unsigned long) &frame->tramp[2]); |
---|
.. | .. |
---|
611 | 462 | if (__put_user(msr, &frame->mc_gregs[PT_MSR])) |
---|
612 | 463 | return 1; |
---|
613 | 464 | if (sigret) { |
---|
614 | | - /* Set up the sigreturn trampoline: li r0,sigret; sc */ |
---|
615 | | - if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) |
---|
616 | | - || __put_user(0x44000002UL, &frame->tramp[1])) |
---|
| 465 | + /* Set up the sigreturn trampoline: li 0,sigret; sc */ |
---|
| 466 | + if (__put_user(PPC_INST_ADDI + sigret, &frame->tramp[0]) |
---|
| 467 | + || __put_user(PPC_INST_SC, &frame->tramp[1])) |
---|
617 | 468 | return 1; |
---|
618 | 469 | flush_icache_range((unsigned long) &frame->tramp[0], |
---|
619 | 470 | (unsigned long) &frame->tramp[2]); |
---|
.. | .. |
---|
644 | 495 | if (!sig) |
---|
645 | 496 | save_r2 = (unsigned int)regs->gpr[2]; |
---|
646 | 497 | err = restore_general_regs(regs, sr); |
---|
647 | | - regs->trap = 0; |
---|
| 498 | + set_trap_norestart(regs); |
---|
648 | 499 | err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); |
---|
649 | 500 | if (!sig) |
---|
650 | 501 | regs->gpr[2] = (unsigned long) save_r2; |
---|
.. | .. |
---|
1013 | 864 | #else |
---|
1014 | 865 | if (__get_user(mcp, &ucp->uc_regs)) |
---|
1015 | 866 | return -EFAULT; |
---|
1016 | | - if (!access_ok(VERIFY_READ, mcp, sizeof(*mcp))) |
---|
| 867 | + if (!access_ok(mcp, sizeof(*mcp))) |
---|
1017 | 868 | return -EFAULT; |
---|
1018 | 869 | #endif |
---|
1019 | 870 | set_current_blocked(&set); |
---|
.. | .. |
---|
1116 | 967 | */ |
---|
1117 | 968 | mctx = (struct mcontext __user *) |
---|
1118 | 969 | ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL); |
---|
1119 | | - if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) |
---|
| 970 | + if (!access_ok(old_ctx, ctx_size) |
---|
1120 | 971 | || save_user_regs(regs, mctx, NULL, 0, ctx_has_vsx_region) |
---|
1121 | 972 | || put_sigset_t(&old_ctx->uc_sigmask, ¤t->blocked) |
---|
1122 | 973 | || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs)) |
---|
.. | .. |
---|
1124 | 975 | } |
---|
1125 | 976 | if (new_ctx == NULL) |
---|
1126 | 977 | return 0; |
---|
1127 | | - if (!access_ok(VERIFY_READ, new_ctx, ctx_size) || |
---|
| 978 | + if (!access_ok(new_ctx, ctx_size) || |
---|
1128 | 979 | fault_in_pages_readable((u8 __user *)new_ctx, ctx_size)) |
---|
1129 | 980 | return -EFAULT; |
---|
1130 | 981 | |
---|
.. | .. |
---|
1154 | 1005 | { |
---|
1155 | 1006 | struct rt_sigframe __user *rt_sf; |
---|
1156 | 1007 | struct pt_regs *regs = current_pt_regs(); |
---|
| 1008 | + int tm_restore = 0; |
---|
1157 | 1009 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
---|
1158 | 1010 | struct ucontext __user *uc_transact; |
---|
1159 | 1011 | unsigned long msr_hi; |
---|
1160 | 1012 | unsigned long tmp; |
---|
1161 | | - int tm_restore = 0; |
---|
1162 | 1013 | #endif |
---|
1163 | 1014 | /* Always make any pending restarted system calls return -EINTR */ |
---|
1164 | 1015 | current->restart_block.fn = do_no_restart_syscall; |
---|
1165 | 1016 | |
---|
1166 | 1017 | rt_sf = (struct rt_sigframe __user *) |
---|
1167 | 1018 | (regs->gpr[1] + __SIGNAL_FRAMESIZE + 16); |
---|
1168 | | - if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf))) |
---|
| 1019 | + if (!access_ok(rt_sf, sizeof(*rt_sf))) |
---|
1169 | 1020 | goto bad; |
---|
1170 | 1021 | |
---|
1171 | 1022 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
---|
.. | .. |
---|
1209 | 1060 | goto bad; |
---|
1210 | 1061 | } |
---|
1211 | 1062 | } |
---|
1212 | | - if (!tm_restore) |
---|
1213 | | - /* Fall through, for non-TM restore */ |
---|
| 1063 | + if (!tm_restore) { |
---|
| 1064 | + /* |
---|
| 1065 | + * Unset regs->msr because ucontext MSR TS is not |
---|
| 1066 | + * set, and recheckpoint was not called. This avoid |
---|
| 1067 | + * hitting a TM Bad thing at RFID |
---|
| 1068 | + */ |
---|
| 1069 | + regs->msr &= ~MSR_TS_MASK; |
---|
| 1070 | + } |
---|
| 1071 | + /* Fall through, for non-TM restore */ |
---|
1214 | 1072 | #endif |
---|
1215 | | - if (do_setcontext(&rt_sf->uc, regs, 1)) |
---|
1216 | | - goto bad; |
---|
| 1073 | + if (!tm_restore) |
---|
| 1074 | + if (do_setcontext(&rt_sf->uc, regs, 1)) |
---|
| 1075 | + goto bad; |
---|
1217 | 1076 | |
---|
1218 | 1077 | /* |
---|
1219 | 1078 | * It's not clear whether or why it is desirable to save the |
---|
.. | .. |
---|
1240 | 1099 | current->comm, current->pid, |
---|
1241 | 1100 | rt_sf, regs->nip, regs->link); |
---|
1242 | 1101 | |
---|
1243 | | - force_sig(SIGSEGV, current); |
---|
| 1102 | + force_sig(SIGSEGV); |
---|
1244 | 1103 | return 0; |
---|
1245 | 1104 | } |
---|
1246 | 1105 | |
---|
.. | .. |
---|
1306 | 1165 | current->thread.debug.dbcr0 = new_dbcr0; |
---|
1307 | 1166 | #endif |
---|
1308 | 1167 | |
---|
1309 | | - if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx)) || |
---|
| 1168 | + if (!access_ok(ctx, sizeof(*ctx)) || |
---|
1310 | 1169 | fault_in_pages_readable((u8 __user *)ctx, sizeof(*ctx))) |
---|
1311 | 1170 | return -EFAULT; |
---|
1312 | 1171 | |
---|
.. | .. |
---|
1329 | 1188 | current->comm, current->pid, |
---|
1330 | 1189 | ctx, regs->nip, regs->link); |
---|
1331 | 1190 | |
---|
1332 | | - force_sig(SIGSEGV, current); |
---|
| 1191 | + force_sig(SIGSEGV); |
---|
1333 | 1192 | goto out; |
---|
1334 | 1193 | } |
---|
1335 | 1194 | |
---|
.. | .. |
---|
1495 | 1354 | { |
---|
1496 | 1355 | sr = (struct mcontext __user *)from_user_ptr(sigctx.regs); |
---|
1497 | 1356 | addr = sr; |
---|
1498 | | - if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) |
---|
| 1357 | + if (!access_ok(sr, sizeof(*sr)) |
---|
1499 | 1358 | || restore_user_regs(regs, sr, 1)) |
---|
1500 | 1359 | goto badframe; |
---|
1501 | 1360 | } |
---|
.. | .. |
---|
1511 | 1370 | current->comm, current->pid, |
---|
1512 | 1371 | addr, regs->nip, regs->link); |
---|
1513 | 1372 | |
---|
1514 | | - force_sig(SIGSEGV, current); |
---|
| 1373 | + force_sig(SIGSEGV); |
---|
1515 | 1374 | return 0; |
---|
1516 | 1375 | } |
---|