// SPDX-License-Identifier: GPL-2.0-or-later #include <linux/regset.h> #include <linux/elf.h> #include <asm/switch_to.h> #include "ptrace-decl.h" /* * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. * The transfer totals 34 quadword. Quadwords 0-31 contain the * corresponding vector registers. Quadword 32 contains the vscr as the * last word (offset 12) within that quadword. Quadword 33 contains the * vrsave as the first word (offset 0) within the quadword. * * This definition of the VMX state is compatible with the current PPC32 * ptrace interface. This allows signal handling and ptrace to use the * same structures. This also simplifies the implementation of a bi-arch * (combined (32- and 64-bit) gdb. */ int vr_active(struct task_struct *target, const struct user_regset *regset) { flush_altivec_to_thread(target); return target->thread.used_vr ? regset->n : 0; } /* * Regardless of transactions, 'vr_state' holds the current running * value of all the VMX registers and 'ckvr_state' holds the last * checkpointed value of all the VMX registers for the current * transaction to fall back on in case it aborts. * * Userspace interface buffer layout: * * struct data { * vector128 vr[32]; * vector128 vscr; * vector128 vrsave; * }; */ int vr_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { union { elf_vrreg_t reg; u32 word; } vrsave; flush_altivec_to_thread(target); BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != offsetof(struct thread_vr_state, vr[32])); membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128)); /* * Copy out only the low-order word of vrsave. */ memset(&vrsave, 0, sizeof(vrsave)); vrsave.word = target->thread.vrsave; return membuf_write(&to, &vrsave, sizeof(vrsave)); } /* * Regardless of transactions, 'vr_state' holds the current running * value of all the VMX registers and 'ckvr_state' holds the last * checkpointed value of all the VMX registers for the current * transaction to fall back on in case it aborts. * * Userspace interface buffer layout: * * struct data { * vector128 vr[32]; * vector128 vscr; * vector128 vrsave; * }; */ int vr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { int ret; flush_altivec_to_thread(target); BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != offsetof(struct thread_vr_state, vr[32])); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.vr_state, 0, 33 * sizeof(vector128)); if (!ret && count > 0) { /* * We use only the first word of vrsave. */ int start, end; union { elf_vrreg_t reg; u32 word; } vrsave; memset(&vrsave, 0, sizeof(vrsave)); vrsave.word = target->thread.vrsave; start = 33 * sizeof(vector128); end = start + sizeof(vrsave); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, start, end); if (!ret) target->thread.vrsave = vrsave.word; } return ret; }