Changes in kernel/arch/arm32/src/fpu_context.c [ce60be1:5c4356b] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/arm32/src/fpu_context.c
rce60be1 r5c4356b 37 37 #include <arch.h> 38 38 #include <arch/types.h> 39 #include <arch/security_ext.h> 40 #include <arch/cp15.h> 39 41 #include <cpu.h> 40 42 … … 55 57 }; 56 58 59 extern uint32_t fpsid_read(void); 60 extern uint32_t mvfr0_read(void); 61 57 62 enum { 58 63 FPEXC_EX_FLAG = (1 << 31), 59 64 FPEXC_ENABLED_FLAG = (1 << 30), 60 65 }; 66 extern uint32_t fpexc_read(void); 67 extern void fpexc_write(uint32_t); 61 68 62 69 /** ARM Architecture Reference Manual ch. B4.1.58, p. B$-1551 */ … … 94 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, 95 102 }; 96 97 static 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 107 static inline void fpscr_write(uint32_t val) 108 { 109 asm volatile ( 110 "vmsr fpscr, %0\n" 111 ::"r" (val): 112 ); 113 } 114 115 static 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 125 static inline void fpexc_write(uint32_t val) 126 { 127 asm volatile ( 128 "vmsr fpexc, %0\n" 129 ::"r" (val): 130 ); 131 } 103 extern uint32_t fpscr_read(void); 104 extern void fpscr_write(uint32_t); 105 106 extern void fpu_context_save_s32(fpu_context_t *); 107 extern void fpu_context_restore_s32(fpu_context_t *); 108 extern void fpu_context_save_d16(fpu_context_t *); 109 extern void fpu_context_restore_d16(fpu_context_t *); 110 extern void fpu_context_save_d32(fpu_context_t *); 111 extern void fpu_context_restore_d32(fpu_context_t *); 132 112 133 113 static void (*save_context)(fpu_context_t *ctx); 134 114 static void (*restore_context)(fpu_context_t *ctx); 135 115 136 /** Saves 32 single precision fpu registers. 137 * @param ctx FPU context area. 138 * Used by VFPv1 139 */ 140 static 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 */ 155 static 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 */ 170 static 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 */ 185 static 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 */ 200 static 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 */ 217 static 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 } 116 static int fpu_have_coprocessor_access() 117 { 118 /* The register containing the information (CPACR) is not available on armv6- 119 * rely on user decision to use CONFIG_FPU. 120 */ 121 #ifdef PROCESSOR_ARCH_armv7_a 122 const uint32_t cpacr = CPACR_read(); 123 /* FPU needs access to coprocessor 10 and 11. 124 * Moreover they need to have same access enabled */ 125 if (((cpacr & CPACR_CP_MASK(10)) != CPACR_CP_FULL_ACCESS(10)) && 126 ((cpacr & CPACR_CP_MASK(11)) != CPACR_CP_FULL_ACCESS(11))) { 127 printf("No access to CP10 and CP11: %" PRIx32 "\n", cpacr); 128 return 0; 129 } 130 #endif 131 return 1; 132 } 133 134 /** Enable coprocessor access. Turn both non-secure mode bit and generic access. 135 * Cortex A8 Manual says: 136 * "You must execute an Instruction Memory Barrier (IMB) sequence immediately 137 * after an update of the Coprocessor Access Control Register, see Memory 138 * Barriers in the ARM Architecture Reference Manual. You must not attempt to 139 * execute any instructions that are affected by the change of access rights 140 * between the IMB sequence and the register update." 141 * Cortex a8 TRM ch. 3.2.27. c1, Coprocessor Access Control Register 142 * 143 * @note do we need to call secure monitor here? 144 */ 145 static void fpu_enable_coprocessor_access() 146 { 147 /* The register containing the information (CPACR) is not available on armv6- 148 * rely on user decision to use CONFIG_FPU. 149 */ 150 #ifdef PROCESSOR_ARCH_armv7_a 151 /* Allow coprocessor access */ 152 uint32_t cpacr = CPACR_read(); 153 /* FPU needs access to coprocessor 10 and 11. 154 * Moreover, they need to have same access enabled */ 155 cpacr &= ~(CPACR_CP_MASK(10) | CPACR_CP_MASK(11)); 156 cpacr |= (CPACR_CP_FULL_ACCESS(10) | CPACR_CP_FULL_ACCESS(11)); 157 CPACR_write(cpacr); 158 #endif 159 } 160 229 161 230 162 void fpu_init(void) 231 163 { 164 /* Check if we have access */ 165 if (!fpu_have_coprocessor_access()) 166 return; 167 232 168 /* Clear all fpu flags */ 233 169 fpexc_write(0); … … 241 177 void fpu_setup(void) 242 178 { 243 uint32_t fpsid = 0; 244 asm volatile ( 245 "vmrs %0, fpsid\n" 246 :"=r"(fpsid):: 247 ); 179 /* Enable coprocessor access*/ 180 fpu_enable_coprocessor_access(); 181 182 /* Check if we succeeded */ 183 if (!fpu_have_coprocessor_access()) 184 return; 185 186 const uint32_t fpsid = fpsid_read(); 248 187 if (fpsid & FPSID_SW_ONLY_FLAG) { 249 188 printf("No FPU avaiable\n"); … … 265 204 case FPU_VFPv3_NO_COMMON: 266 205 case FPU_VFPv3_COMMONv3: { 267 uint32_t mvfr0 = 0; 268 asm volatile ( 269 "vmrs %0,mvfr0\n" 270 :"=r"(mvfr0):: 271 ); 206 const uint32_t mvfr0 = mvfr0_read(); 272 207 /* See page B4-1637 */ 273 208 if ((mvfr0 & 0xf) == 0x1) { … … 288 223 bool handle_if_fpu_exception(void) 289 224 { 225 /* Check if we have access */ 226 if (!fpu_have_coprocessor_access()) 227 return false; 228 290 229 const uint32_t fpexc = fpexc_read(); 291 230 if (fpexc & FPEXC_ENABLED_FLAG) { … … 305 244 void fpu_enable(void) 306 245 { 246 /* Check if we have access */ 247 if (!fpu_have_coprocessor_access()) 248 return; 307 249 /* Enable FPU instructions */ 308 250 fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG); … … 311 253 void fpu_disable(void) 312 254 { 255 /* Check if we have access */ 256 if (!fpu_have_coprocessor_access()) 257 return; 313 258 /* Disable FPU instructions */ 314 259 fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG); … … 317 262 void fpu_context_save(fpu_context_t *ctx) 318 263 { 264 /* This is only necessary if we enable fpu exceptions. */ 265 #if 0 319 266 const uint32_t fpexc = fpexc_read(); 320 267 … … 323 270 //TODO implement common subarch context saving 324 271 } 272 #endif 325 273 if (save_context) 326 274 save_context(ctx);
Note:
See TracChangeset
for help on using the changeset viewer.