| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | 
|---|
| 3 |  | - * | 
|---|
| 4 |  | - * This program is free software; you can redistribute it and/or modify | 
|---|
| 5 |  | - * it under the terms of the GNU General Public License version 2 as | 
|---|
| 6 |  | - * published by the Free Software Foundation. | 
|---|
| 7 | 4 | */ | 
|---|
| 8 | 5 |  | 
|---|
| 9 | 6 | #include <linux/ptrace.h> | 
|---|
| .. | .. | 
|---|
| 21 | 18 |  | 
|---|
| 22 | 19 | static int genregs_get(struct task_struct *target, | 
|---|
| 23 | 20 | const struct user_regset *regset, | 
|---|
| 24 |  | -		       unsigned int pos, unsigned int count, | 
|---|
| 25 |  | -		       void *kbuf, void __user *ubuf) | 
|---|
|  | 21 | +		       struct membuf to) | 
|---|
| 26 | 22 | { | 
|---|
| 27 | 23 | const struct pt_regs *ptregs = task_pt_regs(target); | 
|---|
| 28 | 24 | const struct callee_regs *cregs = task_callee_regs(target); | 
|---|
| 29 |  | -	int ret = 0; | 
|---|
| 30 | 25 | unsigned int stop_pc_val; | 
|---|
| 31 | 26 |  | 
|---|
| 32 |  | -#define REG_O_CHUNK(START, END, PTR)	\ | 
|---|
| 33 |  | -	if (!ret)	\ | 
|---|
| 34 |  | -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ | 
|---|
| 35 |  | -			offsetof(struct user_regs_struct, START), \ | 
|---|
| 36 |  | -			offsetof(struct user_regs_struct, END)); | 
|---|
|  | 27 | +	membuf_zero(&to, 4);	// pad | 
|---|
|  | 28 | +	membuf_store(&to, ptregs->bta); | 
|---|
|  | 29 | +	membuf_store(&to, ptregs->lp_start); | 
|---|
|  | 30 | +	membuf_store(&to, ptregs->lp_end); | 
|---|
|  | 31 | +	membuf_store(&to, ptregs->lp_count); | 
|---|
|  | 32 | +	membuf_store(&to, ptregs->status32); | 
|---|
|  | 33 | +	membuf_store(&to, ptregs->ret); | 
|---|
|  | 34 | +	membuf_store(&to, ptregs->blink); | 
|---|
|  | 35 | +	membuf_store(&to, ptregs->fp); | 
|---|
|  | 36 | +	membuf_store(&to, ptregs->r26);	// gp | 
|---|
|  | 37 | +	membuf_store(&to, ptregs->r12); | 
|---|
|  | 38 | +	membuf_store(&to, ptregs->r11); | 
|---|
|  | 39 | +	membuf_store(&to, ptregs->r10); | 
|---|
|  | 40 | +	membuf_store(&to, ptregs->r9); | 
|---|
|  | 41 | +	membuf_store(&to, ptregs->r8); | 
|---|
|  | 42 | +	membuf_store(&to, ptregs->r7); | 
|---|
|  | 43 | +	membuf_store(&to, ptregs->r6); | 
|---|
|  | 44 | +	membuf_store(&to, ptregs->r5); | 
|---|
|  | 45 | +	membuf_store(&to, ptregs->r4); | 
|---|
|  | 46 | +	membuf_store(&to, ptregs->r3); | 
|---|
|  | 47 | +	membuf_store(&to, ptregs->r2); | 
|---|
|  | 48 | +	membuf_store(&to, ptregs->r1); | 
|---|
|  | 49 | +	membuf_store(&to, ptregs->r0); | 
|---|
|  | 50 | +	membuf_store(&to, ptregs->sp); | 
|---|
|  | 51 | +	membuf_zero(&to, 4);	// pad2 | 
|---|
|  | 52 | +	membuf_store(&to, cregs->r25); | 
|---|
|  | 53 | +	membuf_store(&to, cregs->r24); | 
|---|
|  | 54 | +	membuf_store(&to, cregs->r23); | 
|---|
|  | 55 | +	membuf_store(&to, cregs->r22); | 
|---|
|  | 56 | +	membuf_store(&to, cregs->r21); | 
|---|
|  | 57 | +	membuf_store(&to, cregs->r20); | 
|---|
|  | 58 | +	membuf_store(&to, cregs->r19); | 
|---|
|  | 59 | +	membuf_store(&to, cregs->r18); | 
|---|
|  | 60 | +	membuf_store(&to, cregs->r17); | 
|---|
|  | 61 | +	membuf_store(&to, cregs->r16); | 
|---|
|  | 62 | +	membuf_store(&to, cregs->r15); | 
|---|
|  | 63 | +	membuf_store(&to, cregs->r14); | 
|---|
|  | 64 | +	membuf_store(&to, cregs->r13); | 
|---|
|  | 65 | +	membuf_store(&to, target->thread.fault_address); // efa | 
|---|
| 37 | 66 |  | 
|---|
| 38 |  | -#define REG_O_ONE(LOC, PTR)	\ | 
|---|
| 39 |  | -	if (!ret)		\ | 
|---|
| 40 |  | -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ | 
|---|
| 41 |  | -			offsetof(struct user_regs_struct, LOC), \ | 
|---|
| 42 |  | -			offsetof(struct user_regs_struct, LOC) + 4); | 
|---|
| 43 |  | - | 
|---|
| 44 |  | -#define REG_O_ZERO(LOC)		\ | 
|---|
| 45 |  | -	if (!ret)		\ | 
|---|
| 46 |  | -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ | 
|---|
| 47 |  | -			offsetof(struct user_regs_struct, LOC), \ | 
|---|
| 48 |  | -			offsetof(struct user_regs_struct, LOC) + 4); | 
|---|
| 49 |  | - | 
|---|
| 50 |  | -	REG_O_ZERO(pad); | 
|---|
| 51 |  | -	REG_O_ONE(scratch.bta, &ptregs->bta); | 
|---|
| 52 |  | -	REG_O_ONE(scratch.lp_start, &ptregs->lp_start); | 
|---|
| 53 |  | -	REG_O_ONE(scratch.lp_end, &ptregs->lp_end); | 
|---|
| 54 |  | -	REG_O_ONE(scratch.lp_count, &ptregs->lp_count); | 
|---|
| 55 |  | -	REG_O_ONE(scratch.status32, &ptregs->status32); | 
|---|
| 56 |  | -	REG_O_ONE(scratch.ret, &ptregs->ret); | 
|---|
| 57 |  | -	REG_O_ONE(scratch.blink, &ptregs->blink); | 
|---|
| 58 |  | -	REG_O_ONE(scratch.fp, &ptregs->fp); | 
|---|
| 59 |  | -	REG_O_ONE(scratch.gp, &ptregs->r26); | 
|---|
| 60 |  | -	REG_O_ONE(scratch.r12, &ptregs->r12); | 
|---|
| 61 |  | -	REG_O_ONE(scratch.r11, &ptregs->r11); | 
|---|
| 62 |  | -	REG_O_ONE(scratch.r10, &ptregs->r10); | 
|---|
| 63 |  | -	REG_O_ONE(scratch.r9, &ptregs->r9); | 
|---|
| 64 |  | -	REG_O_ONE(scratch.r8, &ptregs->r8); | 
|---|
| 65 |  | -	REG_O_ONE(scratch.r7, &ptregs->r7); | 
|---|
| 66 |  | -	REG_O_ONE(scratch.r6, &ptregs->r6); | 
|---|
| 67 |  | -	REG_O_ONE(scratch.r5, &ptregs->r5); | 
|---|
| 68 |  | -	REG_O_ONE(scratch.r4, &ptregs->r4); | 
|---|
| 69 |  | -	REG_O_ONE(scratch.r3, &ptregs->r3); | 
|---|
| 70 |  | -	REG_O_ONE(scratch.r2, &ptregs->r2); | 
|---|
| 71 |  | -	REG_O_ONE(scratch.r1, &ptregs->r1); | 
|---|
| 72 |  | -	REG_O_ONE(scratch.r0, &ptregs->r0); | 
|---|
| 73 |  | -	REG_O_ONE(scratch.sp, &ptregs->sp); | 
|---|
| 74 |  | - | 
|---|
| 75 |  | -	REG_O_ZERO(pad2); | 
|---|
| 76 |  | - | 
|---|
| 77 |  | -	REG_O_ONE(callee.r25, &cregs->r25); | 
|---|
| 78 |  | -	REG_O_ONE(callee.r24, &cregs->r24); | 
|---|
| 79 |  | -	REG_O_ONE(callee.r23, &cregs->r23); | 
|---|
| 80 |  | -	REG_O_ONE(callee.r22, &cregs->r22); | 
|---|
| 81 |  | -	REG_O_ONE(callee.r21, &cregs->r21); | 
|---|
| 82 |  | -	REG_O_ONE(callee.r20, &cregs->r20); | 
|---|
| 83 |  | -	REG_O_ONE(callee.r19, &cregs->r19); | 
|---|
| 84 |  | -	REG_O_ONE(callee.r18, &cregs->r18); | 
|---|
| 85 |  | -	REG_O_ONE(callee.r17, &cregs->r17); | 
|---|
| 86 |  | -	REG_O_ONE(callee.r16, &cregs->r16); | 
|---|
| 87 |  | -	REG_O_ONE(callee.r15, &cregs->r15); | 
|---|
| 88 |  | -	REG_O_ONE(callee.r14, &cregs->r14); | 
|---|
| 89 |  | -	REG_O_ONE(callee.r13, &cregs->r13); | 
|---|
| 90 |  | - | 
|---|
| 91 |  | -	REG_O_ONE(efa, &target->thread.fault_address); | 
|---|
| 92 |  | - | 
|---|
| 93 |  | -	if (!ret) { | 
|---|
| 94 |  | -		if (in_brkpt_trap(ptregs)) { | 
|---|
| 95 |  | -			stop_pc_val = target->thread.fault_address; | 
|---|
| 96 |  | -			pr_debug("\t\tstop_pc (brk-pt)\n"); | 
|---|
| 97 |  | -		} else { | 
|---|
| 98 |  | -			stop_pc_val = ptregs->ret; | 
|---|
| 99 |  | -			pr_debug("\t\tstop_pc (others)\n"); | 
|---|
| 100 |  | -		} | 
|---|
| 101 |  | - | 
|---|
| 102 |  | -		REG_O_ONE(stop_pc, &stop_pc_val); | 
|---|
|  | 67 | +	if (in_brkpt_trap(ptregs)) { | 
|---|
|  | 68 | +		stop_pc_val = target->thread.fault_address; | 
|---|
|  | 69 | +		pr_debug("\t\tstop_pc (brk-pt)\n"); | 
|---|
|  | 70 | +	} else { | 
|---|
|  | 71 | +		stop_pc_val = ptregs->ret; | 
|---|
|  | 72 | +		pr_debug("\t\tstop_pc (others)\n"); | 
|---|
| 103 | 73 | } | 
|---|
| 104 | 74 |  | 
|---|
| 105 |  | -	return ret; | 
|---|
|  | 75 | +	return membuf_store(&to, stop_pc_val); // stop_pc | 
|---|
| 106 | 76 | } | 
|---|
| 107 | 77 |  | 
|---|
| 108 | 78 | static int genregs_set(struct task_struct *target, | 
|---|
| .. | .. | 
|---|
| 187 | 157 | #ifdef CONFIG_ISA_ARCV2 | 
|---|
| 188 | 158 | static int arcv2regs_get(struct task_struct *target, | 
|---|
| 189 | 159 | const struct user_regset *regset, | 
|---|
| 190 |  | -		       unsigned int pos, unsigned int count, | 
|---|
| 191 |  | -		       void *kbuf, void __user *ubuf) | 
|---|
|  | 160 | +		       struct membuf to) | 
|---|
| 192 | 161 | { | 
|---|
| 193 | 162 | const struct pt_regs *regs = task_pt_regs(target); | 
|---|
| 194 |  | -	int ret, copy_sz; | 
|---|
| 195 | 163 |  | 
|---|
| 196 | 164 | if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS)) | 
|---|
| 197 |  | -		copy_sz = sizeof(struct user_regs_arcv2); | 
|---|
| 198 |  | -	else | 
|---|
| 199 |  | -		copy_sz = 4;	/* r30 only */ | 
|---|
|  | 165 | +		/* | 
|---|
|  | 166 | +		 * itemized copy not needed like above as layout of regs (r30,r58,r59) | 
|---|
|  | 167 | +		 * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2) | 
|---|
|  | 168 | +		 */ | 
|---|
|  | 169 | +		return membuf_write(&to, ®s->r30, sizeof(struct user_regs_arcv2)); | 
|---|
| 200 | 170 |  | 
|---|
| 201 |  | -	/* | 
|---|
| 202 |  | -	 * itemized copy not needed like above as layout of regs (r30,r58,r59) | 
|---|
| 203 |  | -	 * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2) | 
|---|
| 204 |  | -	 */ | 
|---|
| 205 |  | -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->r30, | 
|---|
| 206 |  | -				  0, copy_sz); | 
|---|
| 207 | 171 |  | 
|---|
| 208 |  | -	return ret; | 
|---|
|  | 172 | +	membuf_write(&to, ®s->r30, 4); /* r30 only */ | 
|---|
|  | 173 | +	return membuf_zero(&to, sizeof(struct user_regs_arcv2) - 4); | 
|---|
| 209 | 174 | } | 
|---|
| 210 | 175 |  | 
|---|
| 211 | 176 | static int arcv2regs_set(struct task_struct *target, | 
|---|
| .. | .. | 
|---|
| 240 | 205 | .n = ELF_NGREG, | 
|---|
| 241 | 206 | .size = sizeof(unsigned long), | 
|---|
| 242 | 207 | .align = sizeof(unsigned long), | 
|---|
| 243 |  | -	       .get = genregs_get, | 
|---|
|  | 208 | +	       .regset_get = genregs_get, | 
|---|
| 244 | 209 | .set = genregs_set, | 
|---|
| 245 | 210 | }, | 
|---|
| 246 | 211 | #ifdef CONFIG_ISA_ARCV2 | 
|---|
| .. | .. | 
|---|
| 249 | 214 | .n = ELF_ARCV2REG, | 
|---|
| 250 | 215 | .size = sizeof(unsigned long), | 
|---|
| 251 | 216 | .align = sizeof(unsigned long), | 
|---|
| 252 |  | -	       .get = arcv2regs_get, | 
|---|
|  | 217 | +	       .regset_get = arcv2regs_get, | 
|---|
| 253 | 218 | .set = arcv2regs_set, | 
|---|
| 254 | 219 | }, | 
|---|
| 255 | 220 | #endif | 
|---|
| 256 | 221 | }; | 
|---|
| 257 | 222 |  | 
|---|
| 258 | 223 | static const struct user_regset_view user_arc_view = { | 
|---|
| 259 |  | -	.name		= UTS_MACHINE, | 
|---|
|  | 224 | +	.name		= "arc", | 
|---|
| 260 | 225 | .e_machine	= EM_ARC_INUSE, | 
|---|
| 261 | 226 | .regsets	= arc_regsets, | 
|---|
| 262 | 227 | .n		= ARRAY_SIZE(arc_regsets) | 
|---|