Changeset 660e8fa in mainline for kernel/arch/arm32/src/fpu_context.c


Ignore:
Timestamp:
2013-01-18T20:49:35Z (11 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5fcd537, 6218d4b
Parents:
b5a3b50 (diff), a640bc1 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge arm fpu fixes.

Enable FPU coprocessor (cp10/11) access.
Test for cp10/11 access before using fpu instructions or touching fpu regs.
Move fpu instructions to single asm file instead of allowing it in kernel globally.
Add cp15 helper functions.
Add (unused) security extensions header.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/src/fpu_context.c

    rb5a3b50 r660e8fa  
    3737#include <arch.h>
    3838#include <arch/types.h>
     39#include <arch/security_ext.h>
     40#include <arch/cp15.h>
    3941#include <cpu.h>
    4042
     
    5557};
    5658
     59extern uint32_t fpsid_read(void);
     60extern uint32_t mvfr0_read(void);
     61
    5762enum {
    5863        FPEXC_EX_FLAG = (1 << 31),
    5964        FPEXC_ENABLED_FLAG = (1 << 30),
    6065};
     66extern uint32_t fpexc_read(void);
     67extern void fpexc_write(uint32_t);
    6168
    6269/** ARM Architecture Reference Manual ch. B4.1.58, p. B$-1551 */
     
    94101        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,
    95102};
    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 }
     103extern uint32_t fpscr_read(void);
     104extern void fpscr_write(uint32_t);
     105
     106extern void fpu_context_save_s32(fpu_context_t *);
     107extern void fpu_context_restore_s32(fpu_context_t *);
     108extern void fpu_context_save_d16(fpu_context_t *);
     109extern void fpu_context_restore_d16(fpu_context_t *);
     110extern void fpu_context_save_d32(fpu_context_t *);
     111extern void fpu_context_restore_d32(fpu_context_t *);
    132112
    133113static void (*save_context)(fpu_context_t *ctx);
    134114static void (*restore_context)(fpu_context_t *ctx);
    135115
    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 }
     116static 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_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 enabledd */
     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 */
     145static 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#ifndef PROCESSOR_armv7_a
     151        return;
     152#endif
     153
     154        /* Allow coprocessor access */
     155        uint32_t cpacr = CPACR_read();
     156        /* FPU needs access to coprocessor 10 and 11.
     157         * Moreover, they need to have same access enabled */
     158        cpacr &= ~(CPACR_CP_MASK(10) | CPACR_CP_MASK(11));
     159        cpacr |= (CPACR_CP_FULL_ACCESS(10) | CPACR_CP_FULL_ACCESS(11));
     160        CPACR_write(cpacr);
     161
     162        smc_coherence(0);
     163}
     164
    229165
    230166void fpu_init(void)
    231167{
     168        /* Check if we have access */
     169        if (!fpu_have_coprocessor_access())
     170                return;
     171
    232172        /* Clear all fpu flags */
    233173        fpexc_write(0);
     
    241181void fpu_setup(void)
    242182{
    243         uint32_t fpsid = 0;
    244         asm volatile (
    245                 "vmrs %0, fpsid\n"
    246                 :"=r"(fpsid)::
    247         );
     183        /* Enable coprocessor access*/
     184        fpu_enable_coprocessor_access();
     185
     186        /* Check if we succeeded */
     187        if (!fpu_have_coprocessor_access())
     188                return;
     189
     190        const uint32_t fpsid = fpsid_read();
    248191        if (fpsid & FPSID_SW_ONLY_FLAG) {
    249192                printf("No FPU avaiable\n");
     
    265208        case FPU_VFPv3_NO_COMMON:
    266209        case FPU_VFPv3_COMMONv3: {
    267                 uint32_t mvfr0 = 0;
    268                 asm volatile (
    269                         "vmrs %0,mvfr0\n"
    270                         :"=r"(mvfr0)::
    271                 );
     210                const uint32_t mvfr0 = mvfr0_read();
    272211                /* See page B4-1637 */
    273212                if ((mvfr0 & 0xf) == 0x1) {
     
    288227bool handle_if_fpu_exception(void)
    289228{
     229        /* Check if we have access */
     230        if (!fpu_have_coprocessor_access())
     231                return false;
     232
    290233        const uint32_t fpexc = fpexc_read();
    291234        if (fpexc & FPEXC_ENABLED_FLAG) {
     
    305248void fpu_enable(void)
    306249{
     250        /* Check if we have access */
     251        if (!fpu_have_coprocessor_access())
     252                return;
    307253        /* Enable FPU instructions */
    308254        fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
     
    311257void fpu_disable(void)
    312258{
     259        /* Check if we have access */
     260        if (!fpu_have_coprocessor_access())
     261                return;
    313262        /* Disable FPU instructions */
    314263        fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
     
    317266void fpu_context_save(fpu_context_t *ctx)
    318267{
     268        /* This is only necessary if we enable fpu exceptions. */
     269#if 0
    319270        const uint32_t fpexc = fpexc_read();
    320271
     
    323274                //TODO implement common subarch context saving
    324275        }
     276#endif
    325277        if (save_context)
    326278                save_context(ctx);
Note: See TracChangeset for help on using the changeset viewer.