2 * Copyright (C) 2005-2012 Imagination Technologies Ltd.
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.
9 #include <linux/kernel.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 <trace/syscall.h>
20 #define CREATE_TRACE_POINTS
21 #include <trace/events/syscalls.h>
24 * user_regset definitions.
27 static unsigned long user_txstatus(const struct pt_regs
*regs
)
29 unsigned long data
= (unsigned long)regs
->ctx
.Flags
;
31 if (regs
->ctx
.SaveMask
& TBICTX_CBUF_BIT
)
32 data
|= USER_GP_REGS_STATUS_CATCH_BIT
;
37 int metag_gp_regs_copyout(const struct pt_regs
*regs
,
38 unsigned int pos
, unsigned int count
,
39 void *kbuf
, void __user
*ubuf
)
46 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
47 regs
->ctx
.DX
, 0, 4*16);
51 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
52 regs
->ctx
.AX
, 4*16, 4*20);
56 if (regs
->ctx
.SaveMask
& TBICTX_XEXT_BIT
)
57 ptr
= regs
->ctx
.Ext
.Ctx
.pExt
;
59 ptr
= ®s
->ctx
.Ext
.AX2
;
60 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
65 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
66 ®s
->ctx
.AX3
, 4*22, 4*24);
70 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
71 ®s
->ctx
.CurrPC
, 4*24, 4*25);
75 data
= user_txstatus(regs
);
76 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
80 /* TXRPT, TXBPOBITS, TXMODE */
81 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
82 ®s
->ctx
.CurrRPT
, 4*26, 4*29);
86 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
92 int metag_gp_regs_copyin(struct pt_regs
*regs
,
93 unsigned int pos
, unsigned int count
,
94 const void *kbuf
, const void __user
*ubuf
)
101 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
102 regs
->ctx
.DX
, 0, 4*16);
106 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
107 regs
->ctx
.AX
, 4*16, 4*20);
111 if (regs
->ctx
.SaveMask
& TBICTX_XEXT_BIT
)
112 ptr
= regs
->ctx
.Ext
.Ctx
.pExt
;
114 ptr
= ®s
->ctx
.Ext
.AX2
;
115 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
120 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
121 ®s
->ctx
.AX3
, 4*22, 4*24);
125 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
126 ®s
->ctx
.CurrPC
, 4*24, 4*25);
130 data
= user_txstatus(regs
);
131 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
135 regs
->ctx
.Flags
= data
& 0xffff;
136 if (data
& USER_GP_REGS_STATUS_CATCH_BIT
)
137 regs
->ctx
.SaveMask
|= TBICTX_XCBF_BIT
| TBICTX_CBUF_BIT
;
139 regs
->ctx
.SaveMask
&= ~TBICTX_CBUF_BIT
;
140 /* TXRPT, TXBPOBITS, TXMODE */
141 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
142 ®s
->ctx
.CurrRPT
, 4*26, 4*29);
147 static int metag_gp_regs_get(struct task_struct
*target
,
148 const struct user_regset
*regset
,
149 unsigned int pos
, unsigned int count
,
150 void *kbuf
, void __user
*ubuf
)
152 const struct pt_regs
*regs
= task_pt_regs(target
);
153 return metag_gp_regs_copyout(regs
, pos
, count
, kbuf
, ubuf
);
156 static int metag_gp_regs_set(struct task_struct
*target
,
157 const struct user_regset
*regset
,
158 unsigned int pos
, unsigned int count
,
159 const void *kbuf
, const void __user
*ubuf
)
161 struct pt_regs
*regs
= task_pt_regs(target
);
162 return metag_gp_regs_copyin(regs
, pos
, count
, kbuf
, ubuf
);
165 int metag_cb_regs_copyout(const struct pt_regs
*regs
,
166 unsigned int pos
, unsigned int count
,
167 void *kbuf
, void __user
*ubuf
)
172 if (regs
->ctx
.SaveMask
& TBICTX_XCBF_BIT
)
173 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
174 regs
->extcb0
, 0, 4*4);
176 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
181 int metag_cb_regs_copyin(struct pt_regs
*regs
,
182 unsigned int pos
, unsigned int count
,
183 const void *kbuf
, const void __user
*ubuf
)
188 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
189 regs
->extcb0
, 0, 4*4);
193 static int metag_cb_regs_get(struct task_struct
*target
,
194 const struct user_regset
*regset
,
195 unsigned int pos
, unsigned int count
,
196 void *kbuf
, void __user
*ubuf
)
198 const struct pt_regs
*regs
= task_pt_regs(target
);
199 return metag_cb_regs_copyout(regs
, pos
, count
, kbuf
, ubuf
);
202 static int metag_cb_regs_set(struct task_struct
*target
,
203 const struct user_regset
*regset
,
204 unsigned int pos
, unsigned int count
,
205 const void *kbuf
, const void __user
*ubuf
)
207 struct pt_regs
*regs
= task_pt_regs(target
);
208 return metag_cb_regs_copyin(regs
, pos
, count
, kbuf
, ubuf
);
211 int metag_rp_state_copyout(const struct pt_regs
*regs
,
212 unsigned int pos
, unsigned int count
,
213 void *kbuf
, void __user
*ubuf
)
219 /* Empty read pipeline */
220 if (!(regs
->ctx
.SaveMask
& TBICTX_CBRP_BIT
)) {
221 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
226 mask
= (regs
->ctx
.CurrDIVTIME
& TXDIVTIME_RPMASK_BITS
) >>
229 /* Read pipeline entries */
230 ptr
= (void *)®s
->extcb0
[1];
231 for (i
= 0; i
< 6; ++i
, ++ptr
) {
233 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
234 ptr
, 8*i
, 8*(i
+ 1));
236 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
,
237 &ubuf
, 8*i
, 8*(i
+ 1));
241 /* Mask of entries */
242 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
248 int metag_rp_state_copyin(struct pt_regs
*regs
,
249 unsigned int pos
, unsigned int count
,
250 const void *kbuf
, const void __user
*ubuf
)
252 struct user_rp_state rp
;
253 unsigned long long *ptr
;
258 /* Read the entire pipeline before making any changes */
259 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
264 /* Write pipeline entries */
265 ptr
= (void *)®s
->extcb0
[1];
266 for (i
= 0; i
< 6; ++i
, ++ptr
)
267 if (rp
.mask
& (1 << i
))
268 *ptr
= rp
.entries
[i
];
270 /* Update RPMask in TXDIVTIME */
271 regs
->ctx
.CurrDIVTIME
&= ~TXDIVTIME_RPMASK_BITS
;
272 regs
->ctx
.CurrDIVTIME
|= (rp
.mask
<< TXDIVTIME_RPMASK_S
)
273 & TXDIVTIME_RPMASK_BITS
;
275 /* Set/clear flags to indicate catch/read pipeline state */
277 regs
->ctx
.SaveMask
|= TBICTX_XCBF_BIT
| TBICTX_CBRP_BIT
;
279 regs
->ctx
.SaveMask
&= ~TBICTX_CBRP_BIT
;
284 static int metag_rp_state_get(struct task_struct
*target
,
285 const struct user_regset
*regset
,
286 unsigned int pos
, unsigned int count
,
287 void *kbuf
, void __user
*ubuf
)
289 const struct pt_regs
*regs
= task_pt_regs(target
);
290 return metag_rp_state_copyout(regs
, pos
, count
, kbuf
, ubuf
);
293 static int metag_rp_state_set(struct task_struct
*target
,
294 const struct user_regset
*regset
,
295 unsigned int pos
, unsigned int count
,
296 const void *kbuf
, const void __user
*ubuf
)
298 struct pt_regs
*regs
= task_pt_regs(target
);
299 return metag_rp_state_copyin(regs
, pos
, count
, kbuf
, ubuf
);
302 static int metag_tls_get(struct task_struct
*target
,
303 const struct user_regset
*regset
,
304 unsigned int pos
, unsigned int count
,
305 void *kbuf
, void __user
*ubuf
)
307 void __user
*tls
= target
->thread
.tls_ptr
;
308 return user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
, &tls
, 0, -1);
311 static int metag_tls_set(struct task_struct
*target
,
312 const struct user_regset
*regset
,
313 unsigned int pos
, unsigned int count
,
314 const void *kbuf
, const void __user
*ubuf
)
317 void __user
*tls
= target
->thread
.tls_ptr
;
319 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &tls
, 0, -1);
323 target
->thread
.tls_ptr
= tls
;
334 static const struct user_regset metag_regsets
[] = {
336 .core_note_type
= NT_PRSTATUS
,
338 .size
= sizeof(long),
339 .align
= sizeof(long long),
340 .get
= metag_gp_regs_get
,
341 .set
= metag_gp_regs_set
,
344 .core_note_type
= NT_METAG_CBUF
,
345 .n
= sizeof(struct user_cb_regs
) / sizeof(long),
346 .size
= sizeof(long),
347 .align
= sizeof(long long),
348 .get
= metag_cb_regs_get
,
349 .set
= metag_cb_regs_set
,
351 [REGSET_READPIPE
] = {
352 .core_note_type
= NT_METAG_RPIPE
,
353 .n
= sizeof(struct user_rp_state
) / sizeof(long),
354 .size
= sizeof(long),
355 .align
= sizeof(long long),
356 .get
= metag_rp_state_get
,
357 .set
= metag_rp_state_set
,
360 .core_note_type
= NT_METAG_TLS
,
362 .size
= sizeof(void *),
363 .align
= sizeof(void *),
364 .get
= metag_tls_get
,
365 .set
= metag_tls_set
,
369 static const struct user_regset_view user_metag_view
= {
371 .e_machine
= EM_METAG
,
372 .regsets
= metag_regsets
,
373 .n
= ARRAY_SIZE(metag_regsets
)
376 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
378 return &user_metag_view
;
382 * Called by kernel/ptrace.c when detaching..
384 * Make sure single step bits etc are not set.
386 void ptrace_disable(struct task_struct
*child
)
388 /* nothing to do.. */
391 long arch_ptrace(struct task_struct
*child
, long request
, unsigned long addr
,
398 ret
= ptrace_request(child
, request
, addr
, data
);
405 int syscall_trace_enter(struct pt_regs
*regs
)
409 if (test_thread_flag(TIF_SYSCALL_TRACE
))
410 ret
= tracehook_report_syscall_entry(regs
);
412 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT
)))
413 trace_sys_enter(regs
, regs
->ctx
.DX
[0].U1
);
415 return ret
? -1 : regs
->ctx
.DX
[0].U1
;
418 void syscall_trace_leave(struct pt_regs
*regs
)
420 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT
)))
421 trace_sys_exit(regs
, regs
->ctx
.DX
[0].U1
);
423 if (test_thread_flag(TIF_SYSCALL_TRACE
))
424 tracehook_report_syscall_exit(regs
, 0);