source: mainline/kernel/arch/arm32/src/fpu_context.c@ 0abc2ae

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0abc2ae was 6ff23ff, checked in by Jiri Svoboda <jiri@…>, 8 years ago

More comment fixing (ccheck).

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