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 { 11659dc5bfcSNicholas Piggin unsigned long newmsr = (task->thread.regs->msr & ~MSR_DEBUGCHANGE) | 11759dc5bfcSNicholas Piggin (msr & MSR_DEBUGCHANGE); 11859dc5bfcSNicholas 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 1771fd02f66SJulia Lawall * no more used as a flag, lets force usr to always 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) 27018b9fe54SSergey Shtylyov 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) 28318b9fe54SSergey Shtylyov 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 { 293fd727618SJens Axboe if (!target->thread.regs) 294fd727618SJens Axboe return -EINVAL; 295fd727618SJens Axboe 29647e12855SAl Viro return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64)); 2976e0b7975SChristophe Leroy } 2986e0b7975SChristophe Leroy 2996e0b7975SChristophe Leroy static int ppr_set(struct task_struct *target, const struct user_regset *regset, 3006e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3016e0b7975SChristophe Leroy const void __user *ubuf) 3026e0b7975SChristophe Leroy { 303fd727618SJens Axboe if (!target->thread.regs) 304fd727618SJens Axboe return -EINVAL; 305fd727618SJens Axboe 3066e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3076e0b7975SChristophe Leroy &target->thread.regs->ppr, 0, sizeof(u64)); 3086e0b7975SChristophe Leroy } 3096e0b7975SChristophe Leroy 3106e0b7975SChristophe Leroy static int dscr_get(struct task_struct *target, const struct user_regset *regset, 31147e12855SAl Viro struct membuf to) 3126e0b7975SChristophe Leroy { 31347e12855SAl Viro return membuf_write(&to, &target->thread.dscr, sizeof(u64)); 3146e0b7975SChristophe Leroy } 3156e0b7975SChristophe Leroy static int dscr_set(struct task_struct *target, const struct user_regset *regset, 3166e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3176e0b7975SChristophe Leroy const void __user *ubuf) 3186e0b7975SChristophe Leroy { 3196e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3206e0b7975SChristophe Leroy &target->thread.dscr, 0, sizeof(u64)); 3216e0b7975SChristophe Leroy } 3226e0b7975SChristophe Leroy #endif 3236e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 3246e0b7975SChristophe Leroy static int tar_get(struct task_struct *target, const struct user_regset *regset, 32547e12855SAl Viro struct membuf to) 3266e0b7975SChristophe Leroy { 32747e12855SAl Viro return membuf_write(&to, &target->thread.tar, sizeof(u64)); 3286e0b7975SChristophe Leroy } 3296e0b7975SChristophe Leroy static int tar_set(struct task_struct *target, const struct user_regset *regset, 3306e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3316e0b7975SChristophe Leroy const void __user *ubuf) 3326e0b7975SChristophe Leroy { 3336e0b7975SChristophe Leroy return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3346e0b7975SChristophe Leroy &target->thread.tar, 0, sizeof(u64)); 3356e0b7975SChristophe Leroy } 3366e0b7975SChristophe Leroy 3376e0b7975SChristophe Leroy static int ebb_active(struct task_struct *target, const struct user_regset *regset) 3386e0b7975SChristophe Leroy { 3396e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3406e0b7975SChristophe Leroy return -ENODEV; 3416e0b7975SChristophe Leroy 3426e0b7975SChristophe Leroy if (target->thread.used_ebb) 3436e0b7975SChristophe Leroy return regset->n; 3446e0b7975SChristophe Leroy 3456e0b7975SChristophe Leroy return 0; 3466e0b7975SChristophe Leroy } 3476e0b7975SChristophe Leroy 3486e0b7975SChristophe Leroy static int ebb_get(struct task_struct *target, const struct user_regset *regset, 34947e12855SAl Viro struct membuf to) 3506e0b7975SChristophe Leroy { 3516e0b7975SChristophe Leroy /* Build tests */ 3526e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 3536e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 3546e0b7975SChristophe Leroy 3556e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3566e0b7975SChristophe Leroy return -ENODEV; 3576e0b7975SChristophe Leroy 3586e0b7975SChristophe Leroy if (!target->thread.used_ebb) 3596e0b7975SChristophe Leroy return -ENODATA; 3606e0b7975SChristophe Leroy 36147e12855SAl Viro return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long)); 3626e0b7975SChristophe Leroy } 3636e0b7975SChristophe Leroy 3646e0b7975SChristophe Leroy static int ebb_set(struct task_struct *target, const struct user_regset *regset, 3656e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 3666e0b7975SChristophe Leroy const void __user *ubuf) 3676e0b7975SChristophe Leroy { 3686e0b7975SChristophe Leroy int ret = 0; 3696e0b7975SChristophe Leroy 3706e0b7975SChristophe Leroy /* Build tests */ 3716e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 3726e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 3736e0b7975SChristophe Leroy 3746e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3756e0b7975SChristophe Leroy return -ENODEV; 3766e0b7975SChristophe Leroy 3776e0b7975SChristophe Leroy if (target->thread.used_ebb) 3786e0b7975SChristophe Leroy return -ENODATA; 3796e0b7975SChristophe Leroy 3806e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr, 3816e0b7975SChristophe Leroy 0, sizeof(unsigned long)); 3826e0b7975SChristophe Leroy 3836e0b7975SChristophe Leroy if (!ret) 3846e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3856e0b7975SChristophe Leroy &target->thread.ebbhr, sizeof(unsigned long), 3866e0b7975SChristophe Leroy 2 * sizeof(unsigned long)); 3876e0b7975SChristophe Leroy 3886e0b7975SChristophe Leroy if (!ret) 3896e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 3906e0b7975SChristophe Leroy &target->thread.bescr, 2 * sizeof(unsigned long), 3916e0b7975SChristophe Leroy 3 * sizeof(unsigned long)); 3926e0b7975SChristophe Leroy 3936e0b7975SChristophe Leroy return ret; 3946e0b7975SChristophe Leroy } 3956e0b7975SChristophe Leroy static int pmu_active(struct task_struct *target, const struct user_regset *regset) 3966e0b7975SChristophe Leroy { 3976e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 3986e0b7975SChristophe Leroy return -ENODEV; 3996e0b7975SChristophe Leroy 4006e0b7975SChristophe Leroy return regset->n; 4016e0b7975SChristophe Leroy } 4026e0b7975SChristophe Leroy 4036e0b7975SChristophe Leroy static int pmu_get(struct task_struct *target, const struct user_regset *regset, 40447e12855SAl Viro struct membuf to) 4056e0b7975SChristophe Leroy { 4066e0b7975SChristophe Leroy /* Build tests */ 4076e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 4086e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 4096e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 4106e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 4116e0b7975SChristophe Leroy 4126e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 4136e0b7975SChristophe Leroy return -ENODEV; 4146e0b7975SChristophe Leroy 41547e12855SAl Viro return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long)); 4166e0b7975SChristophe Leroy } 4176e0b7975SChristophe Leroy 4186e0b7975SChristophe Leroy static int pmu_set(struct task_struct *target, const struct user_regset *regset, 4196e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 4206e0b7975SChristophe Leroy const void __user *ubuf) 4216e0b7975SChristophe Leroy { 4226e0b7975SChristophe Leroy int ret = 0; 4236e0b7975SChristophe Leroy 4246e0b7975SChristophe Leroy /* Build tests */ 4256e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 4266e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 4276e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 4286e0b7975SChristophe Leroy BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 4296e0b7975SChristophe Leroy 4306e0b7975SChristophe Leroy if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 4316e0b7975SChristophe Leroy return -ENODEV; 4326e0b7975SChristophe Leroy 4336e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.siar, 4346e0b7975SChristophe Leroy 0, sizeof(unsigned long)); 4356e0b7975SChristophe Leroy 4366e0b7975SChristophe Leroy if (!ret) 4376e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4386e0b7975SChristophe Leroy &target->thread.sdar, sizeof(unsigned long), 4396e0b7975SChristophe Leroy 2 * sizeof(unsigned long)); 4406e0b7975SChristophe Leroy 4416e0b7975SChristophe Leroy if (!ret) 4426e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4436e0b7975SChristophe Leroy &target->thread.sier, 2 * sizeof(unsigned long), 4446e0b7975SChristophe Leroy 3 * sizeof(unsigned long)); 4456e0b7975SChristophe Leroy 4466e0b7975SChristophe Leroy if (!ret) 4476e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4486e0b7975SChristophe Leroy &target->thread.mmcr2, 3 * sizeof(unsigned long), 4496e0b7975SChristophe Leroy 4 * sizeof(unsigned long)); 4506e0b7975SChristophe Leroy 4516e0b7975SChristophe Leroy if (!ret) 4526e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 4536e0b7975SChristophe Leroy &target->thread.mmcr0, 4 * sizeof(unsigned long), 4546e0b7975SChristophe Leroy 5 * sizeof(unsigned long)); 4556e0b7975SChristophe Leroy return ret; 4566e0b7975SChristophe Leroy } 457884ad5c5SBenjamin Gray 458884ad5c5SBenjamin Gray static int dexcr_active(struct task_struct *target, const struct user_regset *regset) 459884ad5c5SBenjamin Gray { 460884ad5c5SBenjamin Gray if (!cpu_has_feature(CPU_FTR_ARCH_31)) 461884ad5c5SBenjamin Gray return -ENODEV; 462884ad5c5SBenjamin Gray 463884ad5c5SBenjamin Gray return regset->n; 464884ad5c5SBenjamin Gray } 465884ad5c5SBenjamin Gray 466884ad5c5SBenjamin Gray static int dexcr_get(struct task_struct *target, const struct user_regset *regset, 467884ad5c5SBenjamin Gray struct membuf to) 468884ad5c5SBenjamin Gray { 469884ad5c5SBenjamin Gray if (!cpu_has_feature(CPU_FTR_ARCH_31)) 470884ad5c5SBenjamin Gray return -ENODEV; 471884ad5c5SBenjamin Gray 472884ad5c5SBenjamin Gray /* 473884ad5c5SBenjamin Gray * The DEXCR is currently static across all CPUs, so we don't 474884ad5c5SBenjamin Gray * store the target's value anywhere, but the static value 475884ad5c5SBenjamin Gray * will also be correct. 476884ad5c5SBenjamin Gray */ 477884ad5c5SBenjamin Gray membuf_store(&to, (u64)lower_32_bits(DEXCR_INIT)); 478884ad5c5SBenjamin Gray 479884ad5c5SBenjamin Gray /* 480884ad5c5SBenjamin Gray * Technically the HDEXCR is per-cpu, but a hypervisor can't reasonably 481884ad5c5SBenjamin Gray * change it between CPUs of the same guest. 482884ad5c5SBenjamin Gray */ 483884ad5c5SBenjamin Gray return membuf_store(&to, (u64)lower_32_bits(mfspr(SPRN_HDEXCR_RO))); 484884ad5c5SBenjamin Gray } 485884ad5c5SBenjamin Gray 48697228ca3SBenjamin Gray #ifdef CONFIG_CHECKPOINT_RESTORE 48797228ca3SBenjamin Gray static int hashkeyr_active(struct task_struct *target, const struct user_regset *regset) 48897228ca3SBenjamin Gray { 48997228ca3SBenjamin Gray if (!cpu_has_feature(CPU_FTR_ARCH_31)) 49097228ca3SBenjamin Gray return -ENODEV; 49197228ca3SBenjamin Gray 49297228ca3SBenjamin Gray return regset->n; 49397228ca3SBenjamin Gray } 49497228ca3SBenjamin Gray 49597228ca3SBenjamin Gray static int hashkeyr_get(struct task_struct *target, const struct user_regset *regset, 49697228ca3SBenjamin Gray struct membuf to) 49797228ca3SBenjamin Gray { 49897228ca3SBenjamin Gray if (!cpu_has_feature(CPU_FTR_ARCH_31)) 49997228ca3SBenjamin Gray return -ENODEV; 50097228ca3SBenjamin Gray 50197228ca3SBenjamin Gray return membuf_store(&to, target->thread.hashkeyr); 50297228ca3SBenjamin Gray } 50397228ca3SBenjamin Gray 50497228ca3SBenjamin Gray static int hashkeyr_set(struct task_struct *target, const struct user_regset *regset, 50597228ca3SBenjamin Gray unsigned int pos, unsigned int count, const void *kbuf, 50697228ca3SBenjamin Gray const void __user *ubuf) 50797228ca3SBenjamin Gray { 50897228ca3SBenjamin Gray if (!cpu_has_feature(CPU_FTR_ARCH_31)) 50997228ca3SBenjamin Gray return -ENODEV; 51097228ca3SBenjamin Gray 51197228ca3SBenjamin Gray return user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.hashkeyr, 51297228ca3SBenjamin Gray 0, sizeof(unsigned long)); 51397228ca3SBenjamin Gray } 51497228ca3SBenjamin Gray #endif /* CONFIG_CHECKPOINT_RESTORE */ 515884ad5c5SBenjamin Gray #endif /* CONFIG_PPC_BOOK3S_64 */ 5166e0b7975SChristophe Leroy 5176e0b7975SChristophe Leroy #ifdef CONFIG_PPC_MEM_KEYS 5186e0b7975SChristophe Leroy static int pkey_active(struct task_struct *target, const struct user_regset *regset) 5196e0b7975SChristophe Leroy { 5206e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 5216e0b7975SChristophe Leroy return -ENODEV; 5226e0b7975SChristophe Leroy 5236e0b7975SChristophe Leroy return regset->n; 5246e0b7975SChristophe Leroy } 5256e0b7975SChristophe Leroy 5266e0b7975SChristophe Leroy static int pkey_get(struct task_struct *target, const struct user_regset *regset, 52747e12855SAl Viro struct membuf to) 5286e0b7975SChristophe Leroy { 5296e0b7975SChristophe Leroy 5306e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 5316e0b7975SChristophe Leroy return -ENODEV; 5326e0b7975SChristophe Leroy 533edc541ecSAneesh Kumar K.V membuf_store(&to, target->thread.regs->amr); 534edc541ecSAneesh Kumar K.V membuf_store(&to, target->thread.regs->iamr); 53525d8d4eeSLinus Torvalds return membuf_store(&to, default_uamor); 5366e0b7975SChristophe Leroy } 5376e0b7975SChristophe Leroy 5386e0b7975SChristophe Leroy static int pkey_set(struct task_struct *target, const struct user_regset *regset, 5396e0b7975SChristophe Leroy unsigned int pos, unsigned int count, const void *kbuf, 5406e0b7975SChristophe Leroy const void __user *ubuf) 5416e0b7975SChristophe Leroy { 5426e0b7975SChristophe Leroy u64 new_amr; 5436e0b7975SChristophe Leroy int ret; 5446e0b7975SChristophe Leroy 5456e0b7975SChristophe Leroy if (!arch_pkeys_enabled()) 5466e0b7975SChristophe Leroy return -ENODEV; 5476e0b7975SChristophe Leroy 5486e0b7975SChristophe Leroy /* Only the AMR can be set from userspace */ 5496e0b7975SChristophe Leroy if (pos != 0 || count != sizeof(new_amr)) 5506e0b7975SChristophe Leroy return -EINVAL; 5516e0b7975SChristophe Leroy 5526e0b7975SChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 5536e0b7975SChristophe Leroy &new_amr, 0, sizeof(new_amr)); 5546e0b7975SChristophe Leroy if (ret) 5556e0b7975SChristophe Leroy return ret; 5566e0b7975SChristophe Leroy 557e0d8e991SAneesh Kumar K.V /* 558e0d8e991SAneesh Kumar K.V * UAMOR determines which bits of the AMR can be set from userspace. 559e0d8e991SAneesh Kumar K.V * UAMOR value 0b11 indicates that the AMR value can be modified 560e0d8e991SAneesh Kumar K.V * from userspace. If the kernel is using a specific key, we avoid 561e0d8e991SAneesh Kumar K.V * userspace modifying the AMR value for that key by masking them 562e0d8e991SAneesh Kumar K.V * via UAMOR 0b00. 563e0d8e991SAneesh Kumar K.V * 564e0d8e991SAneesh Kumar K.V * Pick the AMR values for the keys that kernel is using. This 565e0d8e991SAneesh Kumar K.V * will be indicated by the ~default_uamor bits. 566e0d8e991SAneesh Kumar K.V */ 567edc541ecSAneesh Kumar K.V target->thread.regs->amr = (new_amr & default_uamor) | 568edc541ecSAneesh Kumar K.V (target->thread.regs->amr & ~default_uamor); 5696e0b7975SChristophe Leroy 5706e0b7975SChristophe Leroy return 0; 5716e0b7975SChristophe Leroy } 5726e0b7975SChristophe Leroy #endif /* CONFIG_PPC_MEM_KEYS */ 5736e0b7975SChristophe Leroy 5746e0b7975SChristophe Leroy static const struct user_regset native_regsets[] = { 5756e0b7975SChristophe Leroy [REGSET_GPR] = { 5766e0b7975SChristophe Leroy .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 5776e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 57847e12855SAl Viro .regset_get = gpr_get, .set = gpr_set 5796e0b7975SChristophe Leroy }, 5806e0b7975SChristophe Leroy [REGSET_FPR] = { 5816e0b7975SChristophe Leroy .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 5826e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 58347e12855SAl Viro .regset_get = fpr_get, .set = fpr_set 5846e0b7975SChristophe Leroy }, 5856e0b7975SChristophe Leroy #ifdef CONFIG_ALTIVEC 5866e0b7975SChristophe Leroy [REGSET_VMX] = { 5876e0b7975SChristophe Leroy .core_note_type = NT_PPC_VMX, .n = 34, 5886e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 58947e12855SAl Viro .active = vr_active, .regset_get = vr_get, .set = vr_set 5906e0b7975SChristophe Leroy }, 5916e0b7975SChristophe Leroy #endif 5926e0b7975SChristophe Leroy #ifdef CONFIG_VSX 5936e0b7975SChristophe Leroy [REGSET_VSX] = { 5946e0b7975SChristophe Leroy .core_note_type = NT_PPC_VSX, .n = 32, 5956e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 59647e12855SAl Viro .active = vsr_active, .regset_get = vsr_get, .set = vsr_set 5976e0b7975SChristophe Leroy }, 5986e0b7975SChristophe Leroy #endif 5996e0b7975SChristophe Leroy #ifdef CONFIG_SPE 6006e0b7975SChristophe Leroy [REGSET_SPE] = { 6016e0b7975SChristophe Leroy .core_note_type = NT_PPC_SPE, .n = 35, 6026e0b7975SChristophe Leroy .size = sizeof(u32), .align = sizeof(u32), 60347e12855SAl Viro .active = evr_active, .regset_get = evr_get, .set = evr_set 6046e0b7975SChristophe Leroy }, 6056e0b7975SChristophe Leroy #endif 6066e0b7975SChristophe Leroy #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 6076e0b7975SChristophe Leroy [REGSET_TM_CGPR] = { 6086e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 6096e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 61047e12855SAl Viro .active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set 6116e0b7975SChristophe Leroy }, 6126e0b7975SChristophe Leroy [REGSET_TM_CFPR] = { 6136e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 6146e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 61547e12855SAl Viro .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 6166e0b7975SChristophe Leroy }, 6176e0b7975SChristophe Leroy [REGSET_TM_CVMX] = { 6186e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 6196e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 62047e12855SAl Viro .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 6216e0b7975SChristophe Leroy }, 6226e0b7975SChristophe Leroy [REGSET_TM_CVSX] = { 6236e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 6246e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 62547e12855SAl Viro .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 6266e0b7975SChristophe Leroy }, 6276e0b7975SChristophe Leroy [REGSET_TM_SPR] = { 6286e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 6296e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 63047e12855SAl Viro .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 6316e0b7975SChristophe Leroy }, 6326e0b7975SChristophe Leroy [REGSET_TM_CTAR] = { 6336e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CTAR, .n = 1, 6346e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 63547e12855SAl Viro .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 6366e0b7975SChristophe Leroy }, 6376e0b7975SChristophe Leroy [REGSET_TM_CPPR] = { 6386e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CPPR, .n = 1, 6396e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 64047e12855SAl Viro .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 6416e0b7975SChristophe Leroy }, 6426e0b7975SChristophe Leroy [REGSET_TM_CDSCR] = { 6436e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 6446e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 64547e12855SAl Viro .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 6466e0b7975SChristophe Leroy }, 6476e0b7975SChristophe Leroy #endif 6486e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 6496e0b7975SChristophe Leroy [REGSET_PPR] = { 6506e0b7975SChristophe Leroy .core_note_type = NT_PPC_PPR, .n = 1, 6516e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 65247e12855SAl Viro .regset_get = ppr_get, .set = ppr_set 6536e0b7975SChristophe Leroy }, 6546e0b7975SChristophe Leroy [REGSET_DSCR] = { 6556e0b7975SChristophe Leroy .core_note_type = NT_PPC_DSCR, .n = 1, 6566e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 65747e12855SAl Viro .regset_get = dscr_get, .set = dscr_set 6586e0b7975SChristophe Leroy }, 6596e0b7975SChristophe Leroy #endif 6606e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 6616e0b7975SChristophe Leroy [REGSET_TAR] = { 6626e0b7975SChristophe Leroy .core_note_type = NT_PPC_TAR, .n = 1, 6636e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 66447e12855SAl Viro .regset_get = tar_get, .set = tar_set 6656e0b7975SChristophe Leroy }, 6666e0b7975SChristophe Leroy [REGSET_EBB] = { 6676e0b7975SChristophe Leroy .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 6686e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 66947e12855SAl Viro .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 6706e0b7975SChristophe Leroy }, 6716e0b7975SChristophe Leroy [REGSET_PMR] = { 6726e0b7975SChristophe Leroy .core_note_type = NT_PPC_PMU, .n = ELF_NPMU, 6736e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 67447e12855SAl Viro .active = pmu_active, .regset_get = pmu_get, .set = pmu_set 6756e0b7975SChristophe Leroy }, 676884ad5c5SBenjamin Gray [REGSET_DEXCR] = { 677884ad5c5SBenjamin Gray .core_note_type = NT_PPC_DEXCR, .n = ELF_NDEXCR, 678884ad5c5SBenjamin Gray .size = sizeof(u64), .align = sizeof(u64), 679884ad5c5SBenjamin Gray .active = dexcr_active, .regset_get = dexcr_get 680884ad5c5SBenjamin Gray }, 68197228ca3SBenjamin Gray #ifdef CONFIG_CHECKPOINT_RESTORE 68297228ca3SBenjamin Gray [REGSET_HASHKEYR] = { 68397228ca3SBenjamin Gray .core_note_type = NT_PPC_HASHKEYR, .n = ELF_NHASHKEYR, 68497228ca3SBenjamin Gray .size = sizeof(u64), .align = sizeof(u64), 68597228ca3SBenjamin Gray .active = hashkeyr_active, .regset_get = hashkeyr_get, .set = hashkeyr_set 68697228ca3SBenjamin Gray }, 68797228ca3SBenjamin Gray #endif 6886e0b7975SChristophe Leroy #endif 6896e0b7975SChristophe Leroy #ifdef CONFIG_PPC_MEM_KEYS 6906e0b7975SChristophe Leroy [REGSET_PKEY] = { 6916e0b7975SChristophe Leroy .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY, 6926e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 69347e12855SAl Viro .active = pkey_active, .regset_get = pkey_get, .set = pkey_set 6946e0b7975SChristophe Leroy }, 6956e0b7975SChristophe Leroy #endif 6966e0b7975SChristophe Leroy }; 6976e0b7975SChristophe Leroy 6986e0b7975SChristophe Leroy const struct user_regset_view user_ppc_native_view = { 6996e0b7975SChristophe Leroy .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, 7006e0b7975SChristophe Leroy .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) 7016e0b7975SChristophe Leroy }; 7026e0b7975SChristophe Leroy 7036e0b7975SChristophe Leroy #include <linux/compat.h> 7046e0b7975SChristophe Leroy 7056e0b7975SChristophe Leroy int gpr32_get_common(struct task_struct *target, 7066e0b7975SChristophe Leroy const struct user_regset *regset, 70747e12855SAl Viro struct membuf to, unsigned long *regs) 7086e0b7975SChristophe Leroy { 70947e12855SAl Viro int i; 7106e0b7975SChristophe Leroy 71147e12855SAl Viro for (i = 0; i < PT_MSR; i++) 71247e12855SAl Viro membuf_store(&to, (u32)regs[i]); 71347e12855SAl Viro membuf_store(&to, (u32)get_user_msr(target)); 71447e12855SAl Viro for (i++ ; i < PT_REGS_COUNT; i++) 71547e12855SAl Viro membuf_store(&to, (u32)regs[i]); 71647e12855SAl Viro return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32)); 7176e0b7975SChristophe Leroy } 7186e0b7975SChristophe Leroy 719*9a32584bSChristophe Leroy static int gpr32_set_common_kernel(struct task_struct *target, 7206e0b7975SChristophe Leroy const struct user_regset *regset, 7216e0b7975SChristophe Leroy unsigned int pos, unsigned int count, 722*9a32584bSChristophe Leroy const void *kbuf, unsigned long *regs) 7236e0b7975SChristophe Leroy { 7246e0b7975SChristophe Leroy const compat_ulong_t *k = kbuf; 725*9a32584bSChristophe Leroy 726*9a32584bSChristophe Leroy pos /= sizeof(compat_ulong_t); 727*9a32584bSChristophe Leroy count /= sizeof(compat_ulong_t); 728*9a32584bSChristophe Leroy 729*9a32584bSChristophe Leroy for (; count > 0 && pos < PT_MSR; --count) 730*9a32584bSChristophe Leroy regs[pos++] = *k++; 731*9a32584bSChristophe Leroy 732*9a32584bSChristophe Leroy if (count > 0 && pos == PT_MSR) { 733*9a32584bSChristophe Leroy set_user_msr(target, *k++); 734*9a32584bSChristophe Leroy ++pos; 735*9a32584bSChristophe Leroy --count; 736*9a32584bSChristophe Leroy } 737*9a32584bSChristophe Leroy 738*9a32584bSChristophe Leroy for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) 739*9a32584bSChristophe Leroy regs[pos++] = *k++; 740*9a32584bSChristophe Leroy for (; count > 0 && pos < PT_TRAP; --count, ++pos) 741*9a32584bSChristophe Leroy ++k; 742*9a32584bSChristophe Leroy 743*9a32584bSChristophe Leroy if (count > 0 && pos == PT_TRAP) { 744*9a32584bSChristophe Leroy set_user_trap(target, *k++); 745*9a32584bSChristophe Leroy ++pos; 746*9a32584bSChristophe Leroy --count; 747*9a32584bSChristophe Leroy } 748*9a32584bSChristophe Leroy 749*9a32584bSChristophe Leroy kbuf = k; 750*9a32584bSChristophe Leroy pos *= sizeof(compat_ulong_t); 751*9a32584bSChristophe Leroy count *= sizeof(compat_ulong_t); 752*9a32584bSChristophe Leroy user_regset_copyin_ignore(&pos, &count, &kbuf, NULL, 753*9a32584bSChristophe Leroy (PT_TRAP + 1) * sizeof(compat_ulong_t), -1); 754*9a32584bSChristophe Leroy return 0; 755*9a32584bSChristophe Leroy } 756*9a32584bSChristophe Leroy 757*9a32584bSChristophe Leroy static int gpr32_set_common_user(struct task_struct *target, 758*9a32584bSChristophe Leroy const struct user_regset *regset, 759*9a32584bSChristophe Leroy unsigned int pos, unsigned int count, 760*9a32584bSChristophe Leroy const void __user *ubuf, unsigned long *regs) 761*9a32584bSChristophe Leroy { 7626e0b7975SChristophe Leroy const compat_ulong_t __user *u = ubuf; 763*9a32584bSChristophe Leroy const void *kbuf = NULL; 7646e0b7975SChristophe Leroy compat_ulong_t reg; 7656e0b7975SChristophe Leroy 766*9a32584bSChristophe Leroy if (!user_read_access_begin(u, count)) 76793c043e3SChristophe Leroy return -EFAULT; 76893c043e3SChristophe Leroy 7696e0b7975SChristophe Leroy pos /= sizeof(reg); 7706e0b7975SChristophe Leroy count /= sizeof(reg); 7716e0b7975SChristophe Leroy 7726e0b7975SChristophe Leroy for (; count > 0 && pos < PT_MSR; --count) { 77393c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 7746e0b7975SChristophe Leroy regs[pos++] = reg; 7756e0b7975SChristophe Leroy } 7766e0b7975SChristophe Leroy 7776e0b7975SChristophe Leroy if (count > 0 && pos == PT_MSR) { 77893c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 7796e0b7975SChristophe Leroy set_user_msr(target, reg); 7806e0b7975SChristophe Leroy ++pos; 7816e0b7975SChristophe Leroy --count; 7826e0b7975SChristophe Leroy } 7836e0b7975SChristophe Leroy 7846e0b7975SChristophe Leroy for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { 78593c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 7866e0b7975SChristophe Leroy regs[pos++] = reg; 7876e0b7975SChristophe Leroy } 7886e0b7975SChristophe Leroy for (; count > 0 && pos < PT_TRAP; --count, ++pos) 78993c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 7906e0b7975SChristophe Leroy 7916e0b7975SChristophe Leroy if (count > 0 && pos == PT_TRAP) { 79293c043e3SChristophe Leroy unsafe_get_user(reg, u++, Efault); 7936e0b7975SChristophe Leroy set_user_trap(target, reg); 7946e0b7975SChristophe Leroy ++pos; 7956e0b7975SChristophe Leroy --count; 7966e0b7975SChristophe Leroy } 79793c043e3SChristophe Leroy user_read_access_end(); 7986e0b7975SChristophe Leroy 7996e0b7975SChristophe Leroy ubuf = u; 8006e0b7975SChristophe Leroy pos *= sizeof(reg); 8016e0b7975SChristophe Leroy count *= sizeof(reg); 80218b9fe54SSergey Shtylyov user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 8036e0b7975SChristophe Leroy (PT_TRAP + 1) * sizeof(reg), -1); 80418b9fe54SSergey Shtylyov return 0; 80593c043e3SChristophe Leroy 80693c043e3SChristophe Leroy Efault: 80793c043e3SChristophe Leroy user_read_access_end(); 80893c043e3SChristophe Leroy return -EFAULT; 8096e0b7975SChristophe Leroy } 8106e0b7975SChristophe Leroy 811*9a32584bSChristophe Leroy int gpr32_set_common(struct task_struct *target, 812*9a32584bSChristophe Leroy const struct user_regset *regset, 813*9a32584bSChristophe Leroy unsigned int pos, unsigned int count, 814*9a32584bSChristophe Leroy const void *kbuf, const void __user *ubuf, 815*9a32584bSChristophe Leroy unsigned long *regs) 816*9a32584bSChristophe Leroy { 817*9a32584bSChristophe Leroy if (kbuf) 818*9a32584bSChristophe Leroy return gpr32_set_common_kernel(target, regset, pos, count, kbuf, regs); 819*9a32584bSChristophe Leroy else 820*9a32584bSChristophe Leroy return gpr32_set_common_user(target, regset, pos, count, ubuf, regs); 821*9a32584bSChristophe Leroy } 822*9a32584bSChristophe Leroy 8236e0b7975SChristophe Leroy static int gpr32_get(struct task_struct *target, 8246e0b7975SChristophe Leroy const struct user_regset *regset, 82547e12855SAl Viro struct membuf to) 8266e0b7975SChristophe Leroy { 8276e0b7975SChristophe Leroy if (target->thread.regs == NULL) 8286e0b7975SChristophe Leroy return -EIO; 8296e0b7975SChristophe Leroy 83047e12855SAl Viro return gpr32_get_common(target, regset, to, 8316e0b7975SChristophe Leroy &target->thread.regs->gpr[0]); 8326e0b7975SChristophe Leroy } 8336e0b7975SChristophe Leroy 8346e0b7975SChristophe Leroy static int gpr32_set(struct task_struct *target, 8356e0b7975SChristophe Leroy const struct user_regset *regset, 8366e0b7975SChristophe Leroy unsigned int pos, unsigned int count, 8376e0b7975SChristophe Leroy const void *kbuf, const void __user *ubuf) 8386e0b7975SChristophe Leroy { 8396e0b7975SChristophe Leroy if (target->thread.regs == NULL) 8406e0b7975SChristophe Leroy return -EIO; 8416e0b7975SChristophe Leroy 8426e0b7975SChristophe Leroy return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 8436e0b7975SChristophe Leroy &target->thread.regs->gpr[0]); 8446e0b7975SChristophe Leroy } 8456e0b7975SChristophe Leroy 8466e0b7975SChristophe Leroy /* 8476e0b7975SChristophe Leroy * These are the regset flavors matching the CONFIG_PPC32 native set. 8486e0b7975SChristophe Leroy */ 8496e0b7975SChristophe Leroy static const struct user_regset compat_regsets[] = { 8506e0b7975SChristophe Leroy [REGSET_GPR] = { 8516e0b7975SChristophe Leroy .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 8526e0b7975SChristophe Leroy .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), 85347e12855SAl Viro .regset_get = gpr32_get, .set = gpr32_set 8546e0b7975SChristophe Leroy }, 8556e0b7975SChristophe Leroy [REGSET_FPR] = { 8566e0b7975SChristophe Leroy .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 8576e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 85847e12855SAl Viro .regset_get = fpr_get, .set = fpr_set 8596e0b7975SChristophe Leroy }, 8606e0b7975SChristophe Leroy #ifdef CONFIG_ALTIVEC 8616e0b7975SChristophe Leroy [REGSET_VMX] = { 8626e0b7975SChristophe Leroy .core_note_type = NT_PPC_VMX, .n = 34, 8636e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 86447e12855SAl Viro .active = vr_active, .regset_get = vr_get, .set = vr_set 8656e0b7975SChristophe Leroy }, 8666e0b7975SChristophe Leroy #endif 8676e0b7975SChristophe Leroy #ifdef CONFIG_SPE 8686e0b7975SChristophe Leroy [REGSET_SPE] = { 8696e0b7975SChristophe Leroy .core_note_type = NT_PPC_SPE, .n = 35, 8706e0b7975SChristophe Leroy .size = sizeof(u32), .align = sizeof(u32), 87147e12855SAl Viro .active = evr_active, .regset_get = evr_get, .set = evr_set 8726e0b7975SChristophe Leroy }, 8736e0b7975SChristophe Leroy #endif 8746e0b7975SChristophe Leroy #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 8756e0b7975SChristophe Leroy [REGSET_TM_CGPR] = { 8766e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 8776e0b7975SChristophe Leroy .size = sizeof(long), .align = sizeof(long), 8786e0b7975SChristophe Leroy .active = tm_cgpr_active, 87947e12855SAl Viro .regset_get = tm_cgpr32_get, .set = tm_cgpr32_set 8806e0b7975SChristophe Leroy }, 8816e0b7975SChristophe Leroy [REGSET_TM_CFPR] = { 8826e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 8836e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 88447e12855SAl Viro .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 8856e0b7975SChristophe Leroy }, 8866e0b7975SChristophe Leroy [REGSET_TM_CVMX] = { 8876e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 8886e0b7975SChristophe Leroy .size = sizeof(vector128), .align = sizeof(vector128), 88947e12855SAl Viro .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 8906e0b7975SChristophe Leroy }, 8916e0b7975SChristophe Leroy [REGSET_TM_CVSX] = { 8926e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 8936e0b7975SChristophe Leroy .size = sizeof(double), .align = sizeof(double), 89447e12855SAl Viro .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 8956e0b7975SChristophe Leroy }, 8966e0b7975SChristophe Leroy [REGSET_TM_SPR] = { 8976e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 8986e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 89947e12855SAl Viro .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 9006e0b7975SChristophe Leroy }, 9016e0b7975SChristophe Leroy [REGSET_TM_CTAR] = { 9026e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CTAR, .n = 1, 9036e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 90447e12855SAl Viro .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 9056e0b7975SChristophe Leroy }, 9066e0b7975SChristophe Leroy [REGSET_TM_CPPR] = { 9076e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CPPR, .n = 1, 9086e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 90947e12855SAl Viro .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 9106e0b7975SChristophe Leroy }, 9116e0b7975SChristophe Leroy [REGSET_TM_CDSCR] = { 9126e0b7975SChristophe Leroy .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 9136e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 91447e12855SAl Viro .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 9156e0b7975SChristophe Leroy }, 9166e0b7975SChristophe Leroy #endif 9176e0b7975SChristophe Leroy #ifdef CONFIG_PPC64 9186e0b7975SChristophe Leroy [REGSET_PPR] = { 9196e0b7975SChristophe Leroy .core_note_type = NT_PPC_PPR, .n = 1, 9206e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 92147e12855SAl Viro .regset_get = ppr_get, .set = ppr_set 9226e0b7975SChristophe Leroy }, 9236e0b7975SChristophe Leroy [REGSET_DSCR] = { 9246e0b7975SChristophe Leroy .core_note_type = NT_PPC_DSCR, .n = 1, 9256e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 92647e12855SAl Viro .regset_get = dscr_get, .set = dscr_set 9276e0b7975SChristophe Leroy }, 9286e0b7975SChristophe Leroy #endif 9296e0b7975SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_64 9306e0b7975SChristophe Leroy [REGSET_TAR] = { 9316e0b7975SChristophe Leroy .core_note_type = NT_PPC_TAR, .n = 1, 9326e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 93347e12855SAl Viro .regset_get = tar_get, .set = tar_set 9346e0b7975SChristophe Leroy }, 9356e0b7975SChristophe Leroy [REGSET_EBB] = { 9366e0b7975SChristophe Leroy .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 9376e0b7975SChristophe Leroy .size = sizeof(u64), .align = sizeof(u64), 93847e12855SAl Viro .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 9396e0b7975SChristophe Leroy }, 9406e0b7975SChristophe Leroy #endif 9416e0b7975SChristophe Leroy }; 9426e0b7975SChristophe Leroy 9436e0b7975SChristophe Leroy static const struct user_regset_view user_ppc_compat_view = { 9446e0b7975SChristophe Leroy .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, 9456e0b7975SChristophe Leroy .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) 9466e0b7975SChristophe Leroy }; 9476e0b7975SChristophe Leroy 9486e0b7975SChristophe Leroy const struct user_regset_view *task_user_regset_view(struct task_struct *task) 9496e0b7975SChristophe Leroy { 9509d44d1bdSChristophe Leroy if (IS_ENABLED(CONFIG_COMPAT) && is_tsk_32bit_task(task)) 9516e0b7975SChristophe Leroy return &user_ppc_compat_view; 9526e0b7975SChristophe Leroy return &user_ppc_native_view; 9536e0b7975SChristophe Leroy } 954