Linux Audio

Check our new training course

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