1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun #include <linux/regset.h>
4*4882a593Smuzhiyun #include <linux/elf.h>
5*4882a593Smuzhiyun #include <linux/nospec.h>
6*4882a593Smuzhiyun #include <linux/pkeys.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "ptrace-decl.h"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun struct pt_regs_offset {
11*4882a593Smuzhiyun const char *name;
12*4882a593Smuzhiyun int offset;
13*4882a593Smuzhiyun };
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define STR(s) #s /* convert to string */
16*4882a593Smuzhiyun #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
17*4882a593Smuzhiyun #define GPR_OFFSET_NAME(num) \
18*4882a593Smuzhiyun {.name = STR(r##num), .offset = offsetof(struct pt_regs, gpr[num])}, \
19*4882a593Smuzhiyun {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])}
20*4882a593Smuzhiyun #define REG_OFFSET_END {.name = NULL, .offset = 0}
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const struct pt_regs_offset regoffset_table[] = {
23*4882a593Smuzhiyun GPR_OFFSET_NAME(0),
24*4882a593Smuzhiyun GPR_OFFSET_NAME(1),
25*4882a593Smuzhiyun GPR_OFFSET_NAME(2),
26*4882a593Smuzhiyun GPR_OFFSET_NAME(3),
27*4882a593Smuzhiyun GPR_OFFSET_NAME(4),
28*4882a593Smuzhiyun GPR_OFFSET_NAME(5),
29*4882a593Smuzhiyun GPR_OFFSET_NAME(6),
30*4882a593Smuzhiyun GPR_OFFSET_NAME(7),
31*4882a593Smuzhiyun GPR_OFFSET_NAME(8),
32*4882a593Smuzhiyun GPR_OFFSET_NAME(9),
33*4882a593Smuzhiyun GPR_OFFSET_NAME(10),
34*4882a593Smuzhiyun GPR_OFFSET_NAME(11),
35*4882a593Smuzhiyun GPR_OFFSET_NAME(12),
36*4882a593Smuzhiyun GPR_OFFSET_NAME(13),
37*4882a593Smuzhiyun GPR_OFFSET_NAME(14),
38*4882a593Smuzhiyun GPR_OFFSET_NAME(15),
39*4882a593Smuzhiyun GPR_OFFSET_NAME(16),
40*4882a593Smuzhiyun GPR_OFFSET_NAME(17),
41*4882a593Smuzhiyun GPR_OFFSET_NAME(18),
42*4882a593Smuzhiyun GPR_OFFSET_NAME(19),
43*4882a593Smuzhiyun GPR_OFFSET_NAME(20),
44*4882a593Smuzhiyun GPR_OFFSET_NAME(21),
45*4882a593Smuzhiyun GPR_OFFSET_NAME(22),
46*4882a593Smuzhiyun GPR_OFFSET_NAME(23),
47*4882a593Smuzhiyun GPR_OFFSET_NAME(24),
48*4882a593Smuzhiyun GPR_OFFSET_NAME(25),
49*4882a593Smuzhiyun GPR_OFFSET_NAME(26),
50*4882a593Smuzhiyun GPR_OFFSET_NAME(27),
51*4882a593Smuzhiyun GPR_OFFSET_NAME(28),
52*4882a593Smuzhiyun GPR_OFFSET_NAME(29),
53*4882a593Smuzhiyun GPR_OFFSET_NAME(30),
54*4882a593Smuzhiyun GPR_OFFSET_NAME(31),
55*4882a593Smuzhiyun REG_OFFSET_NAME(nip),
56*4882a593Smuzhiyun REG_OFFSET_NAME(msr),
57*4882a593Smuzhiyun REG_OFFSET_NAME(ctr),
58*4882a593Smuzhiyun REG_OFFSET_NAME(link),
59*4882a593Smuzhiyun REG_OFFSET_NAME(xer),
60*4882a593Smuzhiyun REG_OFFSET_NAME(ccr),
61*4882a593Smuzhiyun #ifdef CONFIG_PPC64
62*4882a593Smuzhiyun REG_OFFSET_NAME(softe),
63*4882a593Smuzhiyun #else
64*4882a593Smuzhiyun REG_OFFSET_NAME(mq),
65*4882a593Smuzhiyun #endif
66*4882a593Smuzhiyun REG_OFFSET_NAME(trap),
67*4882a593Smuzhiyun REG_OFFSET_NAME(dar),
68*4882a593Smuzhiyun REG_OFFSET_NAME(dsisr),
69*4882a593Smuzhiyun REG_OFFSET_END,
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /**
73*4882a593Smuzhiyun * regs_query_register_offset() - query register offset from its name
74*4882a593Smuzhiyun * @name: the name of a register
75*4882a593Smuzhiyun *
76*4882a593Smuzhiyun * regs_query_register_offset() returns the offset of a register in struct
77*4882a593Smuzhiyun * pt_regs from its name. If the name is invalid, this returns -EINVAL;
78*4882a593Smuzhiyun */
regs_query_register_offset(const char * name)79*4882a593Smuzhiyun int regs_query_register_offset(const char *name)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun const struct pt_regs_offset *roff;
82*4882a593Smuzhiyun for (roff = regoffset_table; roff->name != NULL; roff++)
83*4882a593Smuzhiyun if (!strcmp(roff->name, name))
84*4882a593Smuzhiyun return roff->offset;
85*4882a593Smuzhiyun return -EINVAL;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /**
89*4882a593Smuzhiyun * regs_query_register_name() - query register name from its offset
90*4882a593Smuzhiyun * @offset: the offset of a register in struct pt_regs.
91*4882a593Smuzhiyun *
92*4882a593Smuzhiyun * regs_query_register_name() returns the name of a register from its
93*4882a593Smuzhiyun * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
94*4882a593Smuzhiyun */
regs_query_register_name(unsigned int offset)95*4882a593Smuzhiyun const char *regs_query_register_name(unsigned int offset)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun const struct pt_regs_offset *roff;
98*4882a593Smuzhiyun for (roff = regoffset_table; roff->name != NULL; roff++)
99*4882a593Smuzhiyun if (roff->offset == offset)
100*4882a593Smuzhiyun return roff->name;
101*4882a593Smuzhiyun return NULL;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun * does not yet catch signals sent when the child dies.
106*4882a593Smuzhiyun * in exit.c or in signal.c.
107*4882a593Smuzhiyun */
108*4882a593Smuzhiyun
get_user_msr(struct task_struct * task)109*4882a593Smuzhiyun static unsigned long get_user_msr(struct task_struct *task)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun return task->thread.regs->msr | task->thread.fpexc_mode;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
set_user_msr(struct task_struct * task,unsigned long msr)114*4882a593Smuzhiyun static int set_user_msr(struct task_struct *task, unsigned long msr)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
117*4882a593Smuzhiyun task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
118*4882a593Smuzhiyun return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun #ifdef CONFIG_PPC64
get_user_dscr(struct task_struct * task,unsigned long * data)122*4882a593Smuzhiyun static int get_user_dscr(struct task_struct *task, unsigned long *data)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun *data = task->thread.dscr;
125*4882a593Smuzhiyun return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
set_user_dscr(struct task_struct * task,unsigned long dscr)128*4882a593Smuzhiyun static int set_user_dscr(struct task_struct *task, unsigned long dscr)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun task->thread.dscr = dscr;
131*4882a593Smuzhiyun task->thread.dscr_inherit = 1;
132*4882a593Smuzhiyun return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun #else
get_user_dscr(struct task_struct * task,unsigned long * data)135*4882a593Smuzhiyun static int get_user_dscr(struct task_struct *task, unsigned long *data)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun return -EIO;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
set_user_dscr(struct task_struct * task,unsigned long dscr)140*4882a593Smuzhiyun static int set_user_dscr(struct task_struct *task, unsigned long dscr)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun return -EIO;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun #endif
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun * We prevent mucking around with the reserved area of trap
148*4882a593Smuzhiyun * which are used internally by the kernel.
149*4882a593Smuzhiyun */
set_user_trap(struct task_struct * task,unsigned long trap)150*4882a593Smuzhiyun static int set_user_trap(struct task_struct *task, unsigned long trap)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun set_trap(task->thread.regs, trap);
153*4882a593Smuzhiyun return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun * Get contents of register REGNO in task TASK.
158*4882a593Smuzhiyun */
ptrace_get_reg(struct task_struct * task,int regno,unsigned long * data)159*4882a593Smuzhiyun int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun unsigned int regs_max;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (task->thread.regs == NULL || !data)
164*4882a593Smuzhiyun return -EIO;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (regno == PT_MSR) {
167*4882a593Smuzhiyun *data = get_user_msr(task);
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (regno == PT_DSCR)
172*4882a593Smuzhiyun return get_user_dscr(task, data);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun * softe copies paca->irq_soft_mask variable state. Since irq_soft_mask is
176*4882a593Smuzhiyun * no more used as a flag, lets force usr to alway see the softe value as 1
177*4882a593Smuzhiyun * which means interrupts are not soft disabled.
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_PPC64) && regno == PT_SOFTE) {
180*4882a593Smuzhiyun *data = 1;
181*4882a593Smuzhiyun return 0;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun regs_max = sizeof(struct user_pt_regs) / sizeof(unsigned long);
185*4882a593Smuzhiyun if (regno < regs_max) {
186*4882a593Smuzhiyun regno = array_index_nospec(regno, regs_max);
187*4882a593Smuzhiyun *data = ((unsigned long *)task->thread.regs)[regno];
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun return -EIO;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /*
195*4882a593Smuzhiyun * Write contents of register REGNO in task TASK.
196*4882a593Smuzhiyun */
ptrace_put_reg(struct task_struct * task,int regno,unsigned long data)197*4882a593Smuzhiyun int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun if (task->thread.regs == NULL)
200*4882a593Smuzhiyun return -EIO;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (regno == PT_MSR)
203*4882a593Smuzhiyun return set_user_msr(task, data);
204*4882a593Smuzhiyun if (regno == PT_TRAP)
205*4882a593Smuzhiyun return set_user_trap(task, data);
206*4882a593Smuzhiyun if (regno == PT_DSCR)
207*4882a593Smuzhiyun return set_user_dscr(task, data);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun if (regno <= PT_MAX_PUT_REG) {
210*4882a593Smuzhiyun regno = array_index_nospec(regno, PT_MAX_PUT_REG + 1);
211*4882a593Smuzhiyun ((unsigned long *)task->thread.regs)[regno] = data;
212*4882a593Smuzhiyun return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun return -EIO;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
gpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)217*4882a593Smuzhiyun static int gpr_get(struct task_struct *target, const struct user_regset *regset,
218*4882a593Smuzhiyun struct membuf to)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun int i;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (target->thread.regs == NULL)
223*4882a593Smuzhiyun return -EIO;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (!FULL_REGS(target->thread.regs)) {
226*4882a593Smuzhiyun /* We have a partial register set. Fill 14-31 with bogus values */
227*4882a593Smuzhiyun for (i = 14; i < 32; i++)
228*4882a593Smuzhiyun target->thread.regs->gpr[i] = NV_REG_POISON;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun membuf_write(&to, target->thread.regs, offsetof(struct pt_regs, msr));
232*4882a593Smuzhiyun membuf_store(&to, get_user_msr(target));
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
235*4882a593Smuzhiyun offsetof(struct pt_regs, msr) + sizeof(long));
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun membuf_write(&to, &target->thread.regs->orig_gpr3,
238*4882a593Smuzhiyun sizeof(struct user_pt_regs) -
239*4882a593Smuzhiyun offsetof(struct pt_regs, orig_gpr3));
240*4882a593Smuzhiyun return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
241*4882a593Smuzhiyun sizeof(struct user_pt_regs));
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
gpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)244*4882a593Smuzhiyun static int gpr_set(struct task_struct *target, const struct user_regset *regset,
245*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
246*4882a593Smuzhiyun const void __user *ubuf)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun unsigned long reg;
249*4882a593Smuzhiyun int ret;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (target->thread.regs == NULL)
252*4882a593Smuzhiyun return -EIO;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun CHECK_FULL_REGS(target->thread.regs);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
257*4882a593Smuzhiyun target->thread.regs,
258*4882a593Smuzhiyun 0, PT_MSR * sizeof(reg));
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (!ret && count > 0) {
261*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
262*4882a593Smuzhiyun PT_MSR * sizeof(reg),
263*4882a593Smuzhiyun (PT_MSR + 1) * sizeof(reg));
264*4882a593Smuzhiyun if (!ret)
265*4882a593Smuzhiyun ret = set_user_msr(target, reg);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
269*4882a593Smuzhiyun offsetof(struct pt_regs, msr) + sizeof(long));
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if (!ret)
272*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
273*4882a593Smuzhiyun &target->thread.regs->orig_gpr3,
274*4882a593Smuzhiyun PT_ORIG_R3 * sizeof(reg),
275*4882a593Smuzhiyun (PT_MAX_PUT_REG + 1) * sizeof(reg));
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
278*4882a593Smuzhiyun ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
279*4882a593Smuzhiyun (PT_MAX_PUT_REG + 1) * sizeof(reg),
280*4882a593Smuzhiyun PT_TRAP * sizeof(reg));
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (!ret && count > 0) {
283*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
284*4882a593Smuzhiyun PT_TRAP * sizeof(reg),
285*4882a593Smuzhiyun (PT_TRAP + 1) * sizeof(reg));
286*4882a593Smuzhiyun if (!ret)
287*4882a593Smuzhiyun ret = set_user_trap(target, reg);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (!ret)
291*4882a593Smuzhiyun ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
292*4882a593Smuzhiyun (PT_TRAP + 1) * sizeof(reg), -1);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun return ret;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun #ifdef CONFIG_PPC64
ppr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)298*4882a593Smuzhiyun static int ppr_get(struct task_struct *target, const struct user_regset *regset,
299*4882a593Smuzhiyun struct membuf to)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64));
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
ppr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)304*4882a593Smuzhiyun static int ppr_set(struct task_struct *target, const struct user_regset *regset,
305*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
306*4882a593Smuzhiyun const void __user *ubuf)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
309*4882a593Smuzhiyun &target->thread.regs->ppr, 0, sizeof(u64));
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
dscr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)312*4882a593Smuzhiyun static int dscr_get(struct task_struct *target, const struct user_regset *regset,
313*4882a593Smuzhiyun struct membuf to)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun return membuf_write(&to, &target->thread.dscr, sizeof(u64));
316*4882a593Smuzhiyun }
dscr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)317*4882a593Smuzhiyun static int dscr_set(struct task_struct *target, const struct user_regset *regset,
318*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
319*4882a593Smuzhiyun const void __user *ubuf)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
322*4882a593Smuzhiyun &target->thread.dscr, 0, sizeof(u64));
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun #endif
325*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
tar_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)326*4882a593Smuzhiyun static int tar_get(struct task_struct *target, const struct user_regset *regset,
327*4882a593Smuzhiyun struct membuf to)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun return membuf_write(&to, &target->thread.tar, sizeof(u64));
330*4882a593Smuzhiyun }
tar_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)331*4882a593Smuzhiyun static int tar_set(struct task_struct *target, const struct user_regset *regset,
332*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
333*4882a593Smuzhiyun const void __user *ubuf)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
336*4882a593Smuzhiyun &target->thread.tar, 0, sizeof(u64));
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
ebb_active(struct task_struct * target,const struct user_regset * regset)339*4882a593Smuzhiyun static int ebb_active(struct task_struct *target, const struct user_regset *regset)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
342*4882a593Smuzhiyun return -ENODEV;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (target->thread.used_ebb)
345*4882a593Smuzhiyun return regset->n;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
ebb_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)350*4882a593Smuzhiyun static int ebb_get(struct task_struct *target, const struct user_regset *regset,
351*4882a593Smuzhiyun struct membuf to)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun /* Build tests */
354*4882a593Smuzhiyun BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr));
355*4882a593Smuzhiyun BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr));
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
358*4882a593Smuzhiyun return -ENODEV;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun if (!target->thread.used_ebb)
361*4882a593Smuzhiyun return -ENODATA;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long));
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
ebb_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)366*4882a593Smuzhiyun static int ebb_set(struct task_struct *target, const struct user_regset *regset,
367*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
368*4882a593Smuzhiyun const void __user *ubuf)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun int ret = 0;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* Build tests */
373*4882a593Smuzhiyun BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr));
374*4882a593Smuzhiyun BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr));
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
377*4882a593Smuzhiyun return -ENODEV;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (target->thread.used_ebb)
380*4882a593Smuzhiyun return -ENODATA;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr,
383*4882a593Smuzhiyun 0, sizeof(unsigned long));
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (!ret)
386*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
387*4882a593Smuzhiyun &target->thread.ebbhr, sizeof(unsigned long),
388*4882a593Smuzhiyun 2 * sizeof(unsigned long));
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (!ret)
391*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
392*4882a593Smuzhiyun &target->thread.bescr, 2 * sizeof(unsigned long),
393*4882a593Smuzhiyun 3 * sizeof(unsigned long));
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun return ret;
396*4882a593Smuzhiyun }
pmu_active(struct task_struct * target,const struct user_regset * regset)397*4882a593Smuzhiyun static int pmu_active(struct task_struct *target, const struct user_regset *regset)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
400*4882a593Smuzhiyun return -ENODEV;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return regset->n;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
pmu_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)405*4882a593Smuzhiyun static int pmu_get(struct task_struct *target, const struct user_regset *regset,
406*4882a593Smuzhiyun struct membuf to)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun /* Build tests */
409*4882a593Smuzhiyun BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar));
410*4882a593Smuzhiyun BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier));
411*4882a593Smuzhiyun BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2));
412*4882a593Smuzhiyun BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0));
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
415*4882a593Smuzhiyun return -ENODEV;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long));
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
pmu_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)420*4882a593Smuzhiyun static int pmu_set(struct task_struct *target, const struct user_regset *regset,
421*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
422*4882a593Smuzhiyun const void __user *ubuf)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun int ret = 0;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Build tests */
427*4882a593Smuzhiyun BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar));
428*4882a593Smuzhiyun BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier));
429*4882a593Smuzhiyun BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2));
430*4882a593Smuzhiyun BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0));
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun if (!cpu_has_feature(CPU_FTR_ARCH_207S))
433*4882a593Smuzhiyun return -ENODEV;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.siar,
436*4882a593Smuzhiyun 0, sizeof(unsigned long));
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!ret)
439*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
440*4882a593Smuzhiyun &target->thread.sdar, sizeof(unsigned long),
441*4882a593Smuzhiyun 2 * sizeof(unsigned long));
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (!ret)
444*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
445*4882a593Smuzhiyun &target->thread.sier, 2 * sizeof(unsigned long),
446*4882a593Smuzhiyun 3 * sizeof(unsigned long));
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (!ret)
449*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
450*4882a593Smuzhiyun &target->thread.mmcr2, 3 * sizeof(unsigned long),
451*4882a593Smuzhiyun 4 * sizeof(unsigned long));
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (!ret)
454*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
455*4882a593Smuzhiyun &target->thread.mmcr0, 4 * sizeof(unsigned long),
456*4882a593Smuzhiyun 5 * sizeof(unsigned long));
457*4882a593Smuzhiyun return ret;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun #endif
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun #ifdef CONFIG_PPC_MEM_KEYS
pkey_active(struct task_struct * target,const struct user_regset * regset)462*4882a593Smuzhiyun static int pkey_active(struct task_struct *target, const struct user_regset *regset)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun if (!arch_pkeys_enabled())
465*4882a593Smuzhiyun return -ENODEV;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun return regset->n;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
pkey_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)470*4882a593Smuzhiyun static int pkey_get(struct task_struct *target, const struct user_regset *regset,
471*4882a593Smuzhiyun struct membuf to)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr));
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (!arch_pkeys_enabled())
476*4882a593Smuzhiyun return -ENODEV;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun membuf_write(&to, &target->thread.amr, 2 * sizeof(unsigned long));
479*4882a593Smuzhiyun return membuf_store(&to, default_uamor);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
pkey_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)482*4882a593Smuzhiyun static int pkey_set(struct task_struct *target, const struct user_regset *regset,
483*4882a593Smuzhiyun unsigned int pos, unsigned int count, const void *kbuf,
484*4882a593Smuzhiyun const void __user *ubuf)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun u64 new_amr;
487*4882a593Smuzhiyun int ret;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (!arch_pkeys_enabled())
490*4882a593Smuzhiyun return -ENODEV;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Only the AMR can be set from userspace */
493*4882a593Smuzhiyun if (pos != 0 || count != sizeof(new_amr))
494*4882a593Smuzhiyun return -EINVAL;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
497*4882a593Smuzhiyun &new_amr, 0, sizeof(new_amr));
498*4882a593Smuzhiyun if (ret)
499*4882a593Smuzhiyun return ret;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun /*
502*4882a593Smuzhiyun * UAMOR determines which bits of the AMR can be set from userspace.
503*4882a593Smuzhiyun * UAMOR value 0b11 indicates that the AMR value can be modified
504*4882a593Smuzhiyun * from userspace. If the kernel is using a specific key, we avoid
505*4882a593Smuzhiyun * userspace modifying the AMR value for that key by masking them
506*4882a593Smuzhiyun * via UAMOR 0b00.
507*4882a593Smuzhiyun *
508*4882a593Smuzhiyun * Pick the AMR values for the keys that kernel is using. This
509*4882a593Smuzhiyun * will be indicated by the ~default_uamor bits.
510*4882a593Smuzhiyun */
511*4882a593Smuzhiyun target->thread.amr = (new_amr & default_uamor) | (target->thread.amr & ~default_uamor);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun return 0;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun #endif /* CONFIG_PPC_MEM_KEYS */
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun static const struct user_regset native_regsets[] = {
518*4882a593Smuzhiyun [REGSET_GPR] = {
519*4882a593Smuzhiyun .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
520*4882a593Smuzhiyun .size = sizeof(long), .align = sizeof(long),
521*4882a593Smuzhiyun .regset_get = gpr_get, .set = gpr_set
522*4882a593Smuzhiyun },
523*4882a593Smuzhiyun [REGSET_FPR] = {
524*4882a593Smuzhiyun .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
525*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
526*4882a593Smuzhiyun .regset_get = fpr_get, .set = fpr_set
527*4882a593Smuzhiyun },
528*4882a593Smuzhiyun #ifdef CONFIG_ALTIVEC
529*4882a593Smuzhiyun [REGSET_VMX] = {
530*4882a593Smuzhiyun .core_note_type = NT_PPC_VMX, .n = 34,
531*4882a593Smuzhiyun .size = sizeof(vector128), .align = sizeof(vector128),
532*4882a593Smuzhiyun .active = vr_active, .regset_get = vr_get, .set = vr_set
533*4882a593Smuzhiyun },
534*4882a593Smuzhiyun #endif
535*4882a593Smuzhiyun #ifdef CONFIG_VSX
536*4882a593Smuzhiyun [REGSET_VSX] = {
537*4882a593Smuzhiyun .core_note_type = NT_PPC_VSX, .n = 32,
538*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
539*4882a593Smuzhiyun .active = vsr_active, .regset_get = vsr_get, .set = vsr_set
540*4882a593Smuzhiyun },
541*4882a593Smuzhiyun #endif
542*4882a593Smuzhiyun #ifdef CONFIG_SPE
543*4882a593Smuzhiyun [REGSET_SPE] = {
544*4882a593Smuzhiyun .core_note_type = NT_PPC_SPE, .n = 35,
545*4882a593Smuzhiyun .size = sizeof(u32), .align = sizeof(u32),
546*4882a593Smuzhiyun .active = evr_active, .regset_get = evr_get, .set = evr_set
547*4882a593Smuzhiyun },
548*4882a593Smuzhiyun #endif
549*4882a593Smuzhiyun #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
550*4882a593Smuzhiyun [REGSET_TM_CGPR] = {
551*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
552*4882a593Smuzhiyun .size = sizeof(long), .align = sizeof(long),
553*4882a593Smuzhiyun .active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set
554*4882a593Smuzhiyun },
555*4882a593Smuzhiyun [REGSET_TM_CFPR] = {
556*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
557*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
558*4882a593Smuzhiyun .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set
559*4882a593Smuzhiyun },
560*4882a593Smuzhiyun [REGSET_TM_CVMX] = {
561*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
562*4882a593Smuzhiyun .size = sizeof(vector128), .align = sizeof(vector128),
563*4882a593Smuzhiyun .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set
564*4882a593Smuzhiyun },
565*4882a593Smuzhiyun [REGSET_TM_CVSX] = {
566*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
567*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
568*4882a593Smuzhiyun .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set
569*4882a593Smuzhiyun },
570*4882a593Smuzhiyun [REGSET_TM_SPR] = {
571*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
572*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
573*4882a593Smuzhiyun .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set
574*4882a593Smuzhiyun },
575*4882a593Smuzhiyun [REGSET_TM_CTAR] = {
576*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CTAR, .n = 1,
577*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
578*4882a593Smuzhiyun .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set
579*4882a593Smuzhiyun },
580*4882a593Smuzhiyun [REGSET_TM_CPPR] = {
581*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CPPR, .n = 1,
582*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
583*4882a593Smuzhiyun .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set
584*4882a593Smuzhiyun },
585*4882a593Smuzhiyun [REGSET_TM_CDSCR] = {
586*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
587*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
588*4882a593Smuzhiyun .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set
589*4882a593Smuzhiyun },
590*4882a593Smuzhiyun #endif
591*4882a593Smuzhiyun #ifdef CONFIG_PPC64
592*4882a593Smuzhiyun [REGSET_PPR] = {
593*4882a593Smuzhiyun .core_note_type = NT_PPC_PPR, .n = 1,
594*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
595*4882a593Smuzhiyun .regset_get = ppr_get, .set = ppr_set
596*4882a593Smuzhiyun },
597*4882a593Smuzhiyun [REGSET_DSCR] = {
598*4882a593Smuzhiyun .core_note_type = NT_PPC_DSCR, .n = 1,
599*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
600*4882a593Smuzhiyun .regset_get = dscr_get, .set = dscr_set
601*4882a593Smuzhiyun },
602*4882a593Smuzhiyun #endif
603*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
604*4882a593Smuzhiyun [REGSET_TAR] = {
605*4882a593Smuzhiyun .core_note_type = NT_PPC_TAR, .n = 1,
606*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
607*4882a593Smuzhiyun .regset_get = tar_get, .set = tar_set
608*4882a593Smuzhiyun },
609*4882a593Smuzhiyun [REGSET_EBB] = {
610*4882a593Smuzhiyun .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
611*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
612*4882a593Smuzhiyun .active = ebb_active, .regset_get = ebb_get, .set = ebb_set
613*4882a593Smuzhiyun },
614*4882a593Smuzhiyun [REGSET_PMR] = {
615*4882a593Smuzhiyun .core_note_type = NT_PPC_PMU, .n = ELF_NPMU,
616*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
617*4882a593Smuzhiyun .active = pmu_active, .regset_get = pmu_get, .set = pmu_set
618*4882a593Smuzhiyun },
619*4882a593Smuzhiyun #endif
620*4882a593Smuzhiyun #ifdef CONFIG_PPC_MEM_KEYS
621*4882a593Smuzhiyun [REGSET_PKEY] = {
622*4882a593Smuzhiyun .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,
623*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
624*4882a593Smuzhiyun .active = pkey_active, .regset_get = pkey_get, .set = pkey_set
625*4882a593Smuzhiyun },
626*4882a593Smuzhiyun #endif
627*4882a593Smuzhiyun };
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun const struct user_regset_view user_ppc_native_view = {
630*4882a593Smuzhiyun .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
631*4882a593Smuzhiyun .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
632*4882a593Smuzhiyun };
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun #include <linux/compat.h>
635*4882a593Smuzhiyun
gpr32_get_common(struct task_struct * target,const struct user_regset * regset,struct membuf to,unsigned long * regs)636*4882a593Smuzhiyun int gpr32_get_common(struct task_struct *target,
637*4882a593Smuzhiyun const struct user_regset *regset,
638*4882a593Smuzhiyun struct membuf to, unsigned long *regs)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun int i;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun for (i = 0; i < PT_MSR; i++)
643*4882a593Smuzhiyun membuf_store(&to, (u32)regs[i]);
644*4882a593Smuzhiyun membuf_store(&to, (u32)get_user_msr(target));
645*4882a593Smuzhiyun for (i++ ; i < PT_REGS_COUNT; i++)
646*4882a593Smuzhiyun membuf_store(&to, (u32)regs[i]);
647*4882a593Smuzhiyun return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32));
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
gpr32_set_common(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf,unsigned long * regs)650*4882a593Smuzhiyun int gpr32_set_common(struct task_struct *target,
651*4882a593Smuzhiyun const struct user_regset *regset,
652*4882a593Smuzhiyun unsigned int pos, unsigned int count,
653*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf,
654*4882a593Smuzhiyun unsigned long *regs)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun const compat_ulong_t *k = kbuf;
657*4882a593Smuzhiyun const compat_ulong_t __user *u = ubuf;
658*4882a593Smuzhiyun compat_ulong_t reg;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun pos /= sizeof(reg);
661*4882a593Smuzhiyun count /= sizeof(reg);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if (kbuf)
664*4882a593Smuzhiyun for (; count > 0 && pos < PT_MSR; --count)
665*4882a593Smuzhiyun regs[pos++] = *k++;
666*4882a593Smuzhiyun else
667*4882a593Smuzhiyun for (; count > 0 && pos < PT_MSR; --count) {
668*4882a593Smuzhiyun if (__get_user(reg, u++))
669*4882a593Smuzhiyun return -EFAULT;
670*4882a593Smuzhiyun regs[pos++] = reg;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun if (count > 0 && pos == PT_MSR) {
675*4882a593Smuzhiyun if (kbuf)
676*4882a593Smuzhiyun reg = *k++;
677*4882a593Smuzhiyun else if (__get_user(reg, u++))
678*4882a593Smuzhiyun return -EFAULT;
679*4882a593Smuzhiyun set_user_msr(target, reg);
680*4882a593Smuzhiyun ++pos;
681*4882a593Smuzhiyun --count;
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (kbuf) {
685*4882a593Smuzhiyun for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
686*4882a593Smuzhiyun regs[pos++] = *k++;
687*4882a593Smuzhiyun for (; count > 0 && pos < PT_TRAP; --count, ++pos)
688*4882a593Smuzhiyun ++k;
689*4882a593Smuzhiyun } else {
690*4882a593Smuzhiyun for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
691*4882a593Smuzhiyun if (__get_user(reg, u++))
692*4882a593Smuzhiyun return -EFAULT;
693*4882a593Smuzhiyun regs[pos++] = reg;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun for (; count > 0 && pos < PT_TRAP; --count, ++pos)
696*4882a593Smuzhiyun if (__get_user(reg, u++))
697*4882a593Smuzhiyun return -EFAULT;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun if (count > 0 && pos == PT_TRAP) {
701*4882a593Smuzhiyun if (kbuf)
702*4882a593Smuzhiyun reg = *k++;
703*4882a593Smuzhiyun else if (__get_user(reg, u++))
704*4882a593Smuzhiyun return -EFAULT;
705*4882a593Smuzhiyun set_user_trap(target, reg);
706*4882a593Smuzhiyun ++pos;
707*4882a593Smuzhiyun --count;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun kbuf = k;
711*4882a593Smuzhiyun ubuf = u;
712*4882a593Smuzhiyun pos *= sizeof(reg);
713*4882a593Smuzhiyun count *= sizeof(reg);
714*4882a593Smuzhiyun return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
715*4882a593Smuzhiyun (PT_TRAP + 1) * sizeof(reg), -1);
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun
gpr32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)718*4882a593Smuzhiyun static int gpr32_get(struct task_struct *target,
719*4882a593Smuzhiyun const struct user_regset *regset,
720*4882a593Smuzhiyun struct membuf to)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun int i;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun if (target->thread.regs == NULL)
725*4882a593Smuzhiyun return -EIO;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun if (!FULL_REGS(target->thread.regs)) {
728*4882a593Smuzhiyun /*
729*4882a593Smuzhiyun * We have a partial register set.
730*4882a593Smuzhiyun * Fill 14-31 with bogus values.
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun for (i = 14; i < 32; i++)
733*4882a593Smuzhiyun target->thread.regs->gpr[i] = NV_REG_POISON;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun return gpr32_get_common(target, regset, to,
736*4882a593Smuzhiyun &target->thread.regs->gpr[0]);
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun
gpr32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)739*4882a593Smuzhiyun static int gpr32_set(struct task_struct *target,
740*4882a593Smuzhiyun const struct user_regset *regset,
741*4882a593Smuzhiyun unsigned int pos, unsigned int count,
742*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun if (target->thread.regs == NULL)
745*4882a593Smuzhiyun return -EIO;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun CHECK_FULL_REGS(target->thread.regs);
748*4882a593Smuzhiyun return gpr32_set_common(target, regset, pos, count, kbuf, ubuf,
749*4882a593Smuzhiyun &target->thread.regs->gpr[0]);
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun /*
753*4882a593Smuzhiyun * These are the regset flavors matching the CONFIG_PPC32 native set.
754*4882a593Smuzhiyun */
755*4882a593Smuzhiyun static const struct user_regset compat_regsets[] = {
756*4882a593Smuzhiyun [REGSET_GPR] = {
757*4882a593Smuzhiyun .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
758*4882a593Smuzhiyun .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
759*4882a593Smuzhiyun .regset_get = gpr32_get, .set = gpr32_set
760*4882a593Smuzhiyun },
761*4882a593Smuzhiyun [REGSET_FPR] = {
762*4882a593Smuzhiyun .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
763*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
764*4882a593Smuzhiyun .regset_get = fpr_get, .set = fpr_set
765*4882a593Smuzhiyun },
766*4882a593Smuzhiyun #ifdef CONFIG_ALTIVEC
767*4882a593Smuzhiyun [REGSET_VMX] = {
768*4882a593Smuzhiyun .core_note_type = NT_PPC_VMX, .n = 34,
769*4882a593Smuzhiyun .size = sizeof(vector128), .align = sizeof(vector128),
770*4882a593Smuzhiyun .active = vr_active, .regset_get = vr_get, .set = vr_set
771*4882a593Smuzhiyun },
772*4882a593Smuzhiyun #endif
773*4882a593Smuzhiyun #ifdef CONFIG_SPE
774*4882a593Smuzhiyun [REGSET_SPE] = {
775*4882a593Smuzhiyun .core_note_type = NT_PPC_SPE, .n = 35,
776*4882a593Smuzhiyun .size = sizeof(u32), .align = sizeof(u32),
777*4882a593Smuzhiyun .active = evr_active, .regset_get = evr_get, .set = evr_set
778*4882a593Smuzhiyun },
779*4882a593Smuzhiyun #endif
780*4882a593Smuzhiyun #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
781*4882a593Smuzhiyun [REGSET_TM_CGPR] = {
782*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
783*4882a593Smuzhiyun .size = sizeof(long), .align = sizeof(long),
784*4882a593Smuzhiyun .active = tm_cgpr_active,
785*4882a593Smuzhiyun .regset_get = tm_cgpr32_get, .set = tm_cgpr32_set
786*4882a593Smuzhiyun },
787*4882a593Smuzhiyun [REGSET_TM_CFPR] = {
788*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
789*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
790*4882a593Smuzhiyun .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set
791*4882a593Smuzhiyun },
792*4882a593Smuzhiyun [REGSET_TM_CVMX] = {
793*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
794*4882a593Smuzhiyun .size = sizeof(vector128), .align = sizeof(vector128),
795*4882a593Smuzhiyun .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set
796*4882a593Smuzhiyun },
797*4882a593Smuzhiyun [REGSET_TM_CVSX] = {
798*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
799*4882a593Smuzhiyun .size = sizeof(double), .align = sizeof(double),
800*4882a593Smuzhiyun .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set
801*4882a593Smuzhiyun },
802*4882a593Smuzhiyun [REGSET_TM_SPR] = {
803*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
804*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
805*4882a593Smuzhiyun .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set
806*4882a593Smuzhiyun },
807*4882a593Smuzhiyun [REGSET_TM_CTAR] = {
808*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CTAR, .n = 1,
809*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
810*4882a593Smuzhiyun .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set
811*4882a593Smuzhiyun },
812*4882a593Smuzhiyun [REGSET_TM_CPPR] = {
813*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CPPR, .n = 1,
814*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
815*4882a593Smuzhiyun .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set
816*4882a593Smuzhiyun },
817*4882a593Smuzhiyun [REGSET_TM_CDSCR] = {
818*4882a593Smuzhiyun .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
819*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
820*4882a593Smuzhiyun .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set
821*4882a593Smuzhiyun },
822*4882a593Smuzhiyun #endif
823*4882a593Smuzhiyun #ifdef CONFIG_PPC64
824*4882a593Smuzhiyun [REGSET_PPR] = {
825*4882a593Smuzhiyun .core_note_type = NT_PPC_PPR, .n = 1,
826*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
827*4882a593Smuzhiyun .regset_get = ppr_get, .set = ppr_set
828*4882a593Smuzhiyun },
829*4882a593Smuzhiyun [REGSET_DSCR] = {
830*4882a593Smuzhiyun .core_note_type = NT_PPC_DSCR, .n = 1,
831*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
832*4882a593Smuzhiyun .regset_get = dscr_get, .set = dscr_set
833*4882a593Smuzhiyun },
834*4882a593Smuzhiyun #endif
835*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
836*4882a593Smuzhiyun [REGSET_TAR] = {
837*4882a593Smuzhiyun .core_note_type = NT_PPC_TAR, .n = 1,
838*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
839*4882a593Smuzhiyun .regset_get = tar_get, .set = tar_set
840*4882a593Smuzhiyun },
841*4882a593Smuzhiyun [REGSET_EBB] = {
842*4882a593Smuzhiyun .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
843*4882a593Smuzhiyun .size = sizeof(u64), .align = sizeof(u64),
844*4882a593Smuzhiyun .active = ebb_active, .regset_get = ebb_get, .set = ebb_set
845*4882a593Smuzhiyun },
846*4882a593Smuzhiyun #endif
847*4882a593Smuzhiyun };
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun static const struct user_regset_view user_ppc_compat_view = {
850*4882a593Smuzhiyun .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
851*4882a593Smuzhiyun .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun
task_user_regset_view(struct task_struct * task)854*4882a593Smuzhiyun const struct user_regset_view *task_user_regset_view(struct task_struct *task)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_PPC64) && test_tsk_thread_flag(task, TIF_32BIT))
857*4882a593Smuzhiyun return &user_ppc_compat_view;
858*4882a593Smuzhiyun return &user_ppc_native_view;
859*4882a593Smuzhiyun }
860