source: mainline/kernel/arch/arm32/src/fpu_context.c@ 46a6a5d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 46a6a5d was ce60be1, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

arm32, fpu: Mask all traps during fpu initialization.

We do this on ia32 and amd64 too

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup arm32
30 * @{
31 */
32/** @file
33 * @brief arm32 FPU context
34 */
35
36#include <fpu_context.h>
37#include <arch.h>
38#include <arch/types.h>
39#include <cpu.h>
40
41#define FPSID_IMPLEMENTER(r) ((r) >> 24)
42#define FPSID_SW_ONLY_FLAG (1 << 23)
43#define FPSID_SUBACHITECTURE(r) (((r) >> 16) & 0x7f)
44#define FPSID_PART_NUMBER(r) (((r) >> 8) & 0xff)
45#define FPSID_VARIANT(r) (((r) >> 4) 0xf)
46#define FPSID_REVISION(r) (((r) >> 0) 0xf)
47
48
49enum {
50 FPU_VFPv1 = 0x00,
51 FPU_VFPv2_COMMONv1 = 0x01,
52 FPU_VFPv3_COMMONv2 = 0x02,
53 FPU_VFPv3_NO_COMMON = 0x3, /* Does not support fpu exc. traps */
54 FPU_VFPv3_COMMONv3 = 0x4,
55};
56
57enum {
58 FPEXC_EX_FLAG = (1 << 31),
59 FPEXC_ENABLED_FLAG = (1 << 30),
60};
61
62/** ARM Architecture Reference Manual ch. B4.1.58, p. B$-1551 */
63enum {
64 FPSCR_N_FLAG = (1 << 31),
65 FPSCR_Z_FLAG = (1 << 30),
66 FPSCR_C_FLAG = (1 << 29),
67 FPSCR_V_FLAG = (1 << 28),
68 FPSCR_QC_FLAG = (1 << 27),
69 FPSCR_AHP_FLAG = (1 << 26),
70 FPSCR_DN_FLAG = (1 << 25),
71 FPSCR_FZ_FLAG = (1 << 24),
72 FPSCR_ROUND_MODE_MASK = (0x3 << 22),
73 FPSCR_ROUND_TO_NEAREST = (0x0 << 22),
74 FPSCR_ROUND_TO_POS_INF = (0x1 << 22),
75 FPSCR_ROUND_TO_NEG_INF = (0x2 << 22),
76 FPSCR_ROUND_TO_ZERO = (0x3 << 22),
77 FPSCR_STRIDE_MASK = (0x3 << 20),
78 FPSCR_STRIDE_SHIFT = 20,
79 FPSCR_LEN_MASK = (0x7 << 16),
80 FPSCR_LEN_SHIFT = 16,
81 FPSCR_DENORMAL_EN_FLAG = (1 << 15),
82 FPSCR_INEXACT_EN_FLAG = (1 << 12),
83 FPSCR_UNDERFLOW_EN_FLAG = (1 << 11),
84 FPSCR_OVERFLOW_EN_FLAG = (1 << 10),
85 FPSCR_ZERO_DIV_EN_FLAG = (1 << 9),
86 FPSCR_INVALID_OP_EN_FLAG = (1 << 8),
87 FPSCR_DENORMAL_FLAG = (1 << 7),
88 FPSCR_INEXACT_FLAG = (1 << 4),
89 FPSCR_UNDERFLOW_FLAG = (1 << 3),
90 FPSCR_OVERLOW_FLAG = (1 << 2),
91 FPSCR_DIV_ZERO_FLAG = (1 << 1),
92 FPSCR_INVALID_OP_FLAG = (1 << 0),
93
94 FPSCR_EN_ALL = FPSCR_DENORMAL_EN_FLAG | FPSCR_INEXACT_EN_FLAG | FPSCR_UNDERFLOW_EN_FLAG | FPSCR_OVERFLOW_EN_FLAG | FPSCR_ZERO_DIV_EN_FLAG | FPSCR_INVALID_OP_EN_FLAG,
95};
96
97static inline uint32_t fpscr_read()
98{
99 uint32_t reg;
100 asm volatile (
101 "vmrs %0, fpscr\n"
102 :"=r" (reg)::
103 );
104 return reg;
105}
106
107static inline void fpscr_write(uint32_t val)
108{
109 asm volatile (
110 "vmsr fpscr, %0\n"
111 ::"r" (val):
112 );
113}
114
115static inline uint32_t fpexc_read()
116{
117 uint32_t reg;
118 asm volatile (
119 "vmrs %0, fpexc\n"
120 :"=r" (reg)::
121 );
122 return reg;
123}
124
125static inline void fpexc_write(uint32_t val)
126{
127 asm volatile (
128 "vmsr fpexc, %0\n"
129 ::"r" (val):
130 );
131}
132
133static void (*save_context)(fpu_context_t *ctx);
134static void (*restore_context)(fpu_context_t *ctx);
135
136/** Saves 32 single precision fpu registers.
137 * @param ctx FPU context area.
138 * Used by VFPv1
139 */
140static void fpu_context_save_s32(fpu_context_t *ctx)
141{
142 asm volatile (
143 "vmrs r1, fpexc\n"
144 "vmrs r2, fpscr\n"
145 "stmia %0!, {r1, r2}\n"
146 "vstmia %0!, {s0-s31}\n"
147 ::"r" (ctx): "r1","r2","memory"
148 );
149}
150
151/** Restores 32 single precision fpu registers.
152 * @param ctx FPU context area.
153 * Used by VFPv1
154 */
155static void fpu_context_restore_s32(fpu_context_t *ctx)
156{
157 asm volatile (
158 "ldmia %0!, {r1, r2}\n"
159 "vmsr fpexc, r1\n"
160 "vmsr fpscr, r2\n"
161 "vldmia %0!, {s0-s31}\n"
162 ::"r" (ctx): "r1","r2"
163 );
164}
165
166/** Saves 16 double precision fpu registers.
167 * @param ctx FPU context area.
168 * Used by VFPv2, VFPv3-d16, and VFPv4-d16.
169 */
170static void fpu_context_save_d16(fpu_context_t *ctx)
171{
172 asm volatile (
173 "vmrs r1, fpexc\n"
174 "vmrs r2, fpscr\n"
175 "stmia %0!, {r1, r2}\n"
176 "vstmia %0!, {d0-d15}\n"
177 ::"r" (ctx): "r1","r2","memory"
178 );
179}
180
181/** Restores 16 double precision fpu registers.
182 * @param ctx FPU context area.
183 * Used by VFPv2, VFPv3-d16, and VFPv4-d16.
184 */
185static void fpu_context_restore_d16(fpu_context_t *ctx)
186{
187 asm volatile (
188 "ldmia %0!, {r1, r2}\n"
189 "vmsr fpexc, r1\n"
190 "vmsr fpscr, r2\n"
191 "vldmia %0!, {d0-d15}\n"
192 ::"r" (ctx): "r1","r2"
193 );
194}
195
196/** Saves 32 double precision fpu registers.
197 * @param ctx FPU context area.
198 * Used by VFPv3-d32, VFPv4-d32, and advanced SIMD.
199 */
200static void fpu_context_save_d32(fpu_context_t *ctx)
201{
202 asm volatile (
203 "vmrs r1, fpexc\n"
204 "stmia %0!, {r1}\n"
205 "vmrs r1, fpscr\n"
206 "stmia %0!, {r1}\n"
207 "vstmia %0!, {d0-d15}\n"
208 "vstmia %0!, {d16-d31}\n"
209 ::"r" (ctx): "r1","memory"
210 );
211}
212
213/** Restores 32 double precision fpu registers.
214 * @param ctx FPU context area.
215 * Used by VFPv3-d32, VFPv4-d32, and advanced SIMD.
216 */
217static void fpu_context_restore_d32(fpu_context_t *ctx)
218{
219 asm volatile (
220 "ldmia %0!, {r1}\n"
221 "vmsr fpexc, r1\n"
222 "ldmia %0!, {r1}\n"
223 "vmsr fpscr, r1\n"
224 "vldmia %0!, {d0-d15}\n"
225 "vldmia %0!, {d16-d31}\n"
226 ::"r" (ctx): "r1"
227 );
228}
229
230void fpu_init(void)
231{
232 /* Clear all fpu flags */
233 fpexc_write(0);
234 fpu_enable();
235 /* Mask all exception traps,
236 * The bits are RAZ/WI on archs that don't support fpu exc traps.
237 */
238 fpscr_write(fpscr_read() & ~FPSCR_EN_ALL);
239}
240
241void fpu_setup(void)
242{
243 uint32_t fpsid = 0;
244 asm volatile (
245 "vmrs %0, fpsid\n"
246 :"=r"(fpsid)::
247 );
248 if (fpsid & FPSID_SW_ONLY_FLAG) {
249 printf("No FPU avaiable\n");
250 return;
251 }
252 switch (FPSID_SUBACHITECTURE(fpsid))
253 {
254 case FPU_VFPv1:
255 printf("Detected VFPv1\n");
256 save_context = fpu_context_save_s32;
257 restore_context = fpu_context_restore_s32;
258 break;
259 case FPU_VFPv2_COMMONv1:
260 printf("Detected VFPv2\n");
261 save_context = fpu_context_save_d16;
262 restore_context = fpu_context_restore_d16;
263 break;
264 case FPU_VFPv3_COMMONv2:
265 case FPU_VFPv3_NO_COMMON:
266 case FPU_VFPv3_COMMONv3: {
267 uint32_t mvfr0 = 0;
268 asm volatile (
269 "vmrs %0,mvfr0\n"
270 :"=r"(mvfr0)::
271 );
272 /* See page B4-1637 */
273 if ((mvfr0 & 0xf) == 0x1) {
274 printf("Detected VFPv3+ with 16 regs\n");
275 save_context = fpu_context_save_d16;
276 restore_context = fpu_context_restore_d16;
277 } else {
278 printf("Detected VFPv3+ with 32 regs\n");
279 save_context = fpu_context_save_d32;
280 restore_context = fpu_context_restore_d32;
281 }
282 break;
283 }
284
285 }
286}
287
288bool handle_if_fpu_exception(void)
289{
290 const uint32_t fpexc = fpexc_read();
291 if (fpexc & FPEXC_ENABLED_FLAG) {
292 const uint32_t fpscr = fpscr_read();
293 printf("FPU exception\n"
294 "\tFPEXC: %" PRIx32 " FPSCR: %" PRIx32 "\n", fpexc, fpscr);
295 return false;
296 }
297#ifdef CONFIG_FPU_LAZY
298 scheduler_fpu_lazy_request();
299 return true;
300#else
301 return false;
302#endif
303}
304
305void fpu_enable(void)
306{
307 /* Enable FPU instructions */
308 fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
309}
310
311void fpu_disable(void)
312{
313 /* Disable FPU instructions */
314 fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
315}
316
317void fpu_context_save(fpu_context_t *ctx)
318{
319 const uint32_t fpexc = fpexc_read();
320
321 if (fpexc & FPEXC_EX_FLAG) {
322 printf("EX FPU flag is on, things will fail\n");
323 //TODO implement common subarch context saving
324 }
325 if (save_context)
326 save_context(ctx);
327}
328
329void fpu_context_restore(fpu_context_t *ctx)
330{
331 if (restore_context)
332 restore_context(ctx);
333}
Note: See TracBrowser for help on using the repository browser.