1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <linux/regset.h> 4 5 #include <asm/switch_to.h> 6 7 #include "ptrace-decl.h" 8 9 /* 10 * Regardless of transactions, 'fp_state' holds the current running 11 * value of all FPR registers and 'ckfp_state' holds the last checkpointed 12 * value of all FPR registers for the current transaction. 13 * 14 * Userspace interface buffer layout: 15 * 16 * struct data { 17 * u64 fpr[32]; 18 * u64 fpscr; 19 * }; 20 */ 21 int fpr_get(struct task_struct *target, const struct user_regset *regset, 22 struct membuf to) 23 { 24 u64 buf[33]; 25 int i; 26 27 flush_fp_to_thread(target); 28 29 /* copy to local buffer then write that out */ 30 for (i = 0; i < 32 ; i++) 31 buf[i] = target->thread.TS_FPR(i); 32 buf[32] = target->thread.fp_state.fpscr; 33 return membuf_write(&to, buf, 33 * sizeof(u64)); 34 } 35 36 /* 37 * Regardless of transactions, 'fp_state' holds the current running 38 * value of all FPR registers and 'ckfp_state' holds the last checkpointed 39 * value of all FPR registers for the current transaction. 40 * 41 * Userspace interface buffer layout: 42 * 43 * struct data { 44 * u64 fpr[32]; 45 * u64 fpscr; 46 * }; 47 * 48 */ 49 int fpr_set(struct task_struct *target, const struct user_regset *regset, 50 unsigned int pos, unsigned int count, 51 const void *kbuf, const void __user *ubuf) 52 { 53 u64 buf[33]; 54 int i; 55 56 flush_fp_to_thread(target); 57 58 for (i = 0; i < 32 ; i++) 59 buf[i] = target->thread.TS_FPR(i); 60 buf[32] = target->thread.fp_state.fpscr; 61 62 /* copy to local buffer then write that out */ 63 i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); 64 if (i) 65 return i; 66 67 for (i = 0; i < 32 ; i++) 68 target->thread.TS_FPR(i) = buf[i]; 69 target->thread.fp_state.fpscr = buf[32]; 70 return 0; 71 } 72 73 /* 74 * Currently to set and get all the vsx state, you need to call 75 * the fp and VMX calls as well. This only get/sets the lower 32 76 * 128bit VSX registers. 77 */ 78 79 int vsr_active(struct task_struct *target, const struct user_regset *regset) 80 { 81 flush_vsx_to_thread(target); 82 return target->thread.used_vsr ? regset->n : 0; 83 } 84 85 /* 86 * Regardless of transactions, 'fp_state' holds the current running 87 * value of all FPR registers and 'ckfp_state' holds the last 88 * checkpointed value of all FPR registers for the current 89 * transaction. 90 * 91 * Userspace interface buffer layout: 92 * 93 * struct data { 94 * u64 vsx[32]; 95 * }; 96 */ 97 int vsr_get(struct task_struct *target, const struct user_regset *regset, 98 struct membuf to) 99 { 100 u64 buf[32]; 101 int i; 102 103 flush_tmregs_to_thread(target); 104 flush_fp_to_thread(target); 105 flush_altivec_to_thread(target); 106 flush_vsx_to_thread(target); 107 108 for (i = 0; i < 32 ; i++) 109 buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; 110 111 return membuf_write(&to, buf, 32 * sizeof(double)); 112 } 113 114 /* 115 * Regardless of transactions, 'fp_state' holds the current running 116 * value of all FPR registers and 'ckfp_state' holds the last 117 * checkpointed value of all FPR registers for the current 118 * transaction. 119 * 120 * Userspace interface buffer layout: 121 * 122 * struct data { 123 * u64 vsx[32]; 124 * }; 125 */ 126 int vsr_set(struct task_struct *target, const struct user_regset *regset, 127 unsigned int pos, unsigned int count, 128 const void *kbuf, const void __user *ubuf) 129 { 130 u64 buf[32]; 131 int ret, i; 132 133 flush_tmregs_to_thread(target); 134 flush_fp_to_thread(target); 135 flush_altivec_to_thread(target); 136 flush_vsx_to_thread(target); 137 138 for (i = 0; i < 32 ; i++) 139 buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; 140 141 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 142 buf, 0, 32 * sizeof(double)); 143 if (!ret) 144 for (i = 0; i < 32 ; i++) 145 target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; 146 147 return ret; 148 } 149