Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/kernel.h>
0003 #include <linux/types.h>
0004 #include <linux/thread_info.h>
0005 #include <linux/uaccess.h>
0006 #include <linux/sched.h>
0007 
0008 #include <asm/sigcontext.h>
0009 #include <asm/fpumacro.h>
0010 #include <asm/ptrace.h>
0011 #include <asm/switch_to.h>
0012 
0013 #include "sigutil.h"
0014 
0015 int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
0016 {
0017     int err = 0;
0018 #ifdef CONFIG_SMP
0019     if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
0020         put_psr(get_psr() | PSR_EF);
0021         fpsave(&current->thread.float_regs[0], &current->thread.fsr,
0022                &current->thread.fpqueue[0], &current->thread.fpqdepth);
0023         regs->psr &= ~(PSR_EF);
0024         clear_tsk_thread_flag(current, TIF_USEDFPU);
0025     }
0026 #else
0027     if (current == last_task_used_math) {
0028         put_psr(get_psr() | PSR_EF);
0029         fpsave(&current->thread.float_regs[0], &current->thread.fsr,
0030                &current->thread.fpqueue[0], &current->thread.fpqdepth);
0031         last_task_used_math = NULL;
0032         regs->psr &= ~(PSR_EF);
0033     }
0034 #endif
0035     err |= __copy_to_user(&fpu->si_float_regs[0],
0036                   &current->thread.float_regs[0],
0037                   (sizeof(unsigned long) * 32));
0038     err |= __put_user(current->thread.fsr, &fpu->si_fsr);
0039     err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
0040     if (current->thread.fpqdepth != 0)
0041         err |= __copy_to_user(&fpu->si_fpqueue[0],
0042                       &current->thread.fpqueue[0],
0043                       ((sizeof(unsigned long) +
0044                       (sizeof(unsigned long *)))*16));
0045     clear_used_math();
0046     return err;
0047 }
0048 
0049 int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
0050 {
0051     int err;
0052 
0053     if (((unsigned long) fpu) & 3)
0054         return -EFAULT;
0055 
0056 #ifdef CONFIG_SMP
0057     if (test_tsk_thread_flag(current, TIF_USEDFPU))
0058         regs->psr &= ~PSR_EF;
0059 #else
0060     if (current == last_task_used_math) {
0061         last_task_used_math = NULL;
0062         regs->psr &= ~PSR_EF;
0063     }
0064 #endif
0065     set_used_math();
0066     clear_tsk_thread_flag(current, TIF_USEDFPU);
0067 
0068     if (!access_ok(fpu, sizeof(*fpu)))
0069         return -EFAULT;
0070 
0071     err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
0072                    (sizeof(unsigned long) * 32));
0073     err |= __get_user(current->thread.fsr, &fpu->si_fsr);
0074     err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
0075     if (current->thread.fpqdepth != 0)
0076         err |= __copy_from_user(&current->thread.fpqueue[0],
0077                     &fpu->si_fpqueue[0],
0078                     ((sizeof(unsigned long) +
0079                     (sizeof(unsigned long *)))*16));
0080     return err;
0081 }
0082 
0083 int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
0084 {
0085     int i, err = __put_user(wsaved, &rwin->wsaved);
0086 
0087     for (i = 0; i < wsaved; i++) {
0088         struct reg_window32 *rp;
0089         unsigned long fp;
0090 
0091         rp = &current_thread_info()->reg_window[i];
0092         fp = current_thread_info()->rwbuf_stkptrs[i];
0093         err |= copy_to_user(&rwin->reg_window[i], rp,
0094                     sizeof(struct reg_window32));
0095         err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
0096     }
0097     return err;
0098 }
0099 
0100 int restore_rwin_state(__siginfo_rwin_t __user *rp)
0101 {
0102     struct thread_info *t = current_thread_info();
0103     int i, wsaved, err;
0104 
0105     if (((unsigned long) rp) & 3)
0106         return -EFAULT;
0107 
0108     get_user(wsaved, &rp->wsaved);
0109     if (wsaved > NSWINS)
0110         return -EFAULT;
0111 
0112     err = 0;
0113     for (i = 0; i < wsaved; i++) {
0114         err |= copy_from_user(&t->reg_window[i],
0115                       &rp->reg_window[i],
0116                       sizeof(struct reg_window32));
0117         err |= __get_user(t->rwbuf_stkptrs[i],
0118                   &rp->rwbuf_stkptrs[i]);
0119     }
0120     if (err)
0121         return err;
0122 
0123     t->w_saved = wsaved;
0124     synchronize_user_stack();
0125     if (t->w_saved)
0126         return -EFAULT;
0127     return 0;
0128 
0129 }