powerpc: Endian safe trampoline
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / powerpc / include / asm / ppc_asm.h
index 5995457..ce05bba 100644 (file)
@@ -180,9 +180,20 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 #define REST_32VRS_TRANSACT(n,b,base)  REST_16VRS_TRANSACT(n,b,base);  \
                                        REST_16VRS_TRANSACT(n+16,b,base)
 
+#ifdef __BIG_ENDIAN__
+#define STXVD2X_ROT(n,b,base)          STXVD2X(n,b,base)
+#define LXVD2X_ROT(n,b,base)           LXVD2X(n,b,base)
+#else
+#define STXVD2X_ROT(n,b,base)          XXSWAPD(n,n);           \
+                                       STXVD2X(n,b,base);      \
+                                       XXSWAPD(n,n)
+
+#define LXVD2X_ROT(n,b,base)           LXVD2X(n,b,base);       \
+                                       XXSWAPD(n,n)
+#endif
 
 #define SAVE_VSR_TRANSACT(n,b,base)    li b,THREAD_TRANSACT_VSR0+(16*(n)); \
-                                       STXVD2X(n,R##base,R##b)
+                                       STXVD2X_ROT(n,R##base,R##b)
 #define SAVE_2VSRS_TRANSACT(n,b,base)  SAVE_VSR_TRANSACT(n,b,base);    \
                                        SAVE_VSR_TRANSACT(n+1,b,base)
 #define SAVE_4VSRS_TRANSACT(n,b,base)  SAVE_2VSRS_TRANSACT(n,b,base);  \
@@ -195,7 +206,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
                                        SAVE_16VSRS_TRANSACT(n+16,b,base)
 
 #define REST_VSR_TRANSACT(n,b,base)    li b,THREAD_TRANSACT_VSR0+(16*(n)); \
-                                       LXVD2X(n,R##base,R##b)
+                                       LXVD2X_ROT(n,R##base,R##b)
 #define REST_2VSRS_TRANSACT(n,b,base)  REST_VSR_TRANSACT(n,b,base);    \
                                        REST_VSR_TRANSACT(n+1,b,base)
 #define REST_4VSRS_TRANSACT(n,b,base)  REST_2VSRS_TRANSACT(n,b,base);  \
@@ -208,13 +219,15 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
                                        REST_16VSRS_TRANSACT(n+16,b,base)
 
 /* Save the lower 32 VSRs in the thread VSR region */
-#define SAVE_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n));  STXVD2X(n,R##base,R##b)
+#define SAVE_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n)); \
+                               STXVD2X_ROT(n,R##base,R##b)
 #define SAVE_2VSRS(n,b,base)   SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base)
 #define SAVE_4VSRS(n,b,base)   SAVE_2VSRS(n,b,base); SAVE_2VSRS(n+2,b,base)
 #define SAVE_8VSRS(n,b,base)   SAVE_4VSRS(n,b,base); SAVE_4VSRS(n+4,b,base)
 #define SAVE_16VSRS(n,b,base)  SAVE_8VSRS(n,b,base); SAVE_8VSRS(n+8,b,base)
 #define SAVE_32VSRS(n,b,base)  SAVE_16VSRS(n,b,base); SAVE_16VSRS(n+16,b,base)
-#define REST_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n)); LXVD2X(n,R##base,R##b)
+#define REST_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n)); \
+                               LXVD2X_ROT(n,R##base,R##b)
 #define REST_2VSRS(n,b,base)   REST_VSR(n,b,base); REST_VSR(n+1,b,base)
 #define REST_4VSRS(n,b,base)   REST_2VSRS(n,b,base); REST_2VSRS(n+2,b,base)
 #define REST_8VSRS(n,b,base)   REST_4VSRS(n,b,base); REST_4VSRS(n+4,b,base)
@@ -832,6 +845,35 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,946)
 #define N_SLINE        68
 #define N_SO   100
 
-#endif /*  __ASSEMBLY__ */
+/*
+ * Create an endian fixup trampoline
+ *
+ * This starts with a "tdi 0,0,0x48" instruction which is
+ * essentially a "trap never", and thus akin to a nop.
+ *
+ * The opcode for this instruction read with the wrong endian
+ * however results in a b . + 8
+ *
+ * So essentially we use that trick to execute the following
+ * trampoline in "reverse endian" if we are running with the
+ * MSR_LE bit set the "wrong" way for whatever endianness the
+ * kernel is built for.
+ */
 
+#ifdef CONFIG_PPC_BOOK3E
+#define FIXUP_ENDIAN
+#else
+#define FIXUP_ENDIAN                                              \
+       tdi   0,0,0x48;   /* Reverse endian of b . + 8          */ \
+       b     $+36;       /* Skip trampoline if endian is good  */ \
+       .long 0x05009f42; /* bcl 20,31,$+4                      */ \
+       .long 0xa602487d; /* mflr r10                           */ \
+       .long 0x1c004a39; /* addi r10,r10,28                    */ \
+       .long 0xa600607d; /* mfmsr r11                          */ \
+       .long 0x01006b69; /* xori r11,r11,1                     */ \
+       .long 0xa6035a7d; /* mtsrr0 r10                         */ \
+       .long 0xa6037b7d; /* mtsrr1 r11                         */ \
+       .long 0x2400004c  /* rfid                               */
+#endif /* !CONFIG_PPC_BOOK3E */
+#endif /*  __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_PPC_ASM_H */