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(s: &to, v: buf, size: 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: &pos, count: &count, kbuf: &kbuf, ubuf: &ubuf, data: buf, start_pos: 0, end_pos: -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(tsk: 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(s: &to, v: buf, size: 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(tsk: 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: &pos, count: &count, kbuf: &kbuf, ubuf: &ubuf, |
142 | data: buf, start_pos: 0, end_pos: 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 | |