Merge tag 'for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power...
[linux-2.6-microblaze.git] / arch / powerpc / kernel / ptrace / ptrace-altivec.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #include <linux/regset.h>
4 #include <linux/elf.h>
5
6 #include <asm/switch_to.h>
7
8 #include "ptrace-decl.h"
9
10 /*
11  * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
12  * The transfer totals 34 quadword.  Quadwords 0-31 contain the
13  * corresponding vector registers.  Quadword 32 contains the vscr as the
14  * last word (offset 12) within that quadword.  Quadword 33 contains the
15  * vrsave as the first word (offset 0) within the quadword.
16  *
17  * This definition of the VMX state is compatible with the current PPC32
18  * ptrace interface.  This allows signal handling and ptrace to use the
19  * same structures.  This also simplifies the implementation of a bi-arch
20  * (combined (32- and 64-bit) gdb.
21  */
22
23 int vr_active(struct task_struct *target, const struct user_regset *regset)
24 {
25         flush_altivec_to_thread(target);
26         return target->thread.used_vr ? regset->n : 0;
27 }
28
29 /*
30  * Regardless of transactions, 'vr_state' holds the current running
31  * value of all the VMX registers and 'ckvr_state' holds the last
32  * checkpointed value of all the VMX registers for the current
33  * transaction to fall back on in case it aborts.
34  *
35  * Userspace interface buffer layout:
36  *
37  * struct data {
38  *      vector128       vr[32];
39  *      vector128       vscr;
40  *      vector128       vrsave;
41  * };
42  */
43 int vr_get(struct task_struct *target, const struct user_regset *regset,
44            unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf)
45 {
46         int ret;
47
48         flush_altivec_to_thread(target);
49
50         BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
51                      offsetof(struct thread_vr_state, vr[32]));
52
53         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
54                                   &target->thread.vr_state, 0,
55                                   33 * sizeof(vector128));
56         if (!ret) {
57                 /*
58                  * Copy out only the low-order word of vrsave.
59                  */
60                 int start, end;
61                 union {
62                         elf_vrreg_t reg;
63                         u32 word;
64                 } vrsave;
65                 memset(&vrsave, 0, sizeof(vrsave));
66
67                 vrsave.word = target->thread.vrsave;
68
69                 start = 33 * sizeof(vector128);
70                 end = start + sizeof(vrsave);
71                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
72                                           start, end);
73         }
74
75         return ret;
76 }
77
78 /*
79  * Regardless of transactions, 'vr_state' holds the current running
80  * value of all the VMX registers and 'ckvr_state' holds the last
81  * checkpointed value of all the VMX registers for the current
82  * transaction to fall back on in case it aborts.
83  *
84  * Userspace interface buffer layout:
85  *
86  * struct data {
87  *      vector128       vr[32];
88  *      vector128       vscr;
89  *      vector128       vrsave;
90  * };
91  */
92 int vr_set(struct task_struct *target, const struct user_regset *regset,
93            unsigned int pos, unsigned int count,
94            const void *kbuf, const void __user *ubuf)
95 {
96         int ret;
97
98         flush_altivec_to_thread(target);
99
100         BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
101                      offsetof(struct thread_vr_state, vr[32]));
102
103         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
104                                  &target->thread.vr_state, 0,
105                                  33 * sizeof(vector128));
106         if (!ret && count > 0) {
107                 /*
108                  * We use only the first word of vrsave.
109                  */
110                 int start, end;
111                 union {
112                         elf_vrreg_t reg;
113                         u32 word;
114                 } vrsave;
115                 memset(&vrsave, 0, sizeof(vrsave));
116
117                 vrsave.word = target->thread.vrsave;
118
119                 start = 33 * sizeof(vector128);
120                 end = start + sizeof(vrsave);
121                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
122                                          start, end);
123                 if (!ret)
124                         target->thread.vrsave = vrsave.word;
125         }
126
127         return ret;
128 }