cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ptrace_64.c (28121B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* ptrace.c: Sparc process tracing support.
      3 *
      4 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
      5 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
      6 *
      7 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
      8 * and David Mosberger.
      9 *
     10 * Added Linux support -miguel (weird, eh?, the original code was meant
     11 * to emulate SunOS).
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/sched.h>
     16#include <linux/sched/task_stack.h>
     17#include <linux/mm.h>
     18#include <linux/errno.h>
     19#include <linux/export.h>
     20#include <linux/ptrace.h>
     21#include <linux/user.h>
     22#include <linux/smp.h>
     23#include <linux/security.h>
     24#include <linux/seccomp.h>
     25#include <linux/audit.h>
     26#include <linux/signal.h>
     27#include <linux/regset.h>
     28#include <trace/syscall.h>
     29#include <linux/compat.h>
     30#include <linux/elf.h>
     31#include <linux/context_tracking.h>
     32
     33#include <asm/asi.h>
     34#include <linux/uaccess.h>
     35#include <asm/psrcompat.h>
     36#include <asm/visasm.h>
     37#include <asm/spitfire.h>
     38#include <asm/page.h>
     39#include <asm/cpudata.h>
     40#include <asm/cacheflush.h>
     41
     42#define CREATE_TRACE_POINTS
     43#include <trace/events/syscalls.h>
     44
     45#include "entry.h"
     46
     47/* #define ALLOW_INIT_TRACING */
     48
     49struct pt_regs_offset {
     50	const char *name;
     51	int offset;
     52};
     53
     54#define REG_OFFSET_NAME(n, r) \
     55	{.name = n, .offset = (PT_V9_##r)}
     56#define REG_OFFSET_END {.name = NULL, .offset = 0}
     57
     58static const struct pt_regs_offset regoffset_table[] = {
     59	REG_OFFSET_NAME("g0", G0),
     60	REG_OFFSET_NAME("g1", G1),
     61	REG_OFFSET_NAME("g2", G2),
     62	REG_OFFSET_NAME("g3", G3),
     63	REG_OFFSET_NAME("g4", G4),
     64	REG_OFFSET_NAME("g5", G5),
     65	REG_OFFSET_NAME("g6", G6),
     66	REG_OFFSET_NAME("g7", G7),
     67
     68	REG_OFFSET_NAME("i0", I0),
     69	REG_OFFSET_NAME("i1", I1),
     70	REG_OFFSET_NAME("i2", I2),
     71	REG_OFFSET_NAME("i3", I3),
     72	REG_OFFSET_NAME("i4", I4),
     73	REG_OFFSET_NAME("i5", I5),
     74	REG_OFFSET_NAME("i6", I6),
     75	REG_OFFSET_NAME("i7", I7),
     76
     77	REG_OFFSET_NAME("tstate", TSTATE),
     78	REG_OFFSET_NAME("pc", TPC),
     79	REG_OFFSET_NAME("npc", TNPC),
     80	REG_OFFSET_NAME("y", Y),
     81	REG_OFFSET_NAME("lr", I7),
     82
     83	REG_OFFSET_END,
     84};
     85
     86/*
     87 * Called by kernel/ptrace.c when detaching..
     88 *
     89 * Make sure single step bits etc are not set.
     90 */
     91void ptrace_disable(struct task_struct *child)
     92{
     93	/* nothing to do */
     94}
     95
     96/* To get the necessary page struct, access_process_vm() first calls
     97 * get_user_pages().  This has done a flush_dcache_page() on the
     98 * accessed page.  Then our caller (copy_{to,from}_user_page()) did
     99 * to memcpy to read/write the data from that page.
    100 *
    101 * Now, the only thing we have to do is:
    102 * 1) flush the D-cache if it's possible than an illegal alias
    103 *    has been created
    104 * 2) flush the I-cache if this is pre-cheetah and we did a write
    105 */
    106void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
    107			 unsigned long uaddr, void *kaddr,
    108			 unsigned long len, int write)
    109{
    110	BUG_ON(len > PAGE_SIZE);
    111
    112	if (tlb_type == hypervisor)
    113		return;
    114
    115	preempt_disable();
    116
    117#ifdef DCACHE_ALIASING_POSSIBLE
    118	/* If bit 13 of the kernel address we used to access the
    119	 * user page is the same as the virtual address that page
    120	 * is mapped to in the user's address space, we can skip the
    121	 * D-cache flush.
    122	 */
    123	if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
    124		unsigned long start = __pa(kaddr);
    125		unsigned long end = start + len;
    126		unsigned long dcache_line_size;
    127
    128		dcache_line_size = local_cpu_data().dcache_line_size;
    129
    130		if (tlb_type == spitfire) {
    131			for (; start < end; start += dcache_line_size)
    132				spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
    133		} else {
    134			start &= ~(dcache_line_size - 1);
    135			for (; start < end; start += dcache_line_size)
    136				__asm__ __volatile__(
    137					"stxa %%g0, [%0] %1\n\t"
    138					"membar #Sync"
    139					: /* no outputs */
    140					: "r" (start),
    141					"i" (ASI_DCACHE_INVALIDATE));
    142		}
    143	}
    144#endif
    145	if (write && tlb_type == spitfire) {
    146		unsigned long start = (unsigned long) kaddr;
    147		unsigned long end = start + len;
    148		unsigned long icache_line_size;
    149
    150		icache_line_size = local_cpu_data().icache_line_size;
    151
    152		for (; start < end; start += icache_line_size)
    153			flushi(start);
    154	}
    155
    156	preempt_enable();
    157}
    158EXPORT_SYMBOL_GPL(flush_ptrace_access);
    159
    160static int get_from_target(struct task_struct *target, unsigned long uaddr,
    161			   void *kbuf, int len)
    162{
    163	if (target == current) {
    164		if (copy_from_user(kbuf, (void __user *) uaddr, len))
    165			return -EFAULT;
    166	} else {
    167		int len2 = access_process_vm(target, uaddr, kbuf, len,
    168				FOLL_FORCE);
    169		if (len2 != len)
    170			return -EFAULT;
    171	}
    172	return 0;
    173}
    174
    175static int set_to_target(struct task_struct *target, unsigned long uaddr,
    176			 void *kbuf, int len)
    177{
    178	if (target == current) {
    179		if (copy_to_user((void __user *) uaddr, kbuf, len))
    180			return -EFAULT;
    181	} else {
    182		int len2 = access_process_vm(target, uaddr, kbuf, len,
    183				FOLL_FORCE | FOLL_WRITE);
    184		if (len2 != len)
    185			return -EFAULT;
    186	}
    187	return 0;
    188}
    189
    190static int regwindow64_get(struct task_struct *target,
    191			   const struct pt_regs *regs,
    192			   struct reg_window *wbuf)
    193{
    194	unsigned long rw_addr = regs->u_regs[UREG_I6];
    195
    196	if (!test_thread_64bit_stack(rw_addr)) {
    197		struct reg_window32 win32;
    198		int i;
    199
    200		if (get_from_target(target, rw_addr, &win32, sizeof(win32)))
    201			return -EFAULT;
    202		for (i = 0; i < 8; i++)
    203			wbuf->locals[i] = win32.locals[i];
    204		for (i = 0; i < 8; i++)
    205			wbuf->ins[i] = win32.ins[i];
    206	} else {
    207		rw_addr += STACK_BIAS;
    208		if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf)))
    209			return -EFAULT;
    210	}
    211
    212	return 0;
    213}
    214
    215static int regwindow64_set(struct task_struct *target,
    216			   const struct pt_regs *regs,
    217			   struct reg_window *wbuf)
    218{
    219	unsigned long rw_addr = regs->u_regs[UREG_I6];
    220
    221	if (!test_thread_64bit_stack(rw_addr)) {
    222		struct reg_window32 win32;
    223		int i;
    224
    225		for (i = 0; i < 8; i++)
    226			win32.locals[i] = wbuf->locals[i];
    227		for (i = 0; i < 8; i++)
    228			win32.ins[i] = wbuf->ins[i];
    229
    230		if (set_to_target(target, rw_addr, &win32, sizeof(win32)))
    231			return -EFAULT;
    232	} else {
    233		rw_addr += STACK_BIAS;
    234		if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf)))
    235			return -EFAULT;
    236	}
    237
    238	return 0;
    239}
    240
    241enum sparc_regset {
    242	REGSET_GENERAL,
    243	REGSET_FP,
    244};
    245
    246static int genregs64_get(struct task_struct *target,
    247			 const struct user_regset *regset,
    248			 struct membuf to)
    249{
    250	const struct pt_regs *regs = task_pt_regs(target);
    251	struct reg_window window;
    252
    253	if (target == current)
    254		flushw_user();
    255
    256	membuf_write(&to, regs->u_regs, 16 * sizeof(u64));
    257	if (!to.left)
    258		return 0;
    259	if (regwindow64_get(target, regs, &window))
    260		return -EFAULT;
    261	membuf_write(&to, &window, 16 * sizeof(u64));
    262	/* TSTATE, TPC, TNPC */
    263	membuf_write(&to, &regs->tstate, 3 * sizeof(u64));
    264	return membuf_store(&to, (u64)regs->y);
    265}
    266
    267static int genregs64_set(struct task_struct *target,
    268			 const struct user_regset *regset,
    269			 unsigned int pos, unsigned int count,
    270			 const void *kbuf, const void __user *ubuf)
    271{
    272	struct pt_regs *regs = task_pt_regs(target);
    273	int ret;
    274
    275	if (target == current)
    276		flushw_user();
    277
    278	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    279				 regs->u_regs,
    280				 0, 16 * sizeof(u64));
    281	if (!ret && count && pos < (32 * sizeof(u64))) {
    282		struct reg_window window;
    283
    284		if (regwindow64_get(target, regs, &window))
    285			return -EFAULT;
    286
    287		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    288					 &window,
    289					 16 * sizeof(u64),
    290					 32 * sizeof(u64));
    291
    292		if (!ret &&
    293		    regwindow64_set(target, regs, &window))
    294			return -EFAULT;
    295	}
    296
    297	if (!ret && count > 0) {
    298		unsigned long tstate;
    299
    300		/* TSTATE */
    301		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    302					 &tstate,
    303					 32 * sizeof(u64),
    304					 33 * sizeof(u64));
    305		if (!ret) {
    306			/* Only the condition codes and the "in syscall"
    307			 * state can be modified in the %tstate register.
    308			 */
    309			tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    310			regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    311			regs->tstate |= tstate;
    312		}
    313	}
    314
    315	if (!ret) {
    316		/* TPC, TNPC */
    317		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    318					 &regs->tpc,
    319					 33 * sizeof(u64),
    320					 35 * sizeof(u64));
    321	}
    322
    323	if (!ret) {
    324		unsigned long y = regs->y;
    325
    326		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    327					 &y,
    328					 35 * sizeof(u64),
    329					 36 * sizeof(u64));
    330		if (!ret)
    331			regs->y = y;
    332	}
    333
    334	if (!ret)
    335		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    336						36 * sizeof(u64), -1);
    337
    338	return ret;
    339}
    340
    341static int fpregs64_get(struct task_struct *target,
    342			const struct user_regset *regset,
    343			struct membuf to)
    344{
    345	struct thread_info *t = task_thread_info(target);
    346	unsigned long fprs;
    347
    348	if (target == current)
    349		save_and_clear_fpu();
    350
    351	fprs = t->fpsaved[0];
    352
    353	if (fprs & FPRS_DL)
    354		membuf_write(&to, t->fpregs, 16 * sizeof(u64));
    355	else
    356		membuf_zero(&to, 16 * sizeof(u64));
    357
    358	if (fprs & FPRS_DU)
    359		membuf_write(&to, t->fpregs + 16, 16 * sizeof(u64));
    360	else
    361		membuf_zero(&to, 16 * sizeof(u64));
    362	if (fprs & FPRS_FEF) {
    363		membuf_store(&to, t->xfsr[0]);
    364		membuf_store(&to, t->gsr[0]);
    365	} else {
    366		membuf_zero(&to, 2 * sizeof(u64));
    367	}
    368	return membuf_store(&to, fprs);
    369}
    370
    371static int fpregs64_set(struct task_struct *target,
    372			const struct user_regset *regset,
    373			unsigned int pos, unsigned int count,
    374			const void *kbuf, const void __user *ubuf)
    375{
    376	unsigned long *fpregs = task_thread_info(target)->fpregs;
    377	unsigned long fprs;
    378	int ret;
    379
    380	if (target == current)
    381		save_and_clear_fpu();
    382
    383	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    384				 fpregs,
    385				 0, 32 * sizeof(u64));
    386	if (!ret)
    387		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    388					 task_thread_info(target)->xfsr,
    389					 32 * sizeof(u64),
    390					 33 * sizeof(u64));
    391	if (!ret)
    392		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    393					 task_thread_info(target)->gsr,
    394					 33 * sizeof(u64),
    395					 34 * sizeof(u64));
    396
    397	fprs = task_thread_info(target)->fpsaved[0];
    398	if (!ret && count > 0) {
    399		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    400					 &fprs,
    401					 34 * sizeof(u64),
    402					 35 * sizeof(u64));
    403	}
    404
    405	fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
    406	task_thread_info(target)->fpsaved[0] = fprs;
    407
    408	if (!ret)
    409		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    410						35 * sizeof(u64), -1);
    411	return ret;
    412}
    413
    414static const struct user_regset sparc64_regsets[] = {
    415	/* Format is:
    416	 * 	G0 --> G7
    417	 *	O0 --> O7
    418	 *	L0 --> L7
    419	 *	I0 --> I7
    420	 *	TSTATE, TPC, TNPC, Y
    421	 */
    422	[REGSET_GENERAL] = {
    423		.core_note_type = NT_PRSTATUS,
    424		.n = 36,
    425		.size = sizeof(u64), .align = sizeof(u64),
    426		.regset_get = genregs64_get, .set = genregs64_set
    427	},
    428	/* Format is:
    429	 *	F0 --> F63
    430	 *	FSR
    431	 *	GSR
    432	 *	FPRS
    433	 */
    434	[REGSET_FP] = {
    435		.core_note_type = NT_PRFPREG,
    436		.n = 35,
    437		.size = sizeof(u64), .align = sizeof(u64),
    438		.regset_get = fpregs64_get, .set = fpregs64_set
    439	},
    440};
    441
    442static int getregs64_get(struct task_struct *target,
    443			 const struct user_regset *regset,
    444			 struct membuf to)
    445{
    446	const struct pt_regs *regs = task_pt_regs(target);
    447
    448	if (target == current)
    449		flushw_user();
    450
    451	membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u64));
    452	membuf_store(&to, (u64)0);
    453	membuf_write(&to, &regs->tstate, 3 * sizeof(u64));
    454	return membuf_store(&to, (u64)regs->y);
    455}
    456
    457static int setregs64_set(struct task_struct *target,
    458			 const struct user_regset *regset,
    459			 unsigned int pos, unsigned int count,
    460			 const void *kbuf, const void __user *ubuf)
    461{
    462	struct pt_regs *regs = task_pt_regs(target);
    463	unsigned long y = regs->y;
    464	unsigned long tstate;
    465	int ret;
    466
    467	if (target == current)
    468		flushw_user();
    469
    470	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    471				 regs->u_regs + 1,
    472				 0 * sizeof(u64),
    473				 15 * sizeof(u64));
    474	if (ret)
    475		return ret;
    476	ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    477				 15 * sizeof(u64), 16 * sizeof(u64));
    478	if (ret)
    479		return ret;
    480	/* TSTATE */
    481	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    482				 &tstate,
    483				 16 * sizeof(u64),
    484				 17 * sizeof(u64));
    485	if (ret)
    486		return ret;
    487	/* Only the condition codes and the "in syscall"
    488	 * state can be modified in the %tstate register.
    489	 */
    490	tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    491	regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    492	regs->tstate |= tstate;
    493
    494	/* TPC, TNPC */
    495	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    496				 &regs->tpc,
    497				 17 * sizeof(u64),
    498				 19 * sizeof(u64));
    499	if (ret)
    500		return ret;
    501	/* Y */
    502	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    503				 &y,
    504				 19 * sizeof(u64),
    505				 20 * sizeof(u64));
    506	if (!ret)
    507		regs->y = y;
    508	return ret;
    509}
    510
    511static const struct user_regset ptrace64_regsets[] = {
    512	/* Format is:
    513	 *      G1 --> G7
    514	 *      O0 --> O7
    515	 *	0
    516	 *      TSTATE, TPC, TNPC, Y
    517	 */
    518	[REGSET_GENERAL] = {
    519		.n = 20, .size = sizeof(u64),
    520		.regset_get = getregs64_get, .set = setregs64_set,
    521	},
    522};
    523
    524static const struct user_regset_view ptrace64_view = {
    525	.regsets = ptrace64_regsets, .n = ARRAY_SIZE(ptrace64_regsets)
    526};
    527
    528static const struct user_regset_view user_sparc64_view = {
    529	.name = "sparc64", .e_machine = EM_SPARCV9,
    530	.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
    531};
    532
    533#ifdef CONFIG_COMPAT
    534static int genregs32_get(struct task_struct *target,
    535			 const struct user_regset *regset,
    536			 struct membuf to)
    537{
    538	const struct pt_regs *regs = task_pt_regs(target);
    539	u32 uregs[16];
    540	int i;
    541
    542	if (target == current)
    543		flushw_user();
    544
    545	for (i = 0; i < 16; i++)
    546		membuf_store(&to, (u32)regs->u_regs[i]);
    547	if (!to.left)
    548		return 0;
    549	if (get_from_target(target, regs->u_regs[UREG_I6],
    550			    uregs, sizeof(uregs)))
    551		return -EFAULT;
    552	membuf_write(&to, uregs, 16 * sizeof(u32));
    553	membuf_store(&to, (u32)tstate_to_psr(regs->tstate));
    554	membuf_store(&to, (u32)(regs->tpc));
    555	membuf_store(&to, (u32)(regs->tnpc));
    556	membuf_store(&to, (u32)(regs->y));
    557	return membuf_zero(&to, 2 * sizeof(u32));
    558}
    559
    560static int genregs32_set(struct task_struct *target,
    561			 const struct user_regset *regset,
    562			 unsigned int pos, unsigned int count,
    563			 const void *kbuf, const void __user *ubuf)
    564{
    565	struct pt_regs *regs = task_pt_regs(target);
    566	compat_ulong_t __user *reg_window;
    567	const compat_ulong_t *k = kbuf;
    568	const compat_ulong_t __user *u = ubuf;
    569	compat_ulong_t reg;
    570
    571	if (target == current)
    572		flushw_user();
    573
    574	pos /= sizeof(reg);
    575	count /= sizeof(reg);
    576
    577	if (kbuf) {
    578		for (; count > 0 && pos < 16; count--)
    579			regs->u_regs[pos++] = *k++;
    580
    581		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
    582		reg_window -= 16;
    583		if (target == current) {
    584			for (; count > 0 && pos < 32; count--) {
    585				if (put_user(*k++, &reg_window[pos++]))
    586					return -EFAULT;
    587			}
    588		} else {
    589			for (; count > 0 && pos < 32; count--) {
    590				if (access_process_vm(target,
    591						      (unsigned long)
    592						      &reg_window[pos],
    593						      (void *) k,
    594						      sizeof(*k),
    595						      FOLL_FORCE | FOLL_WRITE)
    596				    != sizeof(*k))
    597					return -EFAULT;
    598				k++;
    599				pos++;
    600			}
    601		}
    602	} else {
    603		for (; count > 0 && pos < 16; count--) {
    604			if (get_user(reg, u++))
    605				return -EFAULT;
    606			regs->u_regs[pos++] = reg;
    607		}
    608
    609		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
    610		reg_window -= 16;
    611		if (target == current) {
    612			for (; count > 0 && pos < 32; count--) {
    613				if (get_user(reg, u++) ||
    614				    put_user(reg, &reg_window[pos++]))
    615					return -EFAULT;
    616			}
    617		} else {
    618			for (; count > 0 && pos < 32; count--) {
    619				if (get_user(reg, u++))
    620					return -EFAULT;
    621				if (access_process_vm(target,
    622						      (unsigned long)
    623						      &reg_window[pos],
    624						      &reg, sizeof(reg),
    625						      FOLL_FORCE | FOLL_WRITE)
    626				    != sizeof(reg))
    627					return -EFAULT;
    628				pos++;
    629				u++;
    630			}
    631		}
    632	}
    633	while (count > 0) {
    634		unsigned long tstate;
    635
    636		if (kbuf)
    637			reg = *k++;
    638		else if (get_user(reg, u++))
    639			return -EFAULT;
    640
    641		switch (pos) {
    642		case 32: /* PSR */
    643			tstate = regs->tstate;
    644			tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    645			tstate |= psr_to_tstate_icc(reg);
    646			if (reg & PSR_SYSCALL)
    647				tstate |= TSTATE_SYSCALL;
    648			regs->tstate = tstate;
    649			break;
    650		case 33: /* PC */
    651			regs->tpc = reg;
    652			break;
    653		case 34: /* NPC */
    654			regs->tnpc = reg;
    655			break;
    656		case 35: /* Y */
    657			regs->y = reg;
    658			break;
    659		case 36: /* WIM */
    660		case 37: /* TBR */
    661			break;
    662		default:
    663			goto finish;
    664		}
    665
    666		pos++;
    667		count--;
    668	}
    669finish:
    670	pos *= sizeof(reg);
    671	count *= sizeof(reg);
    672
    673	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    674					 38 * sizeof(reg), -1);
    675}
    676
    677static int fpregs32_get(struct task_struct *target,
    678			const struct user_regset *regset,
    679			struct membuf to)
    680{
    681	struct thread_info *t = task_thread_info(target);
    682	bool enabled;
    683
    684	if (target == current)
    685		save_and_clear_fpu();
    686
    687	enabled = t->fpsaved[0] & FPRS_FEF;
    688
    689	membuf_write(&to, t->fpregs, 32 * sizeof(u32));
    690	membuf_zero(&to, sizeof(u32));
    691	if (enabled)
    692		membuf_store(&to, (u32)t->xfsr[0]);
    693	else
    694		membuf_zero(&to, sizeof(u32));
    695	membuf_store(&to, (u32)((enabled << 8) | (8 << 16)));
    696	return membuf_zero(&to, 64 * sizeof(u32));
    697}
    698
    699static int fpregs32_set(struct task_struct *target,
    700			const struct user_regset *regset,
    701			unsigned int pos, unsigned int count,
    702			const void *kbuf, const void __user *ubuf)
    703{
    704	unsigned long *fpregs = task_thread_info(target)->fpregs;
    705	unsigned long fprs;
    706	int ret;
    707
    708	if (target == current)
    709		save_and_clear_fpu();
    710
    711	fprs = task_thread_info(target)->fpsaved[0];
    712
    713	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    714				 fpregs,
    715				 0, 32 * sizeof(u32));
    716	if (!ret)
    717		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    718					  32 * sizeof(u32),
    719					  33 * sizeof(u32));
    720	if (!ret && count > 0) {
    721		compat_ulong_t fsr;
    722		unsigned long val;
    723
    724		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    725					 &fsr,
    726					 33 * sizeof(u32),
    727					 34 * sizeof(u32));
    728		if (!ret) {
    729			val = task_thread_info(target)->xfsr[0];
    730			val &= 0xffffffff00000000UL;
    731			val |= fsr;
    732			task_thread_info(target)->xfsr[0] = val;
    733		}
    734	}
    735
    736	fprs |= (FPRS_FEF | FPRS_DL);
    737	task_thread_info(target)->fpsaved[0] = fprs;
    738
    739	if (!ret)
    740		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    741						34 * sizeof(u32), -1);
    742	return ret;
    743}
    744
    745static const struct user_regset sparc32_regsets[] = {
    746	/* Format is:
    747	 * 	G0 --> G7
    748	 *	O0 --> O7
    749	 *	L0 --> L7
    750	 *	I0 --> I7
    751	 *	PSR, PC, nPC, Y, WIM, TBR
    752	 */
    753	[REGSET_GENERAL] = {
    754		.core_note_type = NT_PRSTATUS,
    755		.n = 38,
    756		.size = sizeof(u32), .align = sizeof(u32),
    757		.regset_get = genregs32_get, .set = genregs32_set
    758	},
    759	/* Format is:
    760	 *	F0 --> F31
    761	 *	empty 32-bit word
    762	 *	FSR (32--bit word)
    763	 *	FPU QUEUE COUNT (8-bit char)
    764	 *	FPU QUEUE ENTRYSIZE (8-bit char)
    765	 *	FPU ENABLED (8-bit char)
    766	 *	empty 8-bit char
    767	 *	FPU QUEUE (64 32-bit ints)
    768	 */
    769	[REGSET_FP] = {
    770		.core_note_type = NT_PRFPREG,
    771		.n = 99,
    772		.size = sizeof(u32), .align = sizeof(u32),
    773		.regset_get = fpregs32_get, .set = fpregs32_set
    774	},
    775};
    776
    777static int getregs_get(struct task_struct *target,
    778			 const struct user_regset *regset,
    779			 struct membuf to)
    780{
    781	const struct pt_regs *regs = task_pt_regs(target);
    782	int i;
    783
    784	if (target == current)
    785		flushw_user();
    786
    787	membuf_store(&to, (u32)tstate_to_psr(regs->tstate));
    788	membuf_store(&to, (u32)(regs->tpc));
    789	membuf_store(&to, (u32)(regs->tnpc));
    790	membuf_store(&to, (u32)(regs->y));
    791	for (i = 1; i < 16; i++)
    792		membuf_store(&to, (u32)regs->u_regs[i]);
    793	return to.left;
    794}
    795
    796static int setregs_set(struct task_struct *target,
    797			 const struct user_regset *regset,
    798			 unsigned int pos, unsigned int count,
    799			 const void *kbuf, const void __user *ubuf)
    800{
    801	struct pt_regs *regs = task_pt_regs(target);
    802	unsigned long tstate;
    803	u32 uregs[19];
    804	int i, ret;
    805
    806	if (target == current)
    807		flushw_user();
    808
    809	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    810				 uregs,
    811				 0, 19 * sizeof(u32));
    812	if (ret)
    813		return ret;
    814
    815	tstate = regs->tstate;
    816	tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
    817	tstate |= psr_to_tstate_icc(uregs[0]);
    818	if (uregs[0] & PSR_SYSCALL)
    819		tstate |= TSTATE_SYSCALL;
    820	regs->tstate = tstate;
    821	regs->tpc = uregs[1];
    822	regs->tnpc = uregs[2];
    823	regs->y = uregs[3];
    824
    825	for (i = 1; i < 15; i++)
    826		regs->u_regs[i] = uregs[3 + i];
    827	return 0;
    828}
    829
    830static int getfpregs_get(struct task_struct *target,
    831			const struct user_regset *regset,
    832			struct membuf to)
    833{
    834	struct thread_info *t = task_thread_info(target);
    835
    836	if (target == current)
    837		save_and_clear_fpu();
    838
    839	membuf_write(&to, t->fpregs, 32 * sizeof(u32));
    840	if (t->fpsaved[0] & FPRS_FEF)
    841		membuf_store(&to, (u32)t->xfsr[0]);
    842	else
    843		membuf_zero(&to, sizeof(u32));
    844	return membuf_zero(&to, 35 * sizeof(u32));
    845}
    846
    847static int setfpregs_set(struct task_struct *target,
    848			const struct user_regset *regset,
    849			unsigned int pos, unsigned int count,
    850			const void *kbuf, const void __user *ubuf)
    851{
    852	unsigned long *fpregs = task_thread_info(target)->fpregs;
    853	unsigned long fprs;
    854	int ret;
    855
    856	if (target == current)
    857		save_and_clear_fpu();
    858
    859	fprs = task_thread_info(target)->fpsaved[0];
    860
    861	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    862				 fpregs,
    863				 0, 32 * sizeof(u32));
    864	if (!ret) {
    865		compat_ulong_t fsr;
    866		unsigned long val;
    867
    868		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    869					 &fsr,
    870					 32 * sizeof(u32),
    871					 33 * sizeof(u32));
    872		if (!ret) {
    873			val = task_thread_info(target)->xfsr[0];
    874			val &= 0xffffffff00000000UL;
    875			val |= fsr;
    876			task_thread_info(target)->xfsr[0] = val;
    877		}
    878	}
    879
    880	fprs |= (FPRS_FEF | FPRS_DL);
    881	task_thread_info(target)->fpsaved[0] = fprs;
    882	return ret;
    883}
    884
    885static const struct user_regset ptrace32_regsets[] = {
    886	[REGSET_GENERAL] = {
    887		.n = 19, .size = sizeof(u32),
    888		.regset_get = getregs_get, .set = setregs_set,
    889	},
    890	[REGSET_FP] = {
    891		.n = 68, .size = sizeof(u32),
    892		.regset_get = getfpregs_get, .set = setfpregs_set,
    893	},
    894};
    895
    896static const struct user_regset_view ptrace32_view = {
    897	.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
    898};
    899
    900static const struct user_regset_view user_sparc32_view = {
    901	.name = "sparc", .e_machine = EM_SPARC,
    902	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
    903};
    904#endif /* CONFIG_COMPAT */
    905
    906const struct user_regset_view *task_user_regset_view(struct task_struct *task)
    907{
    908#ifdef CONFIG_COMPAT
    909	if (test_tsk_thread_flag(task, TIF_32BIT))
    910		return &user_sparc32_view;
    911#endif
    912	return &user_sparc64_view;
    913}
    914
    915#ifdef CONFIG_COMPAT
    916struct compat_fps {
    917	unsigned int regs[32];
    918	unsigned int fsr;
    919	unsigned int flags;
    920	unsigned int extra;
    921	unsigned int fpqd;
    922	struct compat_fq {
    923		unsigned int insnaddr;
    924		unsigned int insn;
    925	} fpq[16];
    926};
    927
    928long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
    929			compat_ulong_t caddr, compat_ulong_t cdata)
    930{
    931	compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
    932	struct pt_regs32 __user *pregs;
    933	struct compat_fps __user *fps;
    934	unsigned long addr2 = caddr2;
    935	unsigned long addr = caddr;
    936	unsigned long data = cdata;
    937	int ret;
    938
    939	pregs = (struct pt_regs32 __user *) addr;
    940	fps = (struct compat_fps __user *) addr;
    941
    942	switch (request) {
    943	case PTRACE_PEEKUSR:
    944		ret = (addr != 0) ? -EIO : 0;
    945		break;
    946
    947	case PTRACE_GETREGS:
    948		ret = copy_regset_to_user(child, &ptrace32_view,
    949					  REGSET_GENERAL, 0,
    950					  19 * sizeof(u32),
    951					  pregs);
    952		break;
    953
    954	case PTRACE_SETREGS:
    955		ret = copy_regset_from_user(child, &ptrace32_view,
    956					  REGSET_GENERAL, 0,
    957					  19 * sizeof(u32),
    958					  pregs);
    959		break;
    960
    961	case PTRACE_GETFPREGS:
    962		ret = copy_regset_to_user(child, &ptrace32_view,
    963					  REGSET_FP, 0,
    964					  68 * sizeof(u32),
    965					  fps);
    966		break;
    967
    968	case PTRACE_SETFPREGS:
    969		ret = copy_regset_from_user(child, &ptrace32_view,
    970					  REGSET_FP, 0,
    971					  33 * sizeof(u32),
    972					  fps);
    973		break;
    974
    975	case PTRACE_READTEXT:
    976	case PTRACE_READDATA:
    977		ret = ptrace_readdata(child, addr,
    978				      (char __user *)addr2, data);
    979		if (ret == data)
    980			ret = 0;
    981		else if (ret >= 0)
    982			ret = -EIO;
    983		break;
    984
    985	case PTRACE_WRITETEXT:
    986	case PTRACE_WRITEDATA:
    987		ret = ptrace_writedata(child, (char __user *) addr2,
    988				       addr, data);
    989		if (ret == data)
    990			ret = 0;
    991		else if (ret >= 0)
    992			ret = -EIO;
    993		break;
    994
    995	default:
    996		if (request == PTRACE_SPARC_DETACH)
    997			request = PTRACE_DETACH;
    998		ret = compat_ptrace_request(child, request, addr, data);
    999		break;
   1000	}
   1001
   1002	return ret;
   1003}
   1004#endif /* CONFIG_COMPAT */
   1005
   1006struct fps {
   1007	unsigned int regs[64];
   1008	unsigned long fsr;
   1009};
   1010
   1011long arch_ptrace(struct task_struct *child, long request,
   1012		 unsigned long addr, unsigned long data)
   1013{
   1014	const struct user_regset_view *view = task_user_regset_view(current);
   1015	unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
   1016	struct pt_regs __user *pregs;
   1017	struct fps __user *fps;
   1018	void __user *addr2p;
   1019	int ret;
   1020
   1021	pregs = (struct pt_regs __user *) addr;
   1022	fps = (struct fps __user *) addr;
   1023	addr2p = (void __user *) addr2;
   1024
   1025	switch (request) {
   1026	case PTRACE_PEEKUSR:
   1027		ret = (addr != 0) ? -EIO : 0;
   1028		break;
   1029
   1030	case PTRACE_GETREGS64:
   1031		ret = copy_regset_to_user(child, &ptrace64_view,
   1032					  REGSET_GENERAL, 0,
   1033					  19 * sizeof(u64),
   1034					  pregs);
   1035		break;
   1036
   1037	case PTRACE_SETREGS64:
   1038		ret = copy_regset_from_user(child, &ptrace64_view,
   1039					  REGSET_GENERAL, 0,
   1040					  19 * sizeof(u64),
   1041					  pregs);
   1042		break;
   1043
   1044	case PTRACE_GETFPREGS64:
   1045		ret = copy_regset_to_user(child, view, REGSET_FP,
   1046					  0 * sizeof(u64),
   1047					  33 * sizeof(u64),
   1048					  fps);
   1049		break;
   1050
   1051	case PTRACE_SETFPREGS64:
   1052		ret = copy_regset_from_user(child, view, REGSET_FP,
   1053					  0 * sizeof(u64),
   1054					  33 * sizeof(u64),
   1055					  fps);
   1056		break;
   1057
   1058	case PTRACE_READTEXT:
   1059	case PTRACE_READDATA:
   1060		ret = ptrace_readdata(child, addr, addr2p, data);
   1061		if (ret == data)
   1062			ret = 0;
   1063		else if (ret >= 0)
   1064			ret = -EIO;
   1065		break;
   1066
   1067	case PTRACE_WRITETEXT:
   1068	case PTRACE_WRITEDATA:
   1069		ret = ptrace_writedata(child, addr2p, addr, data);
   1070		if (ret == data)
   1071			ret = 0;
   1072		else if (ret >= 0)
   1073			ret = -EIO;
   1074		break;
   1075
   1076	default:
   1077		if (request == PTRACE_SPARC_DETACH)
   1078			request = PTRACE_DETACH;
   1079		ret = ptrace_request(child, request, addr, data);
   1080		break;
   1081	}
   1082
   1083	return ret;
   1084}
   1085
   1086asmlinkage int syscall_trace_enter(struct pt_regs *regs)
   1087{
   1088	int ret = 0;
   1089
   1090	/* do the secure computing check first */
   1091	secure_computing_strict(regs->u_regs[UREG_G1]);
   1092
   1093	if (test_thread_flag(TIF_NOHZ))
   1094		user_exit();
   1095
   1096	if (test_thread_flag(TIF_SYSCALL_TRACE))
   1097		ret = ptrace_report_syscall_entry(regs);
   1098
   1099	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
   1100		trace_sys_enter(regs, regs->u_regs[UREG_G1]);
   1101
   1102	audit_syscall_entry(regs->u_regs[UREG_G1], regs->u_regs[UREG_I0],
   1103			    regs->u_regs[UREG_I1], regs->u_regs[UREG_I2],
   1104			    regs->u_regs[UREG_I3]);
   1105
   1106	return ret;
   1107}
   1108
   1109asmlinkage void syscall_trace_leave(struct pt_regs *regs)
   1110{
   1111	if (test_thread_flag(TIF_NOHZ))
   1112		user_exit();
   1113
   1114	audit_syscall_exit(regs);
   1115
   1116	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
   1117		trace_sys_exit(regs, regs->u_regs[UREG_I0]);
   1118
   1119	if (test_thread_flag(TIF_SYSCALL_TRACE))
   1120		ptrace_report_syscall_exit(regs, 0);
   1121
   1122	if (test_thread_flag(TIF_NOHZ))
   1123		user_enter();
   1124}
   1125
   1126/**
   1127 * regs_query_register_offset() - query register offset from its name
   1128 * @name:	the name of a register
   1129 *
   1130 * regs_query_register_offset() returns the offset of a register in struct
   1131 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
   1132 */
   1133int regs_query_register_offset(const char *name)
   1134{
   1135	const struct pt_regs_offset *roff;
   1136
   1137	for (roff = regoffset_table; roff->name != NULL; roff++)
   1138		if (!strcmp(roff->name, name))
   1139			return roff->offset;
   1140	return -EINVAL;
   1141}
   1142
   1143/**
   1144 * regs_within_kernel_stack() - check the address in the stack
   1145 * @regs:	pt_regs which contains kernel stack pointer.
   1146 * @addr:	address which is checked.
   1147 *
   1148 * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
   1149 * If @addr is within the kernel stack, it returns true. If not, returns false.
   1150 */
   1151static inline int regs_within_kernel_stack(struct pt_regs *regs,
   1152					   unsigned long addr)
   1153{
   1154	unsigned long ksp = kernel_stack_pointer(regs) + STACK_BIAS;
   1155	return ((addr & ~(THREAD_SIZE - 1))  ==
   1156		(ksp & ~(THREAD_SIZE - 1)));
   1157}
   1158
   1159/**
   1160 * regs_get_kernel_stack_nth() - get Nth entry of the stack
   1161 * @regs:	pt_regs which contains kernel stack pointer.
   1162 * @n:		stack entry number.
   1163 *
   1164 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
   1165 * is specified by @regs. If the @n th entry is NOT in the kernel stack,
   1166 * this returns 0.
   1167 */
   1168unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
   1169{
   1170	unsigned long ksp = kernel_stack_pointer(regs) + STACK_BIAS;
   1171	unsigned long *addr = (unsigned long *)ksp;
   1172	addr += n;
   1173	if (regs_within_kernel_stack(regs, (unsigned long)addr))
   1174		return *addr;
   1175	else
   1176		return 0;
   1177}