source: mainline/kernel/arch/arm32/src/fpu_context.c@ 467f0c0

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

arm32: Only check cpacr on armv7. Earlier versions do not support the reg.

Add note about user level synchs to barrier.h

  • Property mode set to 100644
File size: 9.2 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 <arch/security_ext.h>
40#include <cpu.h>
41
42#define FPSID_IMPLEMENTER(r) ((r) >> 24)
43#define FPSID_SW_ONLY_FLAG (1 << 23)
44#define FPSID_SUBACHITECTURE(r) (((r) >> 16) & 0x7f)
45#define FPSID_PART_NUMBER(r) (((r) >> 8) & 0xff)
46#define FPSID_VARIANT(r) (((r) >> 4) 0xf)
47#define FPSID_REVISION(r) (((r) >> 0) 0xf)
48
49
50enum {
51 FPU_VFPv1 = 0x00,
52 FPU_VFPv2_COMMONv1 = 0x01,
53 FPU_VFPv3_COMMONv2 = 0x02,
54 FPU_VFPv3_NO_COMMON = 0x3, /* Does not support fpu exc. traps */
55 FPU_VFPv3_COMMONv3 = 0x4,
56};
57
58enum {
59 FPEXC_EX_FLAG = (1 << 31),
60 FPEXC_ENABLED_FLAG = (1 << 30),
61};
62
63/* See Architecture reference manual ch. B4.1.40 */
64enum {
65 CPACR_CP10_MASK = 0x3 << 20,
66 CPACR_CP11_MASK = 0x3 << 22,
67 CPACR_CP10_USER_ACCESS = CPACR_CP10_MASK,
68 CPACR_CP11_USER_ACCESS = CPACR_CP11_MASK,
69 NSACR_CP10_FLAG = 1 << 10,
70 NSACR_CP11_FLAG = 1 << 11,
71};
72
73/** ARM Architecture Reference Manual ch. B4.1.58, p. B$-1551 */
74enum {
75 FPSCR_N_FLAG = (1 << 31),
76 FPSCR_Z_FLAG = (1 << 30),
77 FPSCR_C_FLAG = (1 << 29),
78 FPSCR_V_FLAG = (1 << 28),
79 FPSCR_QC_FLAG = (1 << 27),
80 FPSCR_AHP_FLAG = (1 << 26),
81 FPSCR_DN_FLAG = (1 << 25),
82 FPSCR_FZ_FLAG = (1 << 24),
83 FPSCR_ROUND_MODE_MASK = (0x3 << 22),
84 FPSCR_ROUND_TO_NEAREST = (0x0 << 22),
85 FPSCR_ROUND_TO_POS_INF = (0x1 << 22),
86 FPSCR_ROUND_TO_NEG_INF = (0x2 << 22),
87 FPSCR_ROUND_TO_ZERO = (0x3 << 22),
88 FPSCR_STRIDE_MASK = (0x3 << 20),
89 FPSCR_STRIDE_SHIFT = 20,
90 FPSCR_LEN_MASK = (0x7 << 16),
91 FPSCR_LEN_SHIFT = 16,
92 FPSCR_DENORMAL_EN_FLAG = (1 << 15),
93 FPSCR_INEXACT_EN_FLAG = (1 << 12),
94 FPSCR_UNDERFLOW_EN_FLAG = (1 << 11),
95 FPSCR_OVERFLOW_EN_FLAG = (1 << 10),
96 FPSCR_ZERO_DIV_EN_FLAG = (1 << 9),
97 FPSCR_INVALID_OP_EN_FLAG = (1 << 8),
98 FPSCR_DENORMAL_FLAG = (1 << 7),
99 FPSCR_INEXACT_FLAG = (1 << 4),
100 FPSCR_UNDERFLOW_FLAG = (1 << 3),
101 FPSCR_OVERLOW_FLAG = (1 << 2),
102 FPSCR_DIV_ZERO_FLAG = (1 << 1),
103 FPSCR_INVALID_OP_FLAG = (1 << 0),
104
105 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,
106};
107
108extern uint32_t fpsid_read(void);
109extern uint32_t mvfr0_read(void);
110extern uint32_t fpscr_read(void);
111extern void fpscr_write(uint32_t);
112extern uint32_t fpexc_read(void);
113extern void fpexc_write(uint32_t);
114
115extern void fpu_context_save_s32(fpu_context_t *);
116extern void fpu_context_restore_s32(fpu_context_t *);
117extern void fpu_context_save_d16(fpu_context_t *);
118extern void fpu_context_restore_d16(fpu_context_t *);
119extern void fpu_context_save_d32(fpu_context_t *);
120extern void fpu_context_restore_d32(fpu_context_t *);
121
122static void (*save_context)(fpu_context_t *ctx);
123static void (*restore_context)(fpu_context_t *ctx);
124
125static int fpu_have_coprocessor_access()
126{
127/* The register containing the information (CPACR) is not available on armv6-
128 * rely on user decision to use CONFIG_FPU.
129 */
130#ifndef PROCESSOR_armv7_a
131 return 1;
132#endif
133 uint32_t cpacr;
134 asm volatile ("MRC p15, 0, %0, c1, c0, 2" :"=r" (cpacr)::);
135 /* FPU needs access to coprocessor 10 and 11.
136 * Moreover they need to have same access enabledd */
137 if (((cpacr & CPACR_CP10_MASK) == CPACR_CP10_USER_ACCESS) &&
138 ((cpacr & CPACR_CP11_MASK) == CPACR_CP11_USER_ACCESS))
139 return 1;
140 printf("No sccess to CP10 and CP11: %" PRIx32 "\n", cpacr);
141 return 0;
142}
143
144/** Enable coprocessor access. Turn both non-secure mode bit and generic access.
145 * Cortex A8 Manual says:
146 * "You must execute an Instruction Memory Barrier (IMB) sequence immediately
147 * after an update of the Coprocessor Access Control Register, see Memory
148 * Barriers in the ARM Architecture Reference Manual. You must not attempt to
149 * execute any instructions that are affected by the change of access rights
150 * between the IMB sequence and the register update."
151 * Cortex a8 TRM ch. 3.2.27. c1, Coprocessor Access Control Register
152 *
153 * @note do we need to call secure monitor here?
154 */
155static void fpu_enable_coprocessor_access()
156{
157/* The register containing the information (CPACR) is not available on armv6-
158 * rely on user decision to use CONFIG_FPU.
159 */
160#ifndef PROCESSOR_armv7_a
161 return;
162#endif
163 uint32_t cpr;
164 asm volatile("MRC p15, 0, %0, c1, c1, 0" : "=r" (cpr)::);
165 if (cpr & 1)
166 printf("We are in unsecure state, we can't change access\n");
167
168 /* Allow non-secure access */
169 uint32_t nsacr;
170 asm volatile ("mrc p15, 0, %0, c1, c1, 2" :"=r" (nsacr)::);
171 /* FPU needs access to coprocessor 10 and 11.
172 * Moreover, they need to have same access enabled */
173 nsacr |= NSACR_CP10_FLAG | NSACR_CP11_FLAG;
174 asm volatile ("mcr p15, 0, %0, c1, c1, 2" :"=r" (nsacr)::);
175
176#ifdef MACHINE_beagleboardxm
177 asm volatile ("isb" ::: "memory" );
178#endif
179
180 /* Allow coprocessor access */
181 uint32_t cpacr;
182 asm volatile ("mrc p15, 0, %0, c1, c0, 2" :"=r" (cpacr)::);
183 printf("CPACR before: %x\n", cpacr);
184 /* FPU needs access to coprocessor 10 and 11.
185 * Moreover, they need to have same access enabled */
186 cpacr |= CPACR_CP10_USER_ACCESS;
187 cpacr |= CPACR_CP11_USER_ACCESS;
188 asm volatile ("mcr p15, 0, %0, c1, c0, 2" :"=r" (cpacr)::);
189 printf("CPACR after: %x\n", cpacr);
190
191#ifdef MACHINE_beagleboardxm
192 asm volatile ("isb" ::: "memory" );
193#endif
194}
195
196
197void fpu_init(void)
198{
199 /* Enable coprocessor access*/
200 fpu_enable_coprocessor_access();
201
202 /* Check if we succeeded */
203 if (!fpu_have_coprocessor_access())
204 return;
205
206 /* Clear all fpu flags */
207 fpexc_write(0);
208 fpu_enable();
209 /* Mask all exception traps,
210 * The bits are RAZ/WI on archs that don't support fpu exc traps.
211 */
212 fpscr_write(fpscr_read() & ~FPSCR_EN_ALL);
213}
214
215void fpu_setup(void)
216{
217 /* Check if we have access */
218 if (!fpu_have_coprocessor_access())
219 return;
220
221 const uint32_t fpsid = fpsid_read();
222 if (fpsid & FPSID_SW_ONLY_FLAG) {
223 printf("No FPU avaiable\n");
224 return;
225 }
226 switch (FPSID_SUBACHITECTURE(fpsid))
227 {
228 case FPU_VFPv1:
229 printf("Detected VFPv1\n");
230 save_context = fpu_context_save_s32;
231 restore_context = fpu_context_restore_s32;
232 break;
233 case FPU_VFPv2_COMMONv1:
234 printf("Detected VFPv2\n");
235 save_context = fpu_context_save_d16;
236 restore_context = fpu_context_restore_d16;
237 break;
238 case FPU_VFPv3_COMMONv2:
239 case FPU_VFPv3_NO_COMMON:
240 case FPU_VFPv3_COMMONv3: {
241 const uint32_t mvfr0 = mvfr0_read();
242 /* See page B4-1637 */
243 if ((mvfr0 & 0xf) == 0x1) {
244 printf("Detected VFPv3+ with 16 regs\n");
245 save_context = fpu_context_save_d16;
246 restore_context = fpu_context_restore_d16;
247 } else {
248 printf("Detected VFPv3+ with 32 regs\n");
249 save_context = fpu_context_save_d32;
250 restore_context = fpu_context_restore_d32;
251 }
252 break;
253 }
254
255 }
256}
257
258bool handle_if_fpu_exception(void)
259{
260 /* Check if we have access */
261 if (!fpu_have_coprocessor_access())
262 return false;
263
264 const uint32_t fpexc = fpexc_read();
265 if (fpexc & FPEXC_ENABLED_FLAG) {
266 const uint32_t fpscr = fpscr_read();
267 printf("FPU exception\n"
268 "\tFPEXC: %" PRIx32 " FPSCR: %" PRIx32 "\n", fpexc, fpscr);
269 return false;
270 }
271#ifdef CONFIG_FPU_LAZY
272 scheduler_fpu_lazy_request();
273 return true;
274#else
275 return false;
276#endif
277}
278
279void fpu_enable(void)
280{
281 /* Check if we have access */
282 if (!fpu_have_coprocessor_access())
283 return;
284 /* Enable FPU instructions */
285 fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
286}
287
288void fpu_disable(void)
289{
290 /* Check if we have access */
291 if (!fpu_have_coprocessor_access())
292 return;
293 /* Disable FPU instructions */
294 fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
295}
296
297void fpu_context_save(fpu_context_t *ctx)
298{
299 /* Check if we have access */
300 if (!fpu_have_coprocessor_access())
301 return;
302 const uint32_t fpexc = fpexc_read();
303
304 if (fpexc & FPEXC_EX_FLAG) {
305 printf("EX FPU flag is on, things will fail\n");
306 //TODO implement common subarch context saving
307 }
308 if (save_context)
309 save_context(ctx);
310}
311
312void fpu_context_restore(fpu_context_t *ctx)
313{
314 /* Check if we have access */
315 if (!fpu_have_coprocessor_access())
316 return;
317 if (restore_context)
318 restore_context(ctx);
319}
Note: See TracBrowser for help on using the repository browser.