Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 660e8fa in mainline


Ignore:
Timestamp:
2013-01-18T20:49:35Z (9 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master
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.

Location:
kernel/arch/arm32
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/Makefile.inc

    rb5a3b50 r660e8fa  
    3535GCC_CFLAGS += -fno-omit-frame-pointer -mapcs-frame -march=$(subst _,-,$(PROCESSOR)) -mno-unaligned-access
    3636
     37ifeq ($(MACHINE),beagleboardxm)
     38GCC_CFLAGS += -mcpu=cortex-a8
     39endif
     40
    3741ifeq ($(CONFIG_FPU),y)
    3842# This is necessary to allow vmsr insn and fpexc manipulation
    3943# Use vfp32 to allow context save/restore of d16-d31 regs.
    40 GCC_CFLAGS += -mfloat-abi=hard -mfpu=vfp3
     44AFLAGS += -mfloat-abi=hard -mfpu=vfp3
    4145endif
    4246
     
    7074ifeq ($(CONFIG_FPU),y)
    7175        ARCH_SOURCES += arch/$(KARCH)/src/fpu_context.c
     76        ARCH_SOURCES += arch/$(KARCH)/src/fpu.s
    7277endif
    7378
  • kernel/arch/arm32/include/barrier.h

    rb5a3b50 r660e8fa  
    3939/*
    4040 * TODO: implement true ARM memory barriers for macros below.
     41 * ARMv6 introduced user access of the following commands:
     42 * • Prefetch flush
     43 * • Data synchronization barrier
     44 * • Data memory barrier
     45 * • Clean and prefetch range operations.
     46 * ARM Architecture Reference Manual version I ch. B.3.2.1 p. B3-4
    4147 */
    4248#define CS_ENTER_BARRIER()  asm volatile ("" ::: "memory")
    4349#define CS_LEAVE_BARRIER()  asm volatile ("" ::: "memory")
    4450
     51#if defined PROCESSOR_ARCH_armv7_a
     52/* ARMv7 uses instructions for memory barriers see ARM Architecture reference
     53 * manual for details:
     54 * DMB: ch. A8.8.43 page A8-376
     55 * DSB: ch. A8.8.44 page A8-378
     56 * See ch. A3.8.3 page A3-148 for details about memory barrier implementation
     57 * and functionality on armv7 architecture.
     58 */
     59#define memory_barrier()  asm volatile ("dmb" ::: "memory")
     60#define read_barrier()    asm volatile ("dsb" ::: "memory")
     61#define write_barrier()   asm volatile ("dsb st" ::: "memory")
     62#else
    4563#define memory_barrier()  asm volatile ("" ::: "memory")
    4664#define read_barrier()    asm volatile ("" ::: "memory")
    4765#define write_barrier()   asm volatile ("" ::: "memory")
    48 
     66#endif
    4967/*
    5068 * There are multiple ways ICache can be implemented on ARM machines. Namely
     
    6280 */
    6381
    64 /* Available on both all supported arms,
     82#ifdef PROCESSOR_ARCH_armv7_a
     83#define smc_coherence(a) asm volatile ( "isb" ::: "memory")
     84#define smc_coherence_block(a, l) smc_coherence(a)
     85#else
     86/* Available on all supported arms,
    6587 * invalidates entire ICache so the written value does not matter. */
     88//TODO might be PL1 only on armv5 -
    6689#define smc_coherence(a) asm volatile ( "mcr p15, 0, r0, c7, c5, 0")
    6790#define smc_coherence_block(a, l) smc_coherence(a)
     91#endif
    6892
    6993
  • kernel/arch/arm32/include/regutils.h

    rb5a3b50 r660e8fa  
    6666
    6767/* ARM Processor Operation Modes */
    68 #define USER_MODE        0x10
    69 #define FIQ_MODE         0x11
    70 #define IRQ_MODE         0x12
    71 #define SUPERVISOR_MODE  0x13
    72 #define ABORT_MODE       0x17
    73 #define UNDEFINED_MODE   0x1b
    74 #define SYSTEM_MODE      0x1f
    75 
     68enum {
     69        USER_MODE = 0x10,
     70        FIQ_MODE = 0x11,
     71        IRQ_MODE = 0x12,
     72        SUPERVISOR_MODE = 0x13,
     73        MONITOR_MODE = 0x16,
     74        ABORT_MODE = 0x17,
     75        HYPERVISOR_MODE = 0x1a,
     76        UNDEFINED_MODE = 0x1b,
     77        SYSTEM_MODE = 0x1f,
     78        MODE_MASK = 0x1f,
     79};
    7680/* [CS]PRS manipulation macros */
    7781#define GEN_STATUS_READ(nm, reg) \
  • 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.