]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/metag/kernel/ptrace.c
cpufreq: intel_pstate: Add support for Gemini Lake
[karo-tx-linux.git] / arch / metag / kernel / ptrace.c
1 /*
2  *  Copyright (C) 2005-2012 Imagination Technologies Ltd.
3  *
4  * This file is subject to the terms and conditions of the GNU General
5  * Public License.  See the file COPYING in the main directory of
6  * this archive for more details.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/errno.h>
12 #include <linux/ptrace.h>
13 #include <linux/user.h>
14 #include <linux/regset.h>
15 #include <linux/tracehook.h>
16 #include <linux/elf.h>
17 #include <linux/uaccess.h>
18 #include <linux/sched/task_stack.h>
19
20 #include <trace/syscall.h>
21
22 #define CREATE_TRACE_POINTS
23 #include <trace/events/syscalls.h>
24
25 /*
26  * user_regset definitions.
27  */
28
29 int metag_gp_regs_copyout(const struct pt_regs *regs,
30                           unsigned int pos, unsigned int count,
31                           void *kbuf, void __user *ubuf)
32 {
33         const void *ptr;
34         unsigned long data;
35         int ret;
36
37         /* D{0-1}.{0-7} */
38         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
39                                   regs->ctx.DX, 0, 4*16);
40         if (ret)
41                 goto out;
42         /* A{0-1}.{0-1} */
43         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
44                                   regs->ctx.AX, 4*16, 4*20);
45         if (ret)
46                 goto out;
47         /* A{0-1}.2 */
48         if (regs->ctx.SaveMask & TBICTX_XEXT_BIT)
49                 ptr = regs->ctx.Ext.Ctx.pExt;
50         else
51                 ptr = &regs->ctx.Ext.AX2;
52         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
53                                   ptr, 4*20, 4*22);
54         if (ret)
55                 goto out;
56         /* A{0-1}.3 */
57         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
58                                   &regs->ctx.AX3, 4*22, 4*24);
59         if (ret)
60                 goto out;
61         /* PC */
62         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
63                                   &regs->ctx.CurrPC, 4*24, 4*25);
64         if (ret)
65                 goto out;
66         /* TXSTATUS */
67         data = (unsigned long)regs->ctx.Flags;
68         if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
69                 data |= USER_GP_REGS_STATUS_CATCH_BIT;
70         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
71                                   &data, 4*25, 4*26);
72         if (ret)
73                 goto out;
74         /* TXRPT, TXBPOBITS, TXMODE */
75         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
76                                   &regs->ctx.CurrRPT, 4*26, 4*29);
77         if (ret)
78                 goto out;
79         /* Padding */
80         ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
81                                        4*29, 4*30);
82 out:
83         return ret;
84 }
85
86 int metag_gp_regs_copyin(struct pt_regs *regs,
87                          unsigned int pos, unsigned int count,
88                          const void *kbuf, const void __user *ubuf)
89 {
90         void *ptr;
91         unsigned long data;
92         int ret;
93
94         /* D{0-1}.{0-7} */
95         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
96                                  regs->ctx.DX, 0, 4*16);
97         if (ret)
98                 goto out;
99         /* A{0-1}.{0-1} */
100         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
101                                  regs->ctx.AX, 4*16, 4*20);
102         if (ret)
103                 goto out;
104         /* A{0-1}.2 */
105         if (regs->ctx.SaveMask & TBICTX_XEXT_BIT)
106                 ptr = regs->ctx.Ext.Ctx.pExt;
107         else
108                 ptr = &regs->ctx.Ext.AX2;
109         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
110                                  ptr, 4*20, 4*22);
111         if (ret)
112                 goto out;
113         /* A{0-1}.3 */
114         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
115                                  &regs->ctx.AX3, 4*22, 4*24);
116         if (ret)
117                 goto out;
118         /* PC */
119         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
120                                  &regs->ctx.CurrPC, 4*24, 4*25);
121         if (ret)
122                 goto out;
123         /* TXSTATUS */
124         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
125                                  &data, 4*25, 4*26);
126         if (ret)
127                 goto out;
128         regs->ctx.Flags = data & 0xffff;
129         if (data & USER_GP_REGS_STATUS_CATCH_BIT)
130                 regs->ctx.SaveMask |= TBICTX_XCBF_BIT | TBICTX_CBUF_BIT;
131         else
132                 regs->ctx.SaveMask &= ~TBICTX_CBUF_BIT;
133         /* TXRPT, TXBPOBITS, TXMODE */
134         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
135                                  &regs->ctx.CurrRPT, 4*26, 4*29);
136 out:
137         return ret;
138 }
139
140 static int metag_gp_regs_get(struct task_struct *target,
141                              const struct user_regset *regset,
142                              unsigned int pos, unsigned int count,
143                              void *kbuf, void __user *ubuf)
144 {
145         const struct pt_regs *regs = task_pt_regs(target);
146         return metag_gp_regs_copyout(regs, pos, count, kbuf, ubuf);
147 }
148
149 static int metag_gp_regs_set(struct task_struct *target,
150                              const struct user_regset *regset,
151                              unsigned int pos, unsigned int count,
152                              const void *kbuf, const void __user *ubuf)
153 {
154         struct pt_regs *regs = task_pt_regs(target);
155         return metag_gp_regs_copyin(regs, pos, count, kbuf, ubuf);
156 }
157
158 int metag_cb_regs_copyout(const struct pt_regs *regs,
159                           unsigned int pos, unsigned int count,
160                           void *kbuf, void __user *ubuf)
161 {
162         int ret;
163
164         /* TXCATCH{0-3} */
165         if (regs->ctx.SaveMask & TBICTX_XCBF_BIT)
166                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
167                                           regs->extcb0, 0, 4*4);
168         else
169                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
170                                                0, 4*4);
171         return ret;
172 }
173
174 int metag_cb_regs_copyin(struct pt_regs *regs,
175                          unsigned int pos, unsigned int count,
176                          const void *kbuf, const void __user *ubuf)
177 {
178         int ret;
179
180         /* TXCATCH{0-3} */
181         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
182                                  regs->extcb0, 0, 4*4);
183         return ret;
184 }
185
186 static int metag_cb_regs_get(struct task_struct *target,
187                              const struct user_regset *regset,
188                              unsigned int pos, unsigned int count,
189                              void *kbuf, void __user *ubuf)
190 {
191         const struct pt_regs *regs = task_pt_regs(target);
192         return metag_cb_regs_copyout(regs, pos, count, kbuf, ubuf);
193 }
194
195 static int metag_cb_regs_set(struct task_struct *target,
196                              const struct user_regset *regset,
197                              unsigned int pos, unsigned int count,
198                              const void *kbuf, const void __user *ubuf)
199 {
200         struct pt_regs *regs = task_pt_regs(target);
201         return metag_cb_regs_copyin(regs, pos, count, kbuf, ubuf);
202 }
203
204 int metag_rp_state_copyout(const struct pt_regs *regs,
205                            unsigned int pos, unsigned int count,
206                            void *kbuf, void __user *ubuf)
207 {
208         unsigned long mask;
209         u64 *ptr;
210         int ret, i;
211
212         /* Empty read pipeline */
213         if (!(regs->ctx.SaveMask & TBICTX_CBRP_BIT)) {
214                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
215                                                0, 4*13);
216                 goto out;
217         }
218
219         mask = (regs->ctx.CurrDIVTIME & TXDIVTIME_RPMASK_BITS) >>
220                 TXDIVTIME_RPMASK_S;
221
222         /* Read pipeline entries */
223         ptr = (void *)&regs->extcb0[1];
224         for (i = 0; i < 6; ++i, ++ptr) {
225                 if (mask & (1 << i))
226                         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
227                                                   ptr, 8*i, 8*(i + 1));
228                 else
229                         ret = user_regset_copyout_zero(&pos, &count, &kbuf,
230                                                        &ubuf, 8*i, 8*(i + 1));
231                 if (ret)
232                         goto out;
233         }
234         /* Mask of entries */
235         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
236                                   &mask, 4*12, 4*13);
237 out:
238         return ret;
239 }
240
241 int metag_rp_state_copyin(struct pt_regs *regs,
242                           unsigned int pos, unsigned int count,
243                           const void *kbuf, const void __user *ubuf)
244 {
245         struct user_rp_state rp;
246         unsigned long long *ptr;
247         int ret, i;
248
249         /* Read the entire pipeline before making any changes */
250         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
251                                  &rp, 0, 4*13);
252         if (ret)
253                 goto out;
254
255         /* Write pipeline entries */
256         ptr = (void *)&regs->extcb0[1];
257         for (i = 0; i < 6; ++i, ++ptr)
258                 if (rp.mask & (1 << i))
259                         *ptr = rp.entries[i];
260
261         /* Update RPMask in TXDIVTIME */
262         regs->ctx.CurrDIVTIME &= ~TXDIVTIME_RPMASK_BITS;
263         regs->ctx.CurrDIVTIME |= (rp.mask << TXDIVTIME_RPMASK_S)
264                                  & TXDIVTIME_RPMASK_BITS;
265
266         /* Set/clear flags to indicate catch/read pipeline state */
267         if (rp.mask)
268                 regs->ctx.SaveMask |= TBICTX_XCBF_BIT | TBICTX_CBRP_BIT;
269         else
270                 regs->ctx.SaveMask &= ~TBICTX_CBRP_BIT;
271 out:
272         return ret;
273 }
274
275 static int metag_rp_state_get(struct task_struct *target,
276                               const struct user_regset *regset,
277                               unsigned int pos, unsigned int count,
278                               void *kbuf, void __user *ubuf)
279 {
280         const struct pt_regs *regs = task_pt_regs(target);
281         return metag_rp_state_copyout(regs, pos, count, kbuf, ubuf);
282 }
283
284 static int metag_rp_state_set(struct task_struct *target,
285                               const struct user_regset *regset,
286                               unsigned int pos, unsigned int count,
287                               const void *kbuf, const void __user *ubuf)
288 {
289         struct pt_regs *regs = task_pt_regs(target);
290         return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf);
291 }
292
293 static int metag_tls_get(struct task_struct *target,
294                         const struct user_regset *regset,
295                         unsigned int pos, unsigned int count,
296                         void *kbuf, void __user *ubuf)
297 {
298         void __user *tls = target->thread.tls_ptr;
299         return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
300 }
301
302 static int metag_tls_set(struct task_struct *target,
303                         const struct user_regset *regset,
304                         unsigned int pos, unsigned int count,
305                         const void *kbuf, const void __user *ubuf)
306 {
307         int ret;
308         void __user *tls;
309
310         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
311         if (ret)
312                 return ret;
313
314         target->thread.tls_ptr = tls;
315         return ret;
316 }
317
318 enum metag_regset {
319         REGSET_GENERAL,
320         REGSET_CBUF,
321         REGSET_READPIPE,
322         REGSET_TLS,
323 };
324
325 static const struct user_regset metag_regsets[] = {
326         [REGSET_GENERAL] = {
327                 .core_note_type = NT_PRSTATUS,
328                 .n = ELF_NGREG,
329                 .size = sizeof(long),
330                 .align = sizeof(long long),
331                 .get = metag_gp_regs_get,
332                 .set = metag_gp_regs_set,
333         },
334         [REGSET_CBUF] = {
335                 .core_note_type = NT_METAG_CBUF,
336                 .n = sizeof(struct user_cb_regs) / sizeof(long),
337                 .size = sizeof(long),
338                 .align = sizeof(long long),
339                 .get = metag_cb_regs_get,
340                 .set = metag_cb_regs_set,
341         },
342         [REGSET_READPIPE] = {
343                 .core_note_type = NT_METAG_RPIPE,
344                 .n = sizeof(struct user_rp_state) / sizeof(long),
345                 .size = sizeof(long),
346                 .align = sizeof(long long),
347                 .get = metag_rp_state_get,
348                 .set = metag_rp_state_set,
349         },
350         [REGSET_TLS] = {
351                 .core_note_type = NT_METAG_TLS,
352                 .n = 1,
353                 .size = sizeof(void *),
354                 .align = sizeof(void *),
355                 .get = metag_tls_get,
356                 .set = metag_tls_set,
357         },
358 };
359
360 static const struct user_regset_view user_metag_view = {
361         .name = "metag",
362         .e_machine = EM_METAG,
363         .regsets = metag_regsets,
364         .n = ARRAY_SIZE(metag_regsets)
365 };
366
367 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
368 {
369         return &user_metag_view;
370 }
371
372 /*
373  * Called by kernel/ptrace.c when detaching..
374  *
375  * Make sure single step bits etc are not set.
376  */
377 void ptrace_disable(struct task_struct *child)
378 {
379         /* nothing to do.. */
380 }
381
382 long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
383                  unsigned long data)
384 {
385         int ret;
386
387         switch (request) {
388         default:
389                 ret = ptrace_request(child, request, addr, data);
390                 break;
391         }
392
393         return ret;
394 }
395
396 int syscall_trace_enter(struct pt_regs *regs)
397 {
398         int ret = 0;
399
400         if (test_thread_flag(TIF_SYSCALL_TRACE))
401                 ret = tracehook_report_syscall_entry(regs);
402
403         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
404                 trace_sys_enter(regs, regs->ctx.DX[0].U1);
405
406         return ret ? -1 : regs->ctx.DX[0].U1;
407 }
408
409 void syscall_trace_leave(struct pt_regs *regs)
410 {
411         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
412                 trace_sys_exit(regs, regs->ctx.DX[0].U1);
413
414         if (test_thread_flag(TIF_SYSCALL_TRACE))
415                 tracehook_report_syscall_exit(regs, 0);
416 }