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

TOMOYO Linux Cross Reference
Linux/arch/csky/abiv2/fpu.c

Version: ~ [ linux-5.5 ] ~ [ linux-5.4.15 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.98 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.167 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.211 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.211 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ 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 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
  3 
  4 #include <linux/ptrace.h>
  5 #include <linux/uaccess.h>
  6 #include <abi/reg_ops.h>
  7 
  8 #define MTCR_MASK       0xFC00FFE0
  9 #define MFCR_MASK       0xFC00FFE0
 10 #define MTCR_DIST       0xC0006420
 11 #define MFCR_DIST       0xC0006020
 12 
 13 void __init init_fpu(void)
 14 {
 15         mtcr("cr<1, 2>", 0);
 16 }
 17 
 18 /*
 19  * fpu_libc_helper() is to help libc to excute:
 20  *  - mfcr %a, cr<1, 2>
 21  *  - mfcr %a, cr<2, 2>
 22  *  - mtcr %a, cr<1, 2>
 23  *  - mtcr %a, cr<2, 2>
 24  */
 25 int fpu_libc_helper(struct pt_regs *regs)
 26 {
 27         int fault;
 28         unsigned long instrptr, regx = 0;
 29         unsigned long index = 0, tmp = 0;
 30         unsigned long tinstr = 0;
 31         u16 instr_hi, instr_low;
 32 
 33         instrptr = instruction_pointer(regs);
 34         if (instrptr & 1)
 35                 return 0;
 36 
 37         fault = __get_user(instr_low, (u16 *)instrptr);
 38         if (fault)
 39                 return 0;
 40 
 41         fault = __get_user(instr_hi, (u16 *)(instrptr + 2));
 42         if (fault)
 43                 return 0;
 44 
 45         tinstr = instr_hi | ((unsigned long)instr_low << 16);
 46 
 47         if (((tinstr >> 21) & 0x1F) != 2)
 48                 return 0;
 49 
 50         if ((tinstr & MTCR_MASK) == MTCR_DIST) {
 51                 index = (tinstr >> 16) & 0x1F;
 52                 if (index > 13)
 53                         return 0;
 54 
 55                 tmp = tinstr & 0x1F;
 56                 if (tmp > 2)
 57                         return 0;
 58 
 59                 regx =  *(&regs->a0 + index);
 60 
 61                 if (tmp == 1)
 62                         mtcr("cr<1, 2>", regx);
 63                 else if (tmp == 2)
 64                         mtcr("cr<2, 2>", regx);
 65                 else
 66                         return 0;
 67 
 68                 regs->pc += 4;
 69                 return 1;
 70         }
 71 
 72         if ((tinstr & MFCR_MASK) == MFCR_DIST) {
 73                 index = tinstr & 0x1F;
 74                 if (index > 13)
 75                         return 0;
 76 
 77                 tmp = ((tinstr >> 16) & 0x1F);
 78                 if (tmp > 2)
 79                         return 0;
 80 
 81                 if (tmp == 1)
 82                         regx = mfcr("cr<1, 2>");
 83                 else if (tmp == 2)
 84                         regx = mfcr("cr<2, 2>");
 85                 else
 86                         return 0;
 87 
 88                 *(&regs->a0 + index) = regx;
 89 
 90                 regs->pc += 4;
 91                 return 1;
 92         }
 93 
 94         return 0;
 95 }
 96 
 97 void fpu_fpe(struct pt_regs *regs)
 98 {
 99         int sig, code;
100         unsigned int fesr;
101 
102         fesr = mfcr("cr<2, 2>");
103 
104         sig = SIGFPE;
105         code = FPE_FLTUNK;
106 
107         if (fesr & FPE_ILLE) {
108                 sig = SIGILL;
109                 code = ILL_ILLOPC;
110         } else if (fesr & FPE_IDC) {
111                 sig = SIGILL;
112                 code = ILL_ILLOPN;
113         } else if (fesr & FPE_FEC) {
114                 sig = SIGFPE;
115                 if (fesr & FPE_IOC)
116                         code = FPE_FLTINV;
117                 else if (fesr & FPE_DZC)
118                         code = FPE_FLTDIV;
119                 else if (fesr & FPE_UFC)
120                         code = FPE_FLTUND;
121                 else if (fesr & FPE_OFC)
122                         code = FPE_FLTOVF;
123                 else if (fesr & FPE_IXC)
124                         code = FPE_FLTRES;
125         }
126 
127         force_sig_fault(sig, code, (void __user *)regs->pc, current);
128 }
129 
130 #define FMFVR_FPU_REGS(vrx, vry)        \
131         "fmfvrl %0, "#vrx"\n"           \
132         "fmfvrh %1, "#vrx"\n"           \
133         "fmfvrl %2, "#vry"\n"           \
134         "fmfvrh %3, "#vry"\n"
135 
136 #define FMTVR_FPU_REGS(vrx, vry)        \
137         "fmtvrl "#vrx", %0\n"           \
138         "fmtvrh "#vrx", %1\n"           \
139         "fmtvrl "#vry", %2\n"           \
140         "fmtvrh "#vry", %3\n"
141 
142 #define STW_FPU_REGS(a, b, c, d)        \
143         "stw    %0, (%4, "#a")\n"       \
144         "stw    %1, (%4, "#b")\n"       \
145         "stw    %2, (%4, "#c")\n"       \
146         "stw    %3, (%4, "#d")\n"
147 
148 #define LDW_FPU_REGS(a, b, c, d)        \
149         "ldw    %0, (%4, "#a")\n"       \
150         "ldw    %1, (%4, "#b")\n"       \
151         "ldw    %2, (%4, "#c")\n"       \
152         "ldw    %3, (%4, "#d")\n"
153 
154 void save_to_user_fp(struct user_fp *user_fp)
155 {
156         unsigned long flg;
157         unsigned long tmp1, tmp2;
158         unsigned long *fpregs;
159 
160         local_irq_save(flg);
161 
162         tmp1 = mfcr("cr<1, 2>");
163         tmp2 = mfcr("cr<2, 2>");
164 
165         user_fp->fcr = tmp1;
166         user_fp->fesr = tmp2;
167 
168         fpregs = &user_fp->vr[0];
169 #ifdef CONFIG_CPU_HAS_FPUV2
170 #ifdef CONFIG_CPU_HAS_VDSP
171         asm volatile(
172                 "vstmu.32    vr0-vr3,   (%0)\n"
173                 "vstmu.32    vr4-vr7,   (%0)\n"
174                 "vstmu.32    vr8-vr11,  (%0)\n"
175                 "vstmu.32    vr12-vr15, (%0)\n"
176                 "fstmu.64    vr16-vr31, (%0)\n"
177                 : "+a"(fpregs)
178                 ::"memory");
179 #else
180         asm volatile(
181                 "fstmu.64    vr0-vr31,  (%0)\n"
182                 : "+a"(fpregs)
183                 ::"memory");
184 #endif
185 #else
186         {
187         unsigned long tmp3, tmp4;
188 
189         asm volatile(
190                 FMFVR_FPU_REGS(vr0, vr1)
191                 STW_FPU_REGS(0, 4, 16, 20)
192                 FMFVR_FPU_REGS(vr2, vr3)
193                 STW_FPU_REGS(32, 36, 48, 52)
194                 FMFVR_FPU_REGS(vr4, vr5)
195                 STW_FPU_REGS(64, 68, 80, 84)
196                 FMFVR_FPU_REGS(vr6, vr7)
197                 STW_FPU_REGS(96, 100, 112, 116)
198                 "addi   %4, 128\n"
199                 FMFVR_FPU_REGS(vr8, vr9)
200                 STW_FPU_REGS(0, 4, 16, 20)
201                 FMFVR_FPU_REGS(vr10, vr11)
202                 STW_FPU_REGS(32, 36, 48, 52)
203                 FMFVR_FPU_REGS(vr12, vr13)
204                 STW_FPU_REGS(64, 68, 80, 84)
205                 FMFVR_FPU_REGS(vr14, vr15)
206                 STW_FPU_REGS(96, 100, 112, 116)
207                 : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
208                   "=a"(tmp4), "+a"(fpregs)
209                 ::"memory");
210         }
211 #endif
212 
213         local_irq_restore(flg);
214 }
215 
216 void restore_from_user_fp(struct user_fp *user_fp)
217 {
218         unsigned long flg;
219         unsigned long tmp1, tmp2;
220         unsigned long *fpregs;
221 
222         local_irq_save(flg);
223 
224         tmp1 = user_fp->fcr;
225         tmp2 = user_fp->fesr;
226 
227         mtcr("cr<1, 2>", tmp1);
228         mtcr("cr<2, 2>", tmp2);
229 
230         fpregs = &user_fp->vr[0];
231 #ifdef CONFIG_CPU_HAS_FPUV2
232 #ifdef CONFIG_CPU_HAS_VDSP
233         asm volatile(
234                 "vldmu.32    vr0-vr3,   (%0)\n"
235                 "vldmu.32    vr4-vr7,   (%0)\n"
236                 "vldmu.32    vr8-vr11,  (%0)\n"
237                 "vldmu.32    vr12-vr15, (%0)\n"
238                 "fldmu.64    vr16-vr31, (%0)\n"
239                 : "+a"(fpregs)
240                 ::"memory");
241 #else
242         asm volatile(
243                 "fldmu.64    vr0-vr31,  (%0)\n"
244                 : "+a"(fpregs)
245                 ::"memory");
246 #endif
247 #else
248         {
249         unsigned long tmp3, tmp4;
250 
251         asm volatile(
252                 LDW_FPU_REGS(0, 4, 16, 20)
253                 FMTVR_FPU_REGS(vr0, vr1)
254                 LDW_FPU_REGS(32, 36, 48, 52)
255                 FMTVR_FPU_REGS(vr2, vr3)
256                 LDW_FPU_REGS(64, 68, 80, 84)
257                 FMTVR_FPU_REGS(vr4, vr5)
258                 LDW_FPU_REGS(96, 100, 112, 116)
259                 FMTVR_FPU_REGS(vr6, vr7)
260                 "addi   %4, 128\n"
261                 LDW_FPU_REGS(0, 4, 16, 20)
262                 FMTVR_FPU_REGS(vr8, vr9)
263                 LDW_FPU_REGS(32, 36, 48, 52)
264                 FMTVR_FPU_REGS(vr10, vr11)
265                 LDW_FPU_REGS(64, 68, 80, 84)
266                 FMTVR_FPU_REGS(vr12, vr13)
267                 LDW_FPU_REGS(96, 100, 112, 116)
268                 FMTVR_FPU_REGS(vr14, vr15)
269                 : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
270                   "=a"(tmp4), "+a"(fpregs)
271                 ::"memory");
272         }
273 #endif
274         local_irq_restore(flg);
275 }
276 

~ [ 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