^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/thread_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/sigcontext.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/fpumacro.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/switch_to.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "sigutil.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned long *fpregs = current_thread_info()->fpregs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned long fprs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) fprs = current_thread_info()->fpsaved[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) if (fprs & FPRS_DL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) (sizeof(unsigned int) * 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (fprs & FPRS_DU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) (sizeof(unsigned int) * 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) err |= __put_user(fprs, &fpu->si_fprs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long *fpregs = current_thread_info()->fpregs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned long fprs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (((unsigned long) fpu) & 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) err = get_user(fprs, &fpu->si_fprs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) fprs_write(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) regs->tstate &= ~TSTATE_PEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (fprs & FPRS_DL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) (sizeof(unsigned int) * 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (fprs & FPRS_DU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) (sizeof(unsigned int) * 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) current_thread_info()->fpsaved[0] |= fprs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int i, err = __put_user(wsaved, &rwin->wsaved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) for (i = 0; i < wsaved; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct reg_window *rp = ¤t_thread_info()->reg_window[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) err |= copy_to_user(&rwin->reg_window[i], rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) sizeof(struct reg_window));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int restore_rwin_state(__siginfo_rwin_t __user *rp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct thread_info *t = current_thread_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int i, wsaved, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (((unsigned long) rp) & 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) get_user(wsaved, &rp->wsaved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (wsaved > NSWINS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) for (i = 0; i < wsaved; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) err |= copy_from_user(&t->reg_window[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) &rp->reg_window[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) sizeof(struct reg_window));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) err |= __get_user(t->rwbuf_stkptrs[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) &rp->rwbuf_stkptrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) set_thread_wsaved(wsaved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) synchronize_user_stack();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (get_thread_wsaved())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }