16e0b7975SChristophe Leroy // SPDX-License-Identifier: GPL-2.0-or-later 26e0b7975SChristophe Leroy 36e0b7975SChristophe Leroy #include <linux/regset.h> 46e0b7975SChristophe Leroy #include <linux/elf.h> 56e0b7975SChristophe Leroy #include <linux/nospec.h> 66e0b7975SChristophe Leroy #include <linux/pkeys.h> 76e0b7975SChristophe Leroy 86e0b7975SChristophe Leroy #include "ptrace-decl.h" 96e0b7975SChristophe Leroy 106e0b7975SChristophe Leroy struct pt_regs_offset { 116e0b7975SChristophe Leroy const char *name; 126e0b7975SChristophe Leroy int offset; 136e0b7975SChristophe Leroy }; 146e0b7975SChristophe Leroy 156e0b7975SChristophe Leroy #define STR(s) #s /* convert to string */ 166e0b7975SChristophe Leroy #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} 176e0b7975SChristophe Leroy #define GPR_OFFSET_NAME(num) \ 186e0b7975SChristophe Leroy {.name = STR(r##num), .offset = offsetof(struct pt_regs, gpr[num])}, \ 196e0b7975SChristophe Leroy {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])} 206e0b7975SChristophe Leroy #define REG_OFFSET_END {.name = NULL, .offset = 0} 216e0b7975SChristophe Leroy 226e0b7975SChristophe Leroy static const struct pt_regs_offset regoffset_table[] = { 236e0b7975SChristophe Leroy GPR_OFFSET_NAME(0), 246e0b7975SChristophe Leroy GPR_OFFSET_NAME(1), 256e0b7975SChristophe Leroy GPR_OFFSET_NAME(2), 266e0b7975SChristophe Leroy GPR_OFFSET_NAME(3), 276e0b7975SChristophe Leroy GPR_OFFSET_NAME(4), 286e0b7975SChristophe Leroy GPR_OFFSET_NAME(5), 296e0b7975SChristophe Leroy GPR_OFFSET_NAME(6), 306e0b7975SChristophe Leroy GPR_OFFSET_NAME(7), 316e0b7975SChristophe Leroy GPR_OFFSET_NAME(8), 326e0b7975SChristophe Leroy GPR_OFFSET_NAME(9), 336e0b7975SChristophe Leroy GPR_OFFSET_NAME(10), 346e0b7975SChristophe Leroy GPR_OFFSET_NAME(11), 356e0b7975SChristophe Leroy GPR_OFFSET_NAME(12), 366e0b7975SChristophe Leroy GPR_OFFSET_NAME(13), 376e0b7975SChristophe Leroy GPR_OFFSET_NAME(14), 386e0b7975SChristophe Leroy GPR_OFFSET_NAME(15), 396e0b7975SChristophe Leroy GPR_OFFSET_NAME(16), 406e0b7975SChristophe Leroy GPR_OFFSET_NAME(17), 416e0b7975SChristophe Leroy GPR_OFFSET_NAME(18), 426e0b7975SChristophe Leroy GPR_OFFSET_NAME(19), 436e0b7975SChristophe Leroy GPR_OFFSET_NAME(20), 446e0b7975SChristophe Leroy GPR_OFFSET_NAME(21), 456e0b7975SChristophe Leroy GPR_OFFSET_NAME(22), 466e0b7975SChristophe Leroy GPR_OFFSET_NAME(23), 476e0b7975SChristophe Leroy GPR_OFFSET_NAME(24), 486e0b7975SChristophe Leroy GPR_OFFSET_NAME(25), 496e0b7975SChristophe Leroy GPR_OFFSET_NAME(26), 506e0b7975SChristophe Leroy GPR_OFFSET_NAME(27), 516e0b7975SChristophe Leroy GPR_OFFSET_NAME(28), 526e0b7975SChristophe Leroy GPR_OFFSET_NAME(29), 536e0b7975SChristophe Leroy GPR_OFFSET_NAME(30), 546e0b7975SChristophe Leroy GPR_OFFSET_NAME(31), 556e0b7975SChristophe Leroy REG_OFFSET_NAME(nip), 566e0b7975SChristophe Leroy REG_OFFSET_NAME(msr), 576e0b7975SChristophe Leroy REG_OFFSET_NAME(ctr), 586e0b7975SChristophe Leroy REG_OFFSET_NAME(link), 596e0b7975SChristophe Leroy REG_OFFSET_NAME(xer), 606e0b7975SChristophe Leroy REG_OFFSET_NAME(ccr), 616e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 626e0b7975SChristophe Leroy REG_OFFSET_NAME(softe), 636e0b7975SChristophe Leroy #else 646e0b7975SChristophe Leroy REG_OFFSET_NAME(mq), 656e0b7975SChristophe Leroy #endif 666e0b7975SChristophe Leroy REG_OFFSET_NAME(trap), 676e0b7975SChristophe Leroy REG_OFFSET_NAME(dar), 686e0b7975SChristophe Leroy REG_OFFSET_NAME(dsisr), 696e0b7975SChristophe Leroy REG_OFFSET_END, 706e0b7975SChristophe Leroy }; 716e0b7975SChristophe Leroy 726e0b7975SChristophe Leroy /** 736e0b7975SChristophe Leroy * regs_query_register_offset() - query register offset from its name 746e0b7975SChristophe Leroy * @name: the name of a register 756e0b7975SChristophe Leroy * 766e0b7975SChristophe Leroy * regs_query_register_offset() returns the offset of a register in struct 776e0b7975SChristophe Leroy * pt_regs from its name. If the name is invalid, this returns -EINVAL; 786e0b7975SChristophe Leroy */ 796e0b7975SChristophe Leroy int regs_query_register_offset(const char *name) 806e0b7975SChristophe Leroy { 816e0b7975SChristophe Leroy const struct pt_regs_offset *roff; 826e0b7975SChristophe Leroy for (roff = regoffset_table; roff->name != NULL; roff++) 836e0b7975SChristophe Leroy if (!strcmp(roff->name, name)) 846e0b7975SChristophe Leroy return roff->offset; 856e0b7975SChristophe Leroy return -EINVAL; 866e0b7975SChristophe Leroy } 876e0b7975SChristophe Leroy 886e0b7975SChristophe Leroy /** 896e0b7975SChristophe Leroy * regs_query_register_name() - query register name from its offset 906e0b7975SChristophe Leroy * @offset: the offset of a register in struct pt_regs. 916e0b7975SChristophe Leroy * 926e0b7975SChristophe Leroy * regs_query_register_name() returns the name of a register from its 936e0b7975SChristophe Leroy * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 946e0b7975SChristophe Leroy */ 956e0b7975SChristophe Leroy const char *regs_query_register_name(unsigned int offset) 966e0b7975SChristophe Leroy { 976e0b7975SChristophe Leroy const struct pt_regs_offset *roff; 986e0b7975SChristophe Leroy for (roff = regoffset_table; roff->name != NULL; roff++) 996e0b7975SChristophe Leroy if (roff->offset == offset) 1006e0b7975SChristophe Leroy return roff->name; 1016e0b7975SChristophe Leroy return NULL; 1026e0b7975SChristophe Leroy } 1036e0b7975SChristophe Leroy 1046e0b7975SChristophe Leroy /* 1056e0b7975SChristophe Leroy * does not yet catch signals sent when the child dies. 1066e0b7975SChristophe Leroy * in exit.c or in signal.c. 1076e0b7975SChristophe Leroy */ 1086e0b7975SChristophe Leroy 1096e0b7975SChristophe Leroy static unsigned long get_user_msr(struct task_struct *task) 1106e0b7975SChristophe Leroy { 1116e0b7975SChristophe Leroy return task->thread.regs->msr | task->thread.fpexc_mode; 1126e0b7975SChristophe Leroy } 1136e0b7975SChristophe Leroy 11493c043e3SChristophe Leroy static __always_inline int set_user_msr(struct task_struct *task, unsigned long msr) 1156e0b7975SChristophe Leroy { 116*59dc5bfcSNicholas Piggin unsigned long newmsr = (task->thread.regs->msr & ~MSR_DEBUGCHANGE) | 117*59dc5bfcSNicholas Piggin (msr & MSR_DEBUGCHANGE); 118*59dc5bfcSNicholas Piggin regs_set_return_msr(task->thread.regs, newmsr); 1196e0b7975SChristophe Leroy return 0; 1206e0b7975SChristophe Leroy } 1216e0b7975SChristophe Leroy 1226e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 1236e0b7975SChristophe Leroy static int get_user_dscr(struct task_struct *task, unsigned long *data) 1246e0b7975SChristophe Leroy { 1256e0b7975SChristophe Leroy *data = task->thread.dscr; 1266e0b7975SChristophe Leroy return 0; 1276e0b7975SChristophe Leroy } 1286e0b7975SChristophe Leroy 1296e0b7975SChristophe Leroy static int set_user_dscr(struct task_struct *task, unsigned long dscr) 1306e0b7975SChristophe Leroy { 1316e0b7975SChristophe Leroy task->thread.dscr = dscr; 1326e0b7975SChristophe Leroy task->thread.dscr_inherit = 1; 1336e0b7975SChristophe Leroy return 0; 1346e0b7975SChristophe Leroy } 1356e0b7975SChristophe Leroy #else 1366e0b7975SChristophe Leroy static int get_user_dscr(struct task_struct *task, unsigned long *data) 1376e0b7975SChristophe Leroy { 1386e0b7975SChristophe Leroy return -EIO; 1396e0b7975SChristophe Leroy } 1406e0b7975SChristophe Leroy 1416e0b7975SChristophe Leroy static int set_user_dscr(struct task_struct *task, unsigned long dscr) 1426e0b7975SChristophe Leroy { 1436e0b7975SChristophe Leroy return -EIO; 1446e0b7975SChristophe Leroy } 1456e0b7975SChristophe Leroy #endif 1466e0b7975SChristophe Leroy 1476e0b7975SChristophe Leroy /* 1486e0b7975SChristophe Leroy * We prevent mucking around with the reserved area of trap 1496e0b7975SChristophe Leroy * which are used internally by the kernel. 1506e0b7975SChristophe Leroy */ 15193c043e3SChristophe Leroy static __always_inline int set_user_trap(struct task_struct *task, unsigned long trap) 1526e0b7975SChristophe Leroy { 153db30144bSNicholas Piggin set_trap(task->thread.regs, trap); 1546e0b7975SChristophe Leroy return 0; 1556e0b7975SChristophe Leroy } 1566e0b7975SChristophe Leroy 1576e0b7975SChristophe Leroy /* 1586e0b7975SChristophe Leroy * Get contents of register REGNO in task TASK. 1596e0b7975SChristophe Leroy */ 1606e0b7975SChristophe Leroy int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data) 1616e0b7975SChristophe Leroy { 1626e0b7975SChristophe Leroy unsigned int regs_max; 1636e0b7975SChristophe Leroy 1646e0b7975SChristophe Leroy if (task->thread.regs == NULL || !data) 1656e0b7975SChristophe Leroy return -EIO; 1666e0b7975SChristophe Leroy 1676e0b7975SChristophe Leroy if (regno == PT_MSR) { 1686e0b7975SChristophe Leroy *data = get_user_msr(task); 1696e0b7975SChristophe Leroy return 0; 1706e0b7975SChristophe Leroy } 1716e0b7975SChristophe Leroy 1726e0b7975SChristophe Leroy if (regno == PT_DSCR) 1736e0b7975SChristophe Leroy return get_user_dscr(task, data); 1746e0b7975SChristophe Leroy 1756e0b7975SChristophe Leroy /* 1766e0b7975SChristophe Leroy * softe copies paca->irq_soft_mask variable state. Since irq_soft_mask is 1776e0b7975SChristophe Leroy * no more used as a flag, lets force usr to alway see the softe value as 1 1786e0b7975SChristophe Leroy * which means interrupts are not soft disabled. 1796e0b7975SChristophe Leroy */ 1806e0b7975SChristophe Leroy if (IS_ENABLED(CONFIG_PPC64) && regno == PT_SOFTE) { 1816e0b7975SChristophe Leroy *data = 1; 1826e0b7975SChristophe Leroy return 0; 1836e0b7975SChristophe Leroy } 1846e0b7975SChristophe Leroy 1856e0b7975SChristophe Leroy regs_max = sizeof(struct user_pt_regs) / sizeof(unsigned long); 1866e0b7975SChristophe Leroy if (regno < regs_max) { 1876e0b7975SChristophe Leroy regno = array_index_nospec(regno, regs_max); 1886e0b7975SChristophe Leroy *data = ((unsigned long *)task->thread.regs)[regno]; 1896e0b7975SChristophe Leroy return 0; 1906e0b7975SChristophe Leroy } 1916e0b7975SChristophe Leroy 1926e0b7975SChristophe Leroy return -EIO; 1936e0b7975SChristophe Leroy } 1946e0b7975SChristophe Leroy 1956e0b7975SChristophe Leroy /* 1966e0b7975SChristophe Leroy * Write contents of register REGNO in task TASK. 1976e0b7975SChristophe Leroy */ 1986e0b7975SChristophe Leroy int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) 1996e0b7975SChristophe Leroy { 2006e0b7975SChristophe Leroy if (task->thread.regs == NULL) 2016e0b7975SChristophe Leroy return -EIO; 2026e0b7975SChristophe Leroy 2036e0b7975SChristophe Leroy if (regno == PT_MSR) 2046e0b7975SChristophe Leroy return set_user_msr(task, data); 2056e0b7975SChristophe Leroy if (regno == PT_TRAP) 2066e0b7975SChristophe Leroy return set_user_trap(task, data); 2076e0b7975SChristophe Leroy if (regno == PT_DSCR) 2086e0b7975SChristophe Leroy return set_user_dscr(task, data); 2096e0b7975SChristophe Leroy 2106e0b7975SChristophe Leroy if (regno <= PT_MAX_PUT_REG) { 2116e0b7975SChristophe Leroy regno = array_index_nospec(regno, PT_MAX_PUT_REG + 1); 2126e0b7975SChristophe Leroy ((unsigned long *)task->thread.regs)[regno] = data; 2136e0b7975SChristophe Leroy return 0; 2146e0b7975SChristophe Leroy } 2156e0b7975SChristophe Leroy return -EIO; 2166e0b7975SChristophe Leroy } 2176e0b7975SChristophe Leroy 2186e0b7975SChristophe Leroy static int gpr_get(struct task_struct *target, const struct user_regset *regset, 21947e12855SAl Viro struct membuf to) 2206e0b7975SChristophe Leroy { 221640586f8SOleg Nesterov struct membuf to_msr = membuf_at(&to, offsetof(struct pt_regs, msr)); 222324a6946SOleg Nesterov #ifdef CONFIG_PPC64 223324a6946SOleg Nesterov struct membuf to_softe = membuf_at(&to, offsetof(struct pt_regs, softe)); 224324a6946SOleg Nesterov #endif 2256e0b7975SChristophe Leroy if (target->thread.regs == NULL) 2266e0b7975SChristophe Leroy return -EIO; 2276e0b7975SChristophe Leroy 228640586f8SOleg Nesterov membuf_write(&to, target->thread.regs, sizeof(struct user_pt_regs)); 2296e0b7975SChristophe Leroy 230640586f8SOleg Nesterov membuf_store(&to_msr, get_user_msr(target)); 231324a6946SOleg Nesterov #ifdef CONFIG_PPC64 232324a6946SOleg Nesterov membuf_store(&to_softe, 0x1ul); 233324a6946SOleg Nesterov #endif 23447e12855SAl Viro return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) - 2356e0b7975SChristophe Leroy sizeof(struct user_pt_regs)); 2366e0b7975SChristophe Leroy } 2376e0b7975SChristophe Leroy 2386e0b7975SChristophe Leroy static int gpr_set(struct task_struct *target, const struct user_regset *regset, 2396e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 2406e0b7975SChristophe Leroy const void __user *ubuf) 2416e0b7975SChristophe Leroy { 2426e0b7975SChristophe Leroy unsigned long reg; 2436e0b7975SChristophe Leroy int ret; 2446e0b7975SChristophe Leroy 2456e0b7975SChristophe Leroy if (target->thread.regs == NULL) 2466e0b7975SChristophe Leroy return -EIO; 2476e0b7975SChristophe Leroy 2486e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 2496e0b7975SChristophe Leroy target->thread.regs, 2506e0b7975SChristophe Leroy 0, PT_MSR * sizeof(reg)); 2516e0b7975SChristophe Leroy 2526e0b7975SChristophe Leroy if (!ret && count > 0) { 2536e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, 2546e0b7975SChristophe Leroy PT_MSR * sizeof(reg), 2556e0b7975SChristophe Leroy (PT_MSR + 1) * sizeof(reg)); 2566e0b7975SChristophe Leroy if (!ret) 2576e0b7975SChristophe Leroy ret = set_user_msr(target, reg); 2586e0b7975SChristophe Leroy } 2596e0b7975SChristophe Leroy 2606e0b7975SChristophe Leroy BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != 2616e0b7975SChristophe Leroy offsetof(struct pt_regs, msr) + sizeof(long)); 2626e0b7975SChristophe Leroy 2636e0b7975SChristophe Leroy if (!ret) 2646e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 2656e0b7975SChristophe Leroy &target->thread.regs->orig_gpr3, 2666e0b7975SChristophe Leroy PT_ORIG_R3 * sizeof(reg), 2676e0b7975SChristophe Leroy (PT_MAX_PUT_REG + 1) * sizeof(reg)); 2686e0b7975SChristophe Leroy 2696e0b7975SChristophe Leroy if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret) 2706e0b7975SChristophe Leroy ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 2716e0b7975SChristophe Leroy (PT_MAX_PUT_REG + 1) * sizeof(reg), 2726e0b7975SChristophe Leroy PT_TRAP * sizeof(reg)); 2736e0b7975SChristophe Leroy 2746e0b7975SChristophe Leroy if (!ret && count > 0) { 2756e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, 2766e0b7975SChristophe Leroy PT_TRAP * sizeof(reg), 2776e0b7975SChristophe Leroy (PT_TRAP + 1) * sizeof(reg)); 2786e0b7975SChristophe Leroy if (!ret) 2796e0b7975SChristophe Leroy ret = set_user_trap(target, reg); 2806e0b7975SChristophe Leroy } 2816e0b7975SChristophe Leroy 2826e0b7975SChristophe Leroy if (!ret) 2836e0b7975SChristophe Leroy ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 2846e0b7975SChristophe Leroy (PT_TRAP + 1) * sizeof(reg), -1); 2856e0b7975SChristophe Leroy 2866e0b7975SChristophe Leroy return ret; 2876e0b7975SChristophe Leroy } 2886e0b7975SChristophe Leroy 2896e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 2906e0b7975SChristophe Leroy static int ppr_get(struct task_struct *target, const struct user_regset *regset, 29147e12855SAl Viro struct membuf to) 2926e0b7975SChristophe Leroy { 29347e12855SAl Viro return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64)); 2946e0b7975SChristophe Leroy } 2956e0b7975SChristophe Leroy 2966e0b7975SChristophe Leroy static int ppr_set(struct task_struct *target, const struct user_regset *regset, 2976e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 2986e0b7975SChristophe Leroy const void __user *ubuf) 2996e0b7975SChristophe Leroy { 3006e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3016e0b7975SChristophe Leroy &target->thread.regs->ppr, 0, sizeof(u64)); 3026e0b7975SChristophe Leroy } 3036e0b7975SChristophe Leroy 3046e0b7975SChristophe Leroy static int dscr_get(struct task_struct *target, const struct user_regset *regset, 30547e12855SAl Viro struct membuf to) 3066e0b7975SChristophe Leroy { 30747e12855SAl Viro return membuf_write(&to, &target->thread.dscr, sizeof(u64)); 3086e0b7975SChristophe Leroy } 3096e0b7975SChristophe Leroy static int dscr_set(struct task_struct *target, const struct user_regset *regset, 3106e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3116e0b7975SChristophe Leroy const void __user *ubuf) 3126e0b7975SChristophe Leroy { 3136e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3146e0b7975SChristophe Leroy &target->thread.dscr, 0, sizeof(u64)); 3156e0b7975SChristophe Leroy } 3166e0b7975SChristophe Leroy #endif 3176e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 3186e0b7975SChristophe Leroy static int tar_get(struct task_struct *target, const struct user_regset *regset, 31947e12855SAl Viro struct membuf to) 3206e0b7975SChristophe Leroy { 32147e12855SAl Viro return membuf_write(&to, &target->thread.tar, sizeof(u64)); 3226e0b7975SChristophe Leroy } 3236e0b7975SChristophe Leroy static int tar_set(struct task_struct *target, const struct user_regset *regset, 3246e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3256e0b7975SChristophe Leroy const void __user *ubuf) 3266e0b7975SChristophe Leroy { 3276e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3286e0b7975SChristophe Leroy &target->thread.tar, 0, sizeof(u64)); 3296e0b7975SChristophe Leroy } 3306e0b7975SChristophe Leroy 3316e0b7975SChristophe Leroy static int ebb_active(struct task_struct *target, const struct user_regset *regset) 3326e0b7975SChristophe Leroy { 3336e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3346e0b7975SChristophe Leroy return -ENODEV; 3356e0b7975SChristophe Leroy 3366e0b7975SChristophe Leroy if (target->thread.used_ebb) 3376e0b7975SChristophe Leroy return regset->n; 3386e0b7975SChristophe Leroy 3396e0b7975SChristophe Leroy return 0; 3406e0b7975SChristophe Leroy } 3416e0b7975SChristophe Leroy 3426e0b7975SChristophe Leroy static int ebb_get(struct task_struct *target, const struct user_regset *regset, 34347e12855SAl Viro struct membuf to) 3446e0b7975SChristophe Leroy { 3456e0b7975SChristophe Leroy /* Build tests */ 3466e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 3476e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 3486e0b7975SChristophe Leroy 3496e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3506e0b7975SChristophe Leroy return -ENODEV; 3516e0b7975SChristophe Leroy 3526e0b7975SChristophe Leroy if (!target->thread.used_ebb) 3536e0b7975SChristophe Leroy return -ENODATA; 3546e0b7975SChristophe Leroy 35547e12855SAl Viro return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long)); 3566e0b7975SChristophe Leroy } 3576e0b7975SChristophe Leroy 3586e0b7975SChristophe Leroy static int ebb_set(struct task_struct *target, const struct user_regset *regset, 3596e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3606e0b7975SChristophe Leroy const void __user *ubuf) 3616e0b7975SChristophe Leroy { 3626e0b7975SChristophe Leroy int ret = 0; 3636e0b7975SChristophe Leroy 3646e0b7975SChristophe Leroy /* Build tests */ 3656e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 3666e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 3676e0b7975SChristophe Leroy 3686e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3696e0b7975SChristophe Leroy return -ENODEV; 3706e0b7975SChristophe Leroy 3716e0b7975SChristophe Leroy if (target->thread.used_ebb) 3726e0b7975SChristophe Leroy return -ENODATA; 3736e0b7975SChristophe Leroy 3746e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr, 3756e0b7975SChristophe Leroy 0, sizeof(unsigned long)); 3766e0b7975SChristophe Leroy 3776e0b7975SChristophe Leroy if (!ret) 3786e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3796e0b7975SChristophe Leroy &target->thread.ebbhr, sizeof(unsigned long), 3806e0b7975SChristophe Leroy 2 * sizeof(unsigned long)); 3816e0b7975SChristophe Leroy 3826e0b7975SChristophe Leroy if (!ret) 3836e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3846e0b7975SChristophe Leroy &target->thread.bescr, 2 * sizeof(unsigned long), 3856e0b7975SChristophe Leroy 3 * sizeof(unsigned long)); 3866e0b7975SChristophe Leroy 3876e0b7975SChristophe Leroy return ret; 3886e0b7975SChristophe Leroy } 3896e0b7975SChristophe Leroy static int pmu_active(struct task_struct *target, const struct user_regset *regset) 3906e0b7975SChristophe Leroy { 3916e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3926e0b7975SChristophe Leroy return -ENODEV; 3936e0b7975SChristophe Leroy 3946e0b7975SChristophe Leroy return regset->n; 3956e0b7975SChristophe Leroy } 3966e0b7975SChristophe Leroy 3976e0b7975SChristophe Leroy static int pmu_get(struct task_struct *target, const struct user_regset *regset, 39847e12855SAl Viro struct membuf to) 3996e0b7975SChristophe Leroy { 4006e0b7975SChristophe Leroy /* Build tests */ 4016e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 4026e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 4036e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 4046e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 4056e0b7975SChristophe Leroy 4066e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 4076e0b7975SChristophe Leroy return -ENODEV; 4086e0b7975SChristophe Leroy 40947e12855SAl Viro return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long)); 4106e0b7975SChristophe Leroy } 4116e0b7975SChristophe Leroy 4126e0b7975SChristophe Leroy static int pmu_set(struct task_struct *target, const struct user_regset *regset, 4136e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 4146e0b7975SChristophe Leroy const void __user *ubuf) 4156e0b7975SChristophe Leroy { 4166e0b7975SChristophe Leroy int ret = 0; 4176e0b7975SChristophe Leroy 4186e0b7975SChristophe Leroy /* Build tests */ 4196e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 4206e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 4216e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 4226e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 4236e0b7975SChristophe Leroy 4246e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 4256e0b7975SChristophe Leroy return -ENODEV; 4266e0b7975SChristophe Leroy 4276e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.siar, 4286e0b7975SChristophe Leroy 0, sizeof(unsigned long)); 4296e0b7975SChristophe Leroy 4306e0b7975SChristophe Leroy if (!ret) 4316e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4326e0b7975SChristophe Leroy &target->thread.sdar, sizeof(unsigned long), 4336e0b7975SChristophe Leroy 2 * sizeof(unsigned long)); 4346e0b7975SChristophe Leroy 4356e0b7975SChristophe Leroy if (!ret) 4366e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4376e0b7975SChristophe Leroy &target->thread.sier, 2 * sizeof(unsigned long), 4386e0b7975SChristophe Leroy 3 * sizeof(unsigned long)); 4396e0b7975SChristophe Leroy 4406e0b7975SChristophe Leroy if (!ret) 4416e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4426e0b7975SChristophe Leroy &target->thread.mmcr2, 3 * sizeof(unsigned long), 4436e0b7975SChristophe Leroy 4 * sizeof(unsigned long)); 4446e0b7975SChristophe Leroy 4456e0b7975SChristophe Leroy if (!ret) 4466e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4476e0b7975SChristophe Leroy &target->thread.mmcr0, 4 * sizeof(unsigned long), 4486e0b7975SChristophe Leroy 5 * sizeof(unsigned long)); 4496e0b7975SChristophe Leroy return ret; 4506e0b7975SChristophe Leroy } 4516e0b7975SChristophe Leroy #endif 4526e0b7975SChristophe Leroy 4536e0b7975SChristophe Leroy #ifdef CONFIG_PPC_MEM_KEYS 4546e0b7975SChristophe Leroy static int pkey_active(struct task_struct *target, const struct user_regset *regset) 4556e0b7975SChristophe Leroy { 4566e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 4576e0b7975SChristophe Leroy return -ENODEV; 4586e0b7975SChristophe Leroy 4596e0b7975SChristophe Leroy return regset->n; 4606e0b7975SChristophe Leroy } 4616e0b7975SChristophe Leroy 4626e0b7975SChristophe Leroy static int pkey_get(struct task_struct *target, const struct user_regset *regset, 46347e12855SAl Viro struct membuf to) 4646e0b7975SChristophe Leroy { 4656e0b7975SChristophe Leroy 4666e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 4676e0b7975SChristophe Leroy return -ENODEV; 4686e0b7975SChristophe Leroy 469edc541ecSAneesh Kumar K.V membuf_store(&to, target->thread.regs->amr); 470edc541ecSAneesh Kumar K.V membuf_store(&to, target->thread.regs->iamr); 47125d8d4eeSLinus Torvalds return membuf_store(&to, default_uamor); 4726e0b7975SChristophe Leroy } 4736e0b7975SChristophe Leroy 4746e0b7975SChristophe Leroy static int pkey_set(struct task_struct *target, const struct user_regset *regset, 4756e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 4766e0b7975SChristophe Leroy const void __user *ubuf) 4776e0b7975SChristophe Leroy { 4786e0b7975SChristophe Leroy u64 new_amr; 4796e0b7975SChristophe Leroy int ret; 4806e0b7975SChristophe Leroy 4816e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 4826e0b7975SChristophe Leroy return -ENODEV; 4836e0b7975SChristophe Leroy 4846e0b7975SChristophe Leroy /* Only the AMR can be set from userspace */ 4856e0b7975SChristophe Leroy if (pos != 0 || count != sizeof(new_amr)) 4866e0b7975SChristophe Leroy return -EINVAL; 4876e0b7975SChristophe Leroy 4886e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4896e0b7975SChristophe Leroy &new_amr, 0, sizeof(new_amr)); 4906e0b7975SChristophe Leroy if (ret) 4916e0b7975SChristophe Leroy return ret; 4926e0b7975SChristophe Leroy 493e0d8e991SAneesh Kumar K.V /* 494e0d8e991SAneesh Kumar K.V * UAMOR determines which bits of the AMR can be set from userspace. 495e0d8e991SAneesh Kumar K.V * UAMOR value 0b11 indicates that the AMR value can be modified 496e0d8e991SAneesh Kumar K.V * from userspace. If the kernel is using a specific key, we avoid 497e0d8e991SAneesh Kumar K.V * userspace modifying the AMR value for that key by masking them 498e0d8e991SAneesh Kumar K.V * via UAMOR 0b00. 499e0d8e991SAneesh Kumar K.V * 500e0d8e991SAneesh Kumar K.V * Pick the AMR values for the keys that kernel is using. This 501e0d8e991SAneesh Kumar K.V * will be indicated by the ~default_uamor bits. 502e0d8e991SAneesh Kumar K.V */ 503edc541ecSAneesh Kumar K.V target->thread.regs->amr = (new_amr & default_uamor) | 504edc541ecSAneesh Kumar K.V (target->thread.regs->amr & ~default_uamor); 5056e0b7975SChristophe Leroy 5066e0b7975SChristophe Leroy return 0; 5076e0b7975SChristophe Leroy } 5086e0b7975SChristophe Leroy #endif /* CONFIG_PPC_MEM_KEYS */ 5096e0b7975SChristophe Leroy 5106e0b7975SChristophe Leroy static const struct user_regset native_regsets[] = { 5116e0b7975SChristophe Leroy [REGSET_GPR] = { 5126e0b7975SChristophe Leroy .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 5136e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 51447e12855SAl Viro .regset_get = gpr_get, .set = gpr_set 5156e0b7975SChristophe Leroy }, 5166e0b7975SChristophe Leroy [REGSET_FPR] = { 5176e0b7975SChristophe Leroy .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 5186e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 51947e12855SAl Viro .regset_get = fpr_get, .set = fpr_set 5206e0b7975SChristophe Leroy }, 5216e0b7975SChristophe Leroy #ifdef CONFIG_ALTIVEC 5226e0b7975SChristophe Leroy [REGSET_VMX] = { 5236e0b7975SChristophe Leroy .core_note_type = NT_PPC_VMX, .n = 34, 5246e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 52547e12855SAl Viro .active = vr_active, .regset_get = vr_get, .set = vr_set 5266e0b7975SChristophe Leroy }, 5276e0b7975SChristophe Leroy #endif 5286e0b7975SChristophe Leroy #ifdef CONFIG_VSX 5296e0b7975SChristophe Leroy [REGSET_VSX] = { 5306e0b7975SChristophe Leroy .core_note_type = NT_PPC_VSX, .n = 32, 5316e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 53247e12855SAl Viro .active = vsr_active, .regset_get = vsr_get, .set = vsr_set 5336e0b7975SChristophe Leroy }, 5346e0b7975SChristophe Leroy #endif 5356e0b7975SChristophe Leroy #ifdef CONFIG_SPE 5366e0b7975SChristophe Leroy [REGSET_SPE] = { 5376e0b7975SChristophe Leroy .core_note_type = NT_PPC_SPE, .n = 35, 5386e0b7975SChristophe Leroy .size = sizeof(u32), .align = sizeof(u32), 53947e12855SAl Viro .active = evr_active, .regset_get = evr_get, .set = evr_set 5406e0b7975SChristophe Leroy }, 5416e0b7975SChristophe Leroy #endif 5426e0b7975SChristophe Leroy #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 5436e0b7975SChristophe Leroy [REGSET_TM_CGPR] = { 5446e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 5456e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 54647e12855SAl Viro .active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set 5476e0b7975SChristophe Leroy }, 5486e0b7975SChristophe Leroy [REGSET_TM_CFPR] = { 5496e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 5506e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 55147e12855SAl Viro .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 5526e0b7975SChristophe Leroy }, 5536e0b7975SChristophe Leroy [REGSET_TM_CVMX] = { 5546e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 5556e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 55647e12855SAl Viro .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 5576e0b7975SChristophe Leroy }, 5586e0b7975SChristophe Leroy [REGSET_TM_CVSX] = { 5596e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 5606e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 56147e12855SAl Viro .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 5626e0b7975SChristophe Leroy }, 5636e0b7975SChristophe Leroy [REGSET_TM_SPR] = { 5646e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 5656e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 56647e12855SAl Viro .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 5676e0b7975SChristophe Leroy }, 5686e0b7975SChristophe Leroy [REGSET_TM_CTAR] = { 5696e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CTAR, .n = 1, 5706e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 57147e12855SAl Viro .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 5726e0b7975SChristophe Leroy }, 5736e0b7975SChristophe Leroy [REGSET_TM_CPPR] = { 5746e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CPPR, .n = 1, 5756e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 57647e12855SAl Viro .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 5776e0b7975SChristophe Leroy }, 5786e0b7975SChristophe Leroy [REGSET_TM_CDSCR] = { 5796e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 5806e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 58147e12855SAl Viro .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 5826e0b7975SChristophe Leroy }, 5836e0b7975SChristophe Leroy #endif 5846e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 5856e0b7975SChristophe Leroy [REGSET_PPR] = { 5866e0b7975SChristophe Leroy .core_note_type = NT_PPC_PPR, .n = 1, 5876e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 58847e12855SAl Viro .regset_get = ppr_get, .set = ppr_set 5896e0b7975SChristophe Leroy }, 5906e0b7975SChristophe Leroy [REGSET_DSCR] = { 5916e0b7975SChristophe Leroy .core_note_type = NT_PPC_DSCR, .n = 1, 5926e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 59347e12855SAl Viro .regset_get = dscr_get, .set = dscr_set 5946e0b7975SChristophe Leroy }, 5956e0b7975SChristophe Leroy #endif 5966e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 5976e0b7975SChristophe Leroy [REGSET_TAR] = { 5986e0b7975SChristophe Leroy .core_note_type = NT_PPC_TAR, .n = 1, 5996e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 60047e12855SAl Viro .regset_get = tar_get, .set = tar_set 6016e0b7975SChristophe Leroy }, 6026e0b7975SChristophe Leroy [REGSET_EBB] = { 6036e0b7975SChristophe Leroy .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 6046e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 60547e12855SAl Viro .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 6066e0b7975SChristophe Leroy }, 6076e0b7975SChristophe Leroy [REGSET_PMR] = { 6086e0b7975SChristophe Leroy .core_note_type = NT_PPC_PMU, .n = ELF_NPMU, 6096e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 61047e12855SAl Viro .active = pmu_active, .regset_get = pmu_get, .set = pmu_set 6116e0b7975SChristophe Leroy }, 6126e0b7975SChristophe Leroy #endif 6136e0b7975SChristophe Leroy #ifdef CONFIG_PPC_MEM_KEYS 6146e0b7975SChristophe Leroy [REGSET_PKEY] = { 6156e0b7975SChristophe Leroy .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY, 6166e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 61747e12855SAl Viro .active = pkey_active, .regset_get = pkey_get, .set = pkey_set 6186e0b7975SChristophe Leroy }, 6196e0b7975SChristophe Leroy #endif 6206e0b7975SChristophe Leroy }; 6216e0b7975SChristophe Leroy 6226e0b7975SChristophe Leroy const struct user_regset_view user_ppc_native_view = { 6236e0b7975SChristophe Leroy .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, 6246e0b7975SChristophe Leroy .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) 6256e0b7975SChristophe Leroy }; 6266e0b7975SChristophe Leroy 6276e0b7975SChristophe Leroy #include <linux/compat.h> 6286e0b7975SChristophe Leroy 6296e0b7975SChristophe Leroy int gpr32_get_common(struct task_struct *target, 6306e0b7975SChristophe Leroy const struct user_regset *regset, 63147e12855SAl Viro struct membuf to, unsigned long *regs) 6326e0b7975SChristophe Leroy { 63347e12855SAl Viro int i; 6346e0b7975SChristophe Leroy 63547e12855SAl Viro for (i = 0; i < PT_MSR; i++) 63647e12855SAl Viro membuf_store(&to, (u32)regs[i]); 63747e12855SAl Viro membuf_store(&to, (u32)get_user_msr(target)); 63847e12855SAl Viro for (i++ ; i < PT_REGS_COUNT; i++) 63947e12855SAl Viro membuf_store(&to, (u32)regs[i]); 64047e12855SAl Viro return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32)); 6416e0b7975SChristophe Leroy } 6426e0b7975SChristophe Leroy 6436e0b7975SChristophe Leroy int gpr32_set_common(struct task_struct *target, 6446e0b7975SChristophe Leroy const struct user_regset *regset, 6456e0b7975SChristophe Leroy unsigned int pos, unsigned int count, 6466e0b7975SChristophe Leroy const void *kbuf, const void __user *ubuf, 6476e0b7975SChristophe Leroy unsigned long *regs) 6486e0b7975SChristophe Leroy { 6496e0b7975SChristophe Leroy const compat_ulong_t *k = kbuf; 6506e0b7975SChristophe Leroy const compat_ulong_t __user *u = ubuf; 6516e0b7975SChristophe Leroy compat_ulong_t reg; 6526e0b7975SChristophe Leroy 65393c043e3SChristophe Leroy if (!kbuf && !user_read_access_begin(u, count)) 65493c043e3SChristophe Leroy return -EFAULT; 65593c043e3SChristophe Leroy 6566e0b7975SChristophe Leroy pos /= sizeof(reg); 6576e0b7975SChristophe Leroy count /= sizeof(reg); 6586e0b7975SChristophe Leroy 6596e0b7975SChristophe Leroy if (kbuf) 6606e0b7975SChristophe Leroy for (; count > 0 && pos < PT_MSR; --count) 6616e0b7975SChristophe Leroy regs[pos++] = *k++; 6626e0b7975SChristophe Leroy else 6636e0b7975SChristophe Leroy for (; count > 0 && pos < PT_MSR; --count) { 66493c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 6656e0b7975SChristophe Leroy regs[pos++] = reg; 6666e0b7975SChristophe Leroy } 6676e0b7975SChristophe Leroy 6686e0b7975SChristophe Leroy 6696e0b7975SChristophe Leroy if (count > 0 && pos == PT_MSR) { 6706e0b7975SChristophe Leroy if (kbuf) 6716e0b7975SChristophe Leroy reg = *k++; 67293c043e3SChristophe Leroy else 67393c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 6746e0b7975SChristophe Leroy set_user_msr(target, reg); 6756e0b7975SChristophe Leroy ++pos; 6766e0b7975SChristophe Leroy --count; 6776e0b7975SChristophe Leroy } 6786e0b7975SChristophe Leroy 6796e0b7975SChristophe Leroy if (kbuf) { 6806e0b7975SChristophe Leroy for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) 6816e0b7975SChristophe Leroy regs[pos++] = *k++; 6826e0b7975SChristophe Leroy for (; count > 0 && pos < PT_TRAP; --count, ++pos) 6836e0b7975SChristophe Leroy ++k; 6846e0b7975SChristophe Leroy } else { 6856e0b7975SChristophe Leroy for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { 68693c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 6876e0b7975SChristophe Leroy regs[pos++] = reg; 6886e0b7975SChristophe Leroy } 6896e0b7975SChristophe Leroy for (; count > 0 && pos < PT_TRAP; --count, ++pos) 69093c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 6916e0b7975SChristophe Leroy } 6926e0b7975SChristophe Leroy 6936e0b7975SChristophe Leroy if (count > 0 && pos == PT_TRAP) { 6946e0b7975SChristophe Leroy if (kbuf) 6956e0b7975SChristophe Leroy reg = *k++; 69693c043e3SChristophe Leroy else 69793c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 6986e0b7975SChristophe Leroy set_user_trap(target, reg); 6996e0b7975SChristophe Leroy ++pos; 7006e0b7975SChristophe Leroy --count; 7016e0b7975SChristophe Leroy } 70293c043e3SChristophe Leroy if (!kbuf) 70393c043e3SChristophe Leroy user_read_access_end(); 7046e0b7975SChristophe Leroy 7056e0b7975SChristophe Leroy kbuf = k; 7066e0b7975SChristophe Leroy ubuf = u; 7076e0b7975SChristophe Leroy pos *= sizeof(reg); 7086e0b7975SChristophe Leroy count *= sizeof(reg); 7096e0b7975SChristophe Leroy return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 7106e0b7975SChristophe Leroy (PT_TRAP + 1) * sizeof(reg), -1); 71193c043e3SChristophe Leroy 71293c043e3SChristophe Leroy Efault: 71393c043e3SChristophe Leroy user_read_access_end(); 71493c043e3SChristophe Leroy return -EFAULT; 7156e0b7975SChristophe Leroy } 7166e0b7975SChristophe Leroy 7176e0b7975SChristophe Leroy static int gpr32_get(struct task_struct *target, 7186e0b7975SChristophe Leroy const struct user_regset *regset, 71947e12855SAl Viro struct membuf to) 7206e0b7975SChristophe Leroy { 7216e0b7975SChristophe Leroy if (target->thread.regs == NULL) 7226e0b7975SChristophe Leroy return -EIO; 7236e0b7975SChristophe Leroy 72447e12855SAl Viro return gpr32_get_common(target, regset, to, 7256e0b7975SChristophe Leroy &target->thread.regs->gpr[0]); 7266e0b7975SChristophe Leroy } 7276e0b7975SChristophe Leroy 7286e0b7975SChristophe Leroy static int gpr32_set(struct task_struct *target, 7296e0b7975SChristophe Leroy const struct user_regset *regset, 7306e0b7975SChristophe Leroy unsigned int pos, unsigned int count, 7316e0b7975SChristophe Leroy const void *kbuf, const void __user *ubuf) 7326e0b7975SChristophe Leroy { 7336e0b7975SChristophe Leroy if (target->thread.regs == NULL) 7346e0b7975SChristophe Leroy return -EIO; 7356e0b7975SChristophe Leroy 7366e0b7975SChristophe Leroy return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 7376e0b7975SChristophe Leroy &target->thread.regs->gpr[0]); 7386e0b7975SChristophe Leroy } 7396e0b7975SChristophe Leroy 7406e0b7975SChristophe Leroy /* 7416e0b7975SChristophe Leroy * These are the regset flavors matching the CONFIG_PPC32 native set. 7426e0b7975SChristophe Leroy */ 7436e0b7975SChristophe Leroy static const struct user_regset compat_regsets[] = { 7446e0b7975SChristophe Leroy [REGSET_GPR] = { 7456e0b7975SChristophe Leroy .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 7466e0b7975SChristophe Leroy .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), 74747e12855SAl Viro .regset_get = gpr32_get, .set = gpr32_set 7486e0b7975SChristophe Leroy }, 7496e0b7975SChristophe Leroy [REGSET_FPR] = { 7506e0b7975SChristophe Leroy .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 7516e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 75247e12855SAl Viro .regset_get = fpr_get, .set = fpr_set 7536e0b7975SChristophe Leroy }, 7546e0b7975SChristophe Leroy #ifdef CONFIG_ALTIVEC 7556e0b7975SChristophe Leroy [REGSET_VMX] = { 7566e0b7975SChristophe Leroy .core_note_type = NT_PPC_VMX, .n = 34, 7576e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 75847e12855SAl Viro .active = vr_active, .regset_get = vr_get, .set = vr_set 7596e0b7975SChristophe Leroy }, 7606e0b7975SChristophe Leroy #endif 7616e0b7975SChristophe Leroy #ifdef CONFIG_SPE 7626e0b7975SChristophe Leroy [REGSET_SPE] = { 7636e0b7975SChristophe Leroy .core_note_type = NT_PPC_SPE, .n = 35, 7646e0b7975SChristophe Leroy .size = sizeof(u32), .align = sizeof(u32), 76547e12855SAl Viro .active = evr_active, .regset_get = evr_get, .set = evr_set 7666e0b7975SChristophe Leroy }, 7676e0b7975SChristophe Leroy #endif 7686e0b7975SChristophe Leroy #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 7696e0b7975SChristophe Leroy [REGSET_TM_CGPR] = { 7706e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 7716e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 7726e0b7975SChristophe Leroy .active = tm_cgpr_active, 77347e12855SAl Viro .regset_get = tm_cgpr32_get, .set = tm_cgpr32_set 7746e0b7975SChristophe Leroy }, 7756e0b7975SChristophe Leroy [REGSET_TM_CFPR] = { 7766e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 7776e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 77847e12855SAl Viro .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 7796e0b7975SChristophe Leroy }, 7806e0b7975SChristophe Leroy [REGSET_TM_CVMX] = { 7816e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 7826e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 78347e12855SAl Viro .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 7846e0b7975SChristophe Leroy }, 7856e0b7975SChristophe Leroy [REGSET_TM_CVSX] = { 7866e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 7876e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 78847e12855SAl Viro .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 7896e0b7975SChristophe Leroy }, 7906e0b7975SChristophe Leroy [REGSET_TM_SPR] = { 7916e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 7926e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 79347e12855SAl Viro .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 7946e0b7975SChristophe Leroy }, 7956e0b7975SChristophe Leroy [REGSET_TM_CTAR] = { 7966e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CTAR, .n = 1, 7976e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 79847e12855SAl Viro .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 7996e0b7975SChristophe Leroy }, 8006e0b7975SChristophe Leroy [REGSET_TM_CPPR] = { 8016e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CPPR, .n = 1, 8026e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 80347e12855SAl Viro .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 8046e0b7975SChristophe Leroy }, 8056e0b7975SChristophe Leroy [REGSET_TM_CDSCR] = { 8066e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 8076e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 80847e12855SAl Viro .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 8096e0b7975SChristophe Leroy }, 8106e0b7975SChristophe Leroy #endif 8116e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 8126e0b7975SChristophe Leroy [REGSET_PPR] = { 8136e0b7975SChristophe Leroy .core_note_type = NT_PPC_PPR, .n = 1, 8146e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 81547e12855SAl Viro .regset_get = ppr_get, .set = ppr_set 8166e0b7975SChristophe Leroy }, 8176e0b7975SChristophe Leroy [REGSET_DSCR] = { 8186e0b7975SChristophe Leroy .core_note_type = NT_PPC_DSCR, .n = 1, 8196e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 82047e12855SAl Viro .regset_get = dscr_get, .set = dscr_set 8216e0b7975SChristophe Leroy }, 8226e0b7975SChristophe Leroy #endif 8236e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 8246e0b7975SChristophe Leroy [REGSET_TAR] = { 8256e0b7975SChristophe Leroy .core_note_type = NT_PPC_TAR, .n = 1, 8266e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 82747e12855SAl Viro .regset_get = tar_get, .set = tar_set 8286e0b7975SChristophe Leroy }, 8296e0b7975SChristophe Leroy [REGSET_EBB] = { 8306e0b7975SChristophe Leroy .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 8316e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 83247e12855SAl Viro .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 8336e0b7975SChristophe Leroy }, 8346e0b7975SChristophe Leroy #endif 8356e0b7975SChristophe Leroy }; 8366e0b7975SChristophe Leroy 8376e0b7975SChristophe Leroy static const struct user_regset_view user_ppc_compat_view = { 8386e0b7975SChristophe Leroy .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, 8396e0b7975SChristophe Leroy .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) 8406e0b7975SChristophe Leroy }; 8416e0b7975SChristophe Leroy 8426e0b7975SChristophe Leroy const struct user_regset_view *task_user_regset_view(struct task_struct *task) 8436e0b7975SChristophe Leroy { 8446e0b7975SChristophe Leroy if (IS_ENABLED(CONFIG_PPC64) && test_tsk_thread_flag(task, TIF_32BIT)) 8456e0b7975SChristophe Leroy return &user_ppc_compat_view; 8466e0b7975SChristophe Leroy return &user_ppc_native_view; 8476e0b7975SChristophe Leroy } 848