~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mn10300/kernel/fpu.c

Version: ~ [ linux-5.14-rc3 ] ~ [ linux-5.13.5 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.53 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.135 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.198 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.240 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.276 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.276 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* MN10300 FPU management
  2  *
  3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  4  * Written by David Howells (dhowells@redhat.com)
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public Licence
  8  * as published by the Free Software Foundation; either version
  9  * 2 of the Licence, or (at your option) any later version.
 10  */
 11 #include <asm/uaccess.h>
 12 #include <asm/fpu.h>
 13 #include <asm/elf.h>
 14 #include <asm/exceptions.h>
 15 
 16 #ifdef CONFIG_LAZY_SAVE_FPU
 17 struct task_struct *fpu_state_owner;
 18 #endif
 19 
 20 /*
 21  * error functions in FPU disabled exception
 22  */
 23 asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs)
 24 {
 25         die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
 26                         regs, EXCEP_FPU_DISABLED);
 27 }
 28 
 29 /*
 30  * handle an FPU operational exception
 31  * - there's a possibility that if the FPU is asynchronous, the signal might
 32  *   be meant for a process other than the current one
 33  */
 34 asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
 35 {
 36         struct task_struct *tsk = current;
 37         siginfo_t info;
 38         u32 fpcr;
 39 
 40         if (!user_mode(regs))
 41                 die_if_no_fixup("An FPU Operation exception happened in"
 42                                 " kernel space\n",
 43                                 regs, code);
 44 
 45         if (!is_using_fpu(tsk))
 46                 die_if_no_fixup("An FPU Operation exception happened,"
 47                                 " but the FPU is not in use",
 48                                 regs, code);
 49 
 50         info.si_signo = SIGFPE;
 51         info.si_errno = 0;
 52         info.si_addr = (void *) tsk->thread.uregs->pc;
 53         info.si_code = FPE_FLTINV;
 54 
 55         unlazy_fpu(tsk);
 56 
 57         fpcr = tsk->thread.fpu_state.fpcr;
 58 
 59         if (fpcr & FPCR_EC_Z)
 60                 info.si_code = FPE_FLTDIV;
 61         else if (fpcr & FPCR_EC_O)
 62                 info.si_code = FPE_FLTOVF;
 63         else if (fpcr & FPCR_EC_U)
 64                 info.si_code = FPE_FLTUND;
 65         else if (fpcr & FPCR_EC_I)
 66                 info.si_code = FPE_FLTRES;
 67 
 68         force_sig_info(SIGFPE, &info, tsk);
 69 }
 70 
 71 /*
 72  * save the FPU state to a signal context
 73  */
 74 int fpu_setup_sigcontext(struct fpucontext *fpucontext)
 75 {
 76         struct task_struct *tsk = current;
 77 
 78         if (!is_using_fpu(tsk))
 79                 return 0;
 80 
 81         /* transfer the current FPU state to memory and cause fpu_init() to be
 82          * triggered by the next attempted FPU operation by the current
 83          * process.
 84          */
 85         preempt_disable();
 86 
 87 #ifndef CONFIG_LAZY_SAVE_FPU
 88         if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
 89                 fpu_save(&tsk->thread.fpu_state);
 90                 tsk->thread.uregs->epsw &= ~EPSW_FE;
 91                 tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
 92         }
 93 #else /* !CONFIG_LAZY_SAVE_FPU */
 94         if (fpu_state_owner == tsk) {
 95                 fpu_save(&tsk->thread.fpu_state);
 96                 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
 97                 fpu_state_owner = NULL;
 98         }
 99 #endif /* !CONFIG_LAZY_SAVE_FPU */
100 
101         preempt_enable();
102 
103         /* we no longer have a valid current FPU state */
104         clear_using_fpu(tsk);
105 
106         /* transfer the saved FPU state onto the userspace stack */
107         if (copy_to_user(fpucontext,
108                          &tsk->thread.fpu_state,
109                          min(sizeof(struct fpu_state_struct),
110                              sizeof(struct fpucontext))))
111                 return -1;
112 
113         return 1;
114 }
115 
116 /*
117  * kill a process's FPU state during restoration after signal handling
118  */
119 void fpu_kill_state(struct task_struct *tsk)
120 {
121         /* disown anything left in the FPU */
122         preempt_disable();
123 
124 #ifndef CONFIG_LAZY_SAVE_FPU
125         if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
126                 tsk->thread.uregs->epsw &= ~EPSW_FE;
127                 tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
128         }
129 #else /* !CONFIG_LAZY_SAVE_FPU */
130         if (fpu_state_owner == tsk) {
131                 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
132                 fpu_state_owner = NULL;
133         }
134 #endif /* !CONFIG_LAZY_SAVE_FPU */
135 
136         preempt_enable();
137 
138         /* we no longer have a valid current FPU state */
139         clear_using_fpu(tsk);
140 }
141 
142 /*
143  * restore the FPU state from a signal context
144  */
145 int fpu_restore_sigcontext(struct fpucontext *fpucontext)
146 {
147         struct task_struct *tsk = current;
148         int ret;
149 
150         /* load up the old FPU state */
151         ret = copy_from_user(&tsk->thread.fpu_state, fpucontext,
152                              min(sizeof(struct fpu_state_struct),
153                                  sizeof(struct fpucontext)));
154         if (!ret)
155                 set_using_fpu(tsk);
156 
157         return ret;
158 }
159 
160 /*
161  * fill in the FPU structure for a core dump
162  */
163 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
164 {
165         struct task_struct *tsk = current;
166         int fpvalid;
167 
168         fpvalid = is_using_fpu(tsk);
169         if (fpvalid) {
170                 unlazy_fpu(tsk);
171                 memcpy(fpreg, &tsk->thread.fpu_state, sizeof(*fpreg));
172         }
173 
174         return fpvalid;
175 }
176 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp