Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /* Altivec support for RTEMS; vector register context management.  */
0002 
0003 /*
0004  * Authorship
0005  * ----------
0006  * This software was created by
0007  *     Till Straumann <strauman@slac.stanford.edu>, 2009,
0008  *     Stanford Linear Accelerator Center, Stanford University.
0009  *
0010  * Acknowledgement of sponsorship
0011  * ------------------------------
0012  * This software was produced by
0013  *     the Stanford Linear Accelerator Center, Stanford University,
0014  *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
0015  *
0016  * Government disclaimer of liability
0017  * ----------------------------------
0018  * Neither the United States nor the United States Department of Energy,
0019  * nor any of their employees, makes any warranty, express or implied, or
0020  * assumes any legal liability or responsibility for the accuracy,
0021  * completeness, or usefulness of any data, apparatus, product, or process
0022  * disclosed, or represents that its use would not infringe privately owned
0023  * rights.
0024  *
0025  * Stanford disclaimer of liability
0026  * --------------------------------
0027  * Stanford University makes no representations or warranties, express or
0028  * implied, nor assumes any liability for the use of this software.
0029  *
0030  * Stanford disclaimer of copyright
0031  * --------------------------------
0032  * Stanford University, owner of the copyright, hereby disclaims its
0033  * copyright and all other rights in this software.  Hence, anyone may
0034  * freely use it for any purpose without restriction.
0035  *
0036  * Maintenance of notices
0037  * ----------------------
0038  * In the interest of clarity regarding the origin and status of this
0039  * SLAC software, this and all the preceding Stanford University notices
0040  * are to remain affixed to any copy or derivative of this software made
0041  * or distributed by the recipient and are to be affixed to any copy of
0042  * software made or distributed by the recipient that contains a copy or
0043  * derivative of this software.
0044  *
0045  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0046  */
0047 
0048 #ifdef __ALTIVEC__
0049 
0050 #include <rtems.h>
0051 #include <libcpu/cpuIdent.h>
0052 #include <rtems/bspIo.h>
0053 #include <rtems/error.h>
0054 #include <rtems/score/cpu.h>
0055 #include <rtems/powerpc/powerpc.h>
0056 
0057 #define STATIC static
0058 
0059 #define VEC_ALIGNMENT   16
0060 
0061 #define NAM             "AltiVec Support"
0062 #define ERRID(a,b,c,d)  (((a)<<24) | ((b)<<16) | ((c)<<8) | (d))
0063 
0064 typedef uint32_t _vu32 __attribute__((vector_size(VEC_ALIGNMENT)));
0065 
0066 #ifndef MSR_VE
0067 #define MSR_VE  (1<<(31-6))
0068 #endif
0069 
0070 /* NOTE: These two variables are accessed by assembly code
0071  *       which assumes 32-bit data!
0072  */
0073 uint32_t _CPU_altivec_ctxt_off = 0;
0074 uint32_t _CPU_altivec_psim_cpu = 0;
0075 
0076 static inline uint32_t
0077 mfmsr(void)
0078 {
0079 uint32_t v; 
0080     _CPU_MSR_GET(v);
0081     return v;
0082 }
0083 
0084 static inline void
0085 mtmsr(uint32_t v)
0086 {
0087     _CPU_MSR_SET(v);
0088 }
0089 
0090 static inline void
0091 isync(void)
0092 {
0093     asm volatile("isync");
0094 }
0095 
0096 static inline void
0097 dssall(void)
0098 {
0099     if ( !_CPU_altivec_psim_cpu)
0100         asm volatile("dssall");
0101 }
0102 
0103 static inline uint32_t
0104 set_MSR_VE(void)
0105 {
0106 uint32_t rval;
0107     rval=mfmsr();
0108     if ( ! (MSR_VE & rval ) ) {
0109         mtmsr(rval | MSR_VE);
0110         isync();
0111     }
0112     return rval;
0113 }
0114 
0115 static inline void
0116 clr_MSR_VE(void)
0117 {
0118     dssall();
0119     mtmsr(mfmsr() & ~MSR_VE);
0120     isync();
0121 }
0122 
0123 static inline void
0124 rst_MSR_VE(uint32_t old)
0125 {
0126     if ( ! ( MSR_VE & old ) ) {
0127         dssall();
0128         mtmsr(old);
0129         isync();
0130     }
0131 }
0132 
0133 
0134 /* Code to probe the compiler's stack alignment (PowerPC);
0135  * The routine determines at run-time if the compiler generated
0136  * 8 or 16-byte aligned code.
0137  *
0138  * Till Straumann <strauman@slac.stanford.edu>, 2005
0139  */
0140 
0141 static void dummy(void) __attribute__((noinline));
0142 /* add (empty) asm-statement to make sure this isn't optimized away */
0143 static void dummy(void) { __asm__ volatile(""); }
0144 
0145 static unsigned probe_r1(void) __attribute__((noinline));
0146 static unsigned probe_r1(void)
0147 {
0148 unsigned r1;
0149     /* call something to enforce creation of a minimal stack frame;
0150      * (8 bytes: r1 and lr space for 'dummy' callee). If compiled
0151      * with -meabi -mno-altivec gcc allocates 8 bytes, if -mno-eabi
0152      * or -maltivec / -mabi=altivec then gcc allocates 16 bytes
0153      * according to the sysv / altivec ABI specs.
0154      */
0155     dummy();
0156     /* return stack pointer */
0157     asm volatile("mr %0,1":"=r"(r1));
0158     return r1;
0159 }
0160 
0161 static unsigned
0162 probe_ppc_stack_alignment(void)
0163 {
0164 unsigned r1;
0165     asm volatile("mr %0,1":"=r"(r1));
0166     return (r1 - probe_r1()) & ~ 0xf;
0167 }
0168 
0169 STATIC int check_stack_alignment(void)
0170 {
0171 int rval = 0;
0172     if ( VEC_ALIGNMENT > PPC_STACK_ALIGNMENT ) {
0173         printk(NAM": CPU support has unsufficient stack alignment;\n");
0174         printk("modify 'cpukit/score/cpu/powerpc/rtems/score/powerpc.h'\n");
0175         printk("and choose PPC_ABI_SVR4. I'll enable a workaround for now.\n");
0176         rval |= 1;
0177     }
0178     /* Run-time check; should compile with -mabi=altivec */
0179     if ( probe_ppc_stack_alignment() < VEC_ALIGNMENT ) {
0180         printk(NAM": run-time stack alignment unsufficient; make sure you compile with -mabi=altivec\n");
0181         rval |= 2;
0182     }
0183     return rval;
0184 }
0185 
0186 
0187 static uint32_t probe_vrsave(_vu32 *p_v) __attribute__((noinline));
0188 
0189 /* Check if this code was compiled with -mvrsave=yes or no 
0190  * so that we can set the default/init value accordingly.
0191  */
0192 static uint32_t probe_vrsave(_vu32 *p_v)
0193 {
0194 _vu32     x;
0195 uint32_t vrsave;
0196     /* Explicitly clobber a volatile vector reg (0) that is
0197      * not used to pass return values.
0198      * If -mvrsave=yes was used this should cause gcc to
0199      * set bit 0 in vrsave. OTOH this bit cannot be set
0200      * because v0 is volatile and not used to pass a value
0201      * to the caller...
0202      */
0203     asm volatile("vxor %0, 0, 0; mfvrsave %1":"=v"(x),"=r"(vrsave)::"v0");
0204     if ( p_v ) {
0205         *p_v = x;
0206     }
0207     return vrsave;
0208 }
0209 
0210 static int vrsave_yes(void) __attribute__((noinline));
0211 
0212 static int vrsave_yes(void)
0213 {
0214 uint32_t vrsave_pre;
0215     asm volatile("mfvrsave %0":"=r"(vrsave_pre));
0216     if ( (vrsave_pre & 0x80000000) ) {
0217         printk(NAM": WARNING - unable to determine whether -mvrsave was used; assuming NO\n");
0218         return 0;
0219     }
0220     return probe_vrsave(0) != vrsave_pre;
0221 }
0222 
0223 extern void
0224 _CPU_altivec_set_vrsave_initval(uint32_t);
0225 
0226 
0227 void
0228 _CPU_Initialize_altivec(void)
0229 {
0230 unsigned          pvr;
0231 
0232     /* I don't like to have to #define the offset of the altivec area
0233      * for use by assembly code.
0234      * Therefore, we compute it here and store it in memory...
0235      */
0236     _CPU_altivec_ctxt_off  = offsetof(ppc_context, altivec);
0237 
0238     /*
0239      * See ppc_get_context() and PPC_CONTEXT_OFFSET_GPR1
0240      */
0241     _CPU_altivec_ctxt_off += PPC_DEFAULT_CACHE_LINE_SIZE;
0242 
0243     /* 
0244      * Add space possibly needed for alignment
0245      */
0246     _CPU_altivec_ctxt_off += PPC_CACHE_ALIGNMENT - 1;
0247 
0248     if ( ! vrsave_yes() ) {
0249         /* They seemed to compile with -mvrsave=no. Hence we
0250          * must set VRSAVE so that all registers are saved/restored
0251          * in case this support was not built with IGNORE_VRSAVE.
0252          */
0253         _CPU_altivec_set_vrsave_initval( -1 );
0254     }
0255 
0256     if ( check_stack_alignment() & 2 )
0257         rtems_fatal_error_occurred(ERRID('V','E','C','1'));
0258 
0259     pvr                   = get_ppc_cpu_type();
0260     /* psim has altivec but lacks the streaming instructions :-( */
0261     _CPU_altivec_psim_cpu = (PPC_PSIM == pvr);
0262 
0263     if ( ! ppc_cpu_has_altivec() ) {
0264         printk(NAM": This CPU seems not to have AltiVec\n");
0265         rtems_panic("Unable to initialize AltiVec Support\n");
0266     }
0267 
0268     if ( ! (mfmsr() & MSR_VE) ) {
0269         printk(NAM": Warning: BSP should set MSR_VE early; doing it now...\n");
0270         set_MSR_VE();   
0271     }
0272 }
0273 #endif