Ignore:
File:
1 edited

Legend:

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

    r5c4356b rce60be1  
    3737#include <arch.h>
    3838#include <arch/types.h>
    39 #include <arch/security_ext.h>
    40 #include <arch/cp15.h>
    4139#include <cpu.h>
    4240
     
    5755};
    5856
    59 extern uint32_t fpsid_read(void);
    60 extern uint32_t mvfr0_read(void);
    61 
    6257enum {
    6358        FPEXC_EX_FLAG = (1 << 31),
    6459        FPEXC_ENABLED_FLAG = (1 << 30),
    6560};
    66 extern uint32_t fpexc_read(void);
    67 extern void fpexc_write(uint32_t);
    6861
    6962/** ARM Architecture Reference Manual ch. B4.1.58, p. B$-1551 */
     
    10194        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,
    10295};
    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 *);
     96
     97static 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
     107static inline void fpscr_write(uint32_t val)
     108{
     109        asm volatile (
     110                "vmsr fpscr, %0\n"
     111                ::"r" (val):
     112        );
     113}
     114
     115static 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
     125static inline void fpexc_write(uint32_t val)
     126{
     127        asm volatile (
     128                "vmsr fpexc, %0\n"
     129                ::"r" (val):
     130        );
     131}
    112132
    113133static void (*save_context)(fpu_context_t *ctx);
    114134static void (*restore_context)(fpu_context_t *ctx);
    115135
    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 
     136/** Saves 32 single precision fpu registers.
     137 * @param ctx FPU context area.
     138 * Used by VFPv1
     139 */
     140static 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 */
     155static 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 */
     170static 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 */
     185static 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 */
     200static 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 */
     217static 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}
    161229
    162230void fpu_init(void)
    163231{
    164         /* Check if we have access */
    165         if (!fpu_have_coprocessor_access())
    166                 return;
    167 
    168232        /* Clear all fpu flags */
    169233        fpexc_write(0);
     
    177241void fpu_setup(void)
    178242{
    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();
     243        uint32_t fpsid = 0;
     244        asm volatile (
     245                "vmrs %0, fpsid\n"
     246                :"=r"(fpsid)::
     247        );
    187248        if (fpsid & FPSID_SW_ONLY_FLAG) {
    188249                printf("No FPU avaiable\n");
     
    204265        case FPU_VFPv3_NO_COMMON:
    205266        case FPU_VFPv3_COMMONv3: {
    206                 const uint32_t mvfr0 = mvfr0_read();
     267                uint32_t mvfr0 = 0;
     268                asm volatile (
     269                        "vmrs %0,mvfr0\n"
     270                        :"=r"(mvfr0)::
     271                );
    207272                /* See page B4-1637 */
    208273                if ((mvfr0 & 0xf) == 0x1) {
     
    223288bool handle_if_fpu_exception(void)
    224289{
    225         /* Check if we have access */
    226         if (!fpu_have_coprocessor_access())
    227                 return false;
    228 
    229290        const uint32_t fpexc = fpexc_read();
    230291        if (fpexc & FPEXC_ENABLED_FLAG) {
     
    244305void fpu_enable(void)
    245306{
    246         /* Check if we have access */
    247         if (!fpu_have_coprocessor_access())
    248                 return;
    249307        /* Enable FPU instructions */
    250308        fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
     
    253311void fpu_disable(void)
    254312{
    255         /* Check if we have access */
    256         if (!fpu_have_coprocessor_access())
    257                 return;
    258313        /* Disable FPU instructions */
    259314        fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
     
    262317void fpu_context_save(fpu_context_t *ctx)
    263318{
    264         /* This is only necessary if we enable fpu exceptions. */
    265 #if 0
    266319        const uint32_t fpexc = fpexc_read();
    267320
     
    270323                //TODO implement common subarch context saving
    271324        }
    272 #endif
    273325        if (save_context)
    274326                save_context(ctx);
Note: See TracChangeset for help on using the changeset viewer.