~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/ptrace/ptrace-view.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php