1 | /* SPDX-License-Identifier: GPL-2.0-or-later |
2 | * |
3 | * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Corporation |
4 | * Extracted from signal_32.c and signal_64.c |
5 | */ |
6 | |
7 | #ifndef _POWERPC_ARCH_SIGNAL_H |
8 | #define _POWERPC_ARCH_SIGNAL_H |
9 | |
10 | void __user *get_sigframe(struct ksignal *ksig, struct task_struct *tsk, |
11 | size_t frame_size, int is_32); |
12 | |
13 | extern int handle_signal32(struct ksignal *ksig, sigset_t *oldset, |
14 | struct task_struct *tsk); |
15 | |
16 | extern int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, |
17 | struct task_struct *tsk); |
18 | |
19 | static inline int __get_user_sigset(sigset_t *dst, const sigset_t __user *src) |
20 | { |
21 | BUILD_BUG_ON(sizeof(sigset_t) != sizeof(u64)); |
22 | |
23 | return __get_user(dst->sig[0], (u64 __user *)&src->sig[0]); |
24 | } |
25 | #define unsafe_get_user_sigset(dst, src, label) do { \ |
26 | sigset_t *__dst = dst; \ |
27 | const sigset_t __user *__src = src; \ |
28 | int i; \ |
29 | \ |
30 | for (i = 0; i < _NSIG_WORDS; i++) \ |
31 | unsafe_get_user(__dst->sig[i], &__src->sig[i], label); \ |
32 | } while (0) |
33 | |
34 | #ifdef CONFIG_VSX |
35 | extern unsigned long copy_vsx_to_user(void __user *to, |
36 | struct task_struct *task); |
37 | extern unsigned long copy_ckvsx_to_user(void __user *to, |
38 | struct task_struct *task); |
39 | extern unsigned long copy_vsx_from_user(struct task_struct *task, |
40 | void __user *from); |
41 | extern unsigned long copy_ckvsx_from_user(struct task_struct *task, |
42 | void __user *from); |
43 | unsigned long copy_fpr_to_user(void __user *to, struct task_struct *task); |
44 | unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task); |
45 | unsigned long copy_fpr_from_user(struct task_struct *task, void __user *from); |
46 | unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from); |
47 | |
48 | #define unsafe_copy_fpr_to_user(to, task, label) do { \ |
49 | struct task_struct *__t = task; \ |
50 | u64 __user *buf = (u64 __user *)to; \ |
51 | int i; \ |
52 | \ |
53 | for (i = 0; i < ELF_NFPREG - 1 ; i++) \ |
54 | unsafe_put_user(__t->thread.TS_FPR(i), &buf[i], label); \ |
55 | unsafe_put_user(__t->thread.fp_state.fpscr, &buf[i], label); \ |
56 | } while (0) |
57 | |
58 | #define unsafe_copy_vsx_to_user(to, task, label) do { \ |
59 | struct task_struct *__t = task; \ |
60 | u64 __user *buf = (u64 __user *)to; \ |
61 | int i; \ |
62 | \ |
63 | for (i = 0; i < ELF_NVSRHALFREG ; i++) \ |
64 | unsafe_put_user(__t->thread.fp_state.fpr[i][TS_VSRLOWOFFSET], \ |
65 | &buf[i], label);\ |
66 | } while (0) |
67 | |
68 | #define unsafe_copy_fpr_from_user(task, from, label) do { \ |
69 | struct task_struct *__t = task; \ |
70 | u64 __user *buf = (u64 __user *)from; \ |
71 | int i; \ |
72 | \ |
73 | for (i = 0; i < ELF_NFPREG - 1; i++) \ |
74 | unsafe_get_user(__t->thread.TS_FPR(i), &buf[i], label); \ |
75 | unsafe_get_user(__t->thread.fp_state.fpscr, &buf[i], label); \ |
76 | } while (0) |
77 | |
78 | #define unsafe_copy_vsx_from_user(task, from, label) do { \ |
79 | struct task_struct *__t = task; \ |
80 | u64 __user *buf = (u64 __user *)from; \ |
81 | int i; \ |
82 | \ |
83 | for (i = 0; i < ELF_NVSRHALFREG ; i++) \ |
84 | unsafe_get_user(__t->thread.fp_state.fpr[i][TS_VSRLOWOFFSET], \ |
85 | &buf[i], label); \ |
86 | } while (0) |
87 | |
88 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
89 | #define unsafe_copy_ckfpr_to_user(to, task, label) do { \ |
90 | struct task_struct *__t = task; \ |
91 | u64 __user *buf = (u64 __user *)to; \ |
92 | int i; \ |
93 | \ |
94 | for (i = 0; i < ELF_NFPREG - 1 ; i++) \ |
95 | unsafe_put_user(__t->thread.TS_CKFPR(i), &buf[i], label);\ |
96 | unsafe_put_user(__t->thread.ckfp_state.fpscr, &buf[i], label); \ |
97 | } while (0) |
98 | |
99 | #define unsafe_copy_ckvsx_to_user(to, task, label) do { \ |
100 | struct task_struct *__t = task; \ |
101 | u64 __user *buf = (u64 __user *)to; \ |
102 | int i; \ |
103 | \ |
104 | for (i = 0; i < ELF_NVSRHALFREG ; i++) \ |
105 | unsafe_put_user(__t->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET], \ |
106 | &buf[i], label);\ |
107 | } while (0) |
108 | |
109 | #define unsafe_copy_ckfpr_from_user(task, from, label) do { \ |
110 | struct task_struct *__t = task; \ |
111 | u64 __user *buf = (u64 __user *)from; \ |
112 | int i; \ |
113 | \ |
114 | for (i = 0; i < ELF_NFPREG - 1 ; i++) \ |
115 | unsafe_get_user(__t->thread.TS_CKFPR(i), &buf[i], label);\ |
116 | unsafe_get_user(__t->thread.ckfp_state.fpscr, &buf[i], failed); \ |
117 | } while (0) |
118 | |
119 | #define unsafe_copy_ckvsx_from_user(task, from, label) do { \ |
120 | struct task_struct *__t = task; \ |
121 | u64 __user *buf = (u64 __user *)from; \ |
122 | int i; \ |
123 | \ |
124 | for (i = 0; i < ELF_NVSRHALFREG ; i++) \ |
125 | unsafe_get_user(__t->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET], \ |
126 | &buf[i], label); \ |
127 | } while (0) |
128 | #endif |
129 | #elif defined(CONFIG_PPC_FPU_REGS) |
130 | |
131 | #define unsafe_copy_fpr_to_user(to, task, label) \ |
132 | unsafe_copy_to_user(to, (task)->thread.fp_state.fpr, \ |
133 | ELF_NFPREG * sizeof(double), label) |
134 | |
135 | #define unsafe_copy_fpr_from_user(task, from, label) \ |
136 | unsafe_copy_from_user((task)->thread.fp_state.fpr, from, \ |
137 | ELF_NFPREG * sizeof(double), label) |
138 | |
139 | static inline unsigned long |
140 | copy_fpr_to_user(void __user *to, struct task_struct *task) |
141 | { |
142 | return __copy_to_user(to, task->thread.fp_state.fpr, |
143 | ELF_NFPREG * sizeof(double)); |
144 | } |
145 | |
146 | static inline unsigned long |
147 | copy_fpr_from_user(struct task_struct *task, void __user *from) |
148 | { |
149 | return __copy_from_user(task->thread.fp_state.fpr, from, |
150 | ELF_NFPREG * sizeof(double)); |
151 | } |
152 | |
153 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
154 | #define unsafe_copy_ckfpr_to_user(to, task, label) \ |
155 | unsafe_copy_to_user(to, (task)->thread.ckfp_state.fpr, \ |
156 | ELF_NFPREG * sizeof(double), label) |
157 | |
158 | inline unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task) |
159 | { |
160 | return __copy_to_user(to, task->thread.ckfp_state.fpr, |
161 | ELF_NFPREG * sizeof(double)); |
162 | } |
163 | |
164 | static inline unsigned long |
165 | copy_ckfpr_from_user(struct task_struct *task, void __user *from) |
166 | { |
167 | return __copy_from_user(task->thread.ckfp_state.fpr, from, |
168 | ELF_NFPREG * sizeof(double)); |
169 | } |
170 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ |
171 | #else |
172 | #define unsafe_copy_fpr_to_user(to, task, label) do { if (0) goto label;} while (0) |
173 | |
174 | #define unsafe_copy_fpr_from_user(task, from, label) do { if (0) goto label;} while (0) |
175 | |
176 | static inline unsigned long |
177 | copy_fpr_to_user(void __user *to, struct task_struct *task) |
178 | { |
179 | return 0; |
180 | } |
181 | |
182 | static inline unsigned long |
183 | copy_fpr_from_user(struct task_struct *task, void __user *from) |
184 | { |
185 | return 0; |
186 | } |
187 | #endif |
188 | |
189 | #ifdef CONFIG_PPC64 |
190 | |
191 | extern int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, |
192 | struct task_struct *tsk); |
193 | |
194 | #else /* CONFIG_PPC64 */ |
195 | |
196 | static inline int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, |
197 | struct task_struct *tsk) |
198 | { |
199 | return -EFAULT; |
200 | } |
201 | |
202 | #endif /* !defined(CONFIG_PPC64) */ |
203 | |
204 | void signal_fault(struct task_struct *tsk, struct pt_regs *regs, |
205 | const char *where, void __user *ptr); |
206 | |
207 | #endif /* _POWERPC_ARCH_SIGNAL_H */ |
208 | |