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 | struct membuf to) |
45 | { |
46 | union { |
47 | elf_vrreg_t reg; |
48 | u32 word; |
49 | } vrsave; |
50 | |
51 | flush_altivec_to_thread(target); |
52 | |
53 | BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != |
54 | offsetof(struct thread_vr_state, vr[32])); |
55 | |
56 | membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128)); |
57 | /* |
58 | * Copy out only the low-order word of vrsave. |
59 | */ |
60 | memset(&vrsave, 0, sizeof(vrsave)); |
61 | vrsave.word = target->thread.vrsave; |
62 | return membuf_write(s: &to, v: &vrsave, size: sizeof(vrsave)); |
63 | } |
64 | |
65 | /* |
66 | * Regardless of transactions, 'vr_state' holds the current running |
67 | * value of all the VMX registers and 'ckvr_state' holds the last |
68 | * checkpointed value of all the VMX registers for the current |
69 | * transaction to fall back on in case it aborts. |
70 | * |
71 | * Userspace interface buffer layout: |
72 | * |
73 | * struct data { |
74 | * vector128 vr[32]; |
75 | * vector128 vscr; |
76 | * vector128 vrsave; |
77 | * }; |
78 | */ |
79 | int vr_set(struct task_struct *target, const struct user_regset *regset, |
80 | unsigned int pos, unsigned int count, |
81 | const void *kbuf, const void __user *ubuf) |
82 | { |
83 | int ret; |
84 | |
85 | flush_altivec_to_thread(target); |
86 | |
87 | BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != |
88 | offsetof(struct thread_vr_state, vr[32])); |
89 | |
90 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
91 | &target->thread.vr_state, 0, |
92 | 33 * sizeof(vector128)); |
93 | if (!ret && count > 0) { |
94 | /* |
95 | * We use only the first word of vrsave. |
96 | */ |
97 | int start, end; |
98 | union { |
99 | elf_vrreg_t reg; |
100 | u32 word; |
101 | } vrsave; |
102 | memset(&vrsave, 0, sizeof(vrsave)); |
103 | |
104 | vrsave.word = target->thread.vrsave; |
105 | |
106 | start = 33 * sizeof(vector128); |
107 | end = start + sizeof(vrsave); |
108 | ret = user_regset_copyin(pos: &pos, count: &count, kbuf: &kbuf, ubuf: &ubuf, data: &vrsave, |
109 | start_pos: start, end_pos: end); |
110 | if (!ret) |
111 | target->thread.vrsave = vrsave.word; |
112 | } |
113 | |
114 | return ret; |
115 | } |
116 | |