Changeset 2b95d13 in mainline for kernel/arch/arm32/src/fpu_context.c


Ignore:
Timestamp:
2013-03-12T21:07:15Z (11 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
606f6a1
Parents:
976c434 (diff), eceff5f (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 mainline changes.

File:
1 edited

Legend:

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

    r976c434 r2b95d13  
    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_ARC_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#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
    229161
    230162void fpu_init(void)
    231163{
     164        /* Check if we have access */
     165        if (!fpu_have_coprocessor_access())
     166                return;
     167
    232168        /* Clear all fpu flags */
    233169        fpexc_write(0);
     
    241177void fpu_setup(void)
    242178{
    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();
    248187        if (fpsid & FPSID_SW_ONLY_FLAG) {
    249188                printf("No FPU avaiable\n");
     
    265204        case FPU_VFPv3_NO_COMMON:
    266205        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();
    272207                /* See page B4-1637 */
    273208                if ((mvfr0 & 0xf) == 0x1) {
     
    288223bool handle_if_fpu_exception(void)
    289224{
     225        /* Check if we have access */
     226        if (!fpu_have_coprocessor_access())
     227                return false;
     228
    290229        const uint32_t fpexc = fpexc_read();
    291230        if (fpexc & FPEXC_ENABLED_FLAG) {
     
    305244void fpu_enable(void)
    306245{
     246        /* Check if we have access */
     247        if (!fpu_have_coprocessor_access())
     248                return;
    307249        /* Enable FPU instructions */
    308250        fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
     
    311253void fpu_disable(void)
    312254{
     255        /* Check if we have access */
     256        if (!fpu_have_coprocessor_access())
     257                return;
    313258        /* Disable FPU instructions */
    314259        fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
     
    317262void fpu_context_save(fpu_context_t *ctx)
    318263{
     264        /* This is only necessary if we enable fpu exceptions. */
     265#if 0
    319266        const uint32_t fpexc = fpexc_read();
    320267
     
    323270                //TODO implement common subarch context saving
    324271        }
     272#endif
    325273        if (save_context)
    326274                save_context(ctx);
Note: See TracChangeset for help on using the changeset viewer.