[xtensa-cvscommit] linux/arch/xtensa/mm init.c,1.3,1.4
Brought to you by:
zankel
|
From: <joe...@us...> - 2002-11-28 00:40:53
|
Update of /cvsroot/xtensa/linux/arch/xtensa/mm
In directory sc8-pr-cvs1:/tmp/cvs-serv11618/arch/xtensa/mm
Modified Files:
init.c
Log Message:
Add unaligned exception handling. None of this code is on by default, and we'll leave it off until we sync up with hardware that supports this exception. See the XTFIXME comment in the core.h files to enable this code.
Index: init.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/mm/init.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** init.c 22 Sep 2002 21:46:48 -0000 1.3
--- init.c 28 Nov 2002 00:40:49 -0000 1.4
***************
*** 492,495 ****
--- 492,528 ----
}
+
+ static void unaligned_test (void);
+
+ void debug_hooks (void)
+ {
+
+ #ifdef CONFIG_KGDB
+
+ /* We put the kgdb hook here, since we want it in
+ * arch-specific code, and after the console has been
+ * initialized. Doing this right after the IRQs are
+ * initialized would be ideal, but then the user wouldn't see
+ * the "Waiting for..." message on the console. */
+
+ extern int gdb_enter;
+ extern void breakpoint(void);
+ extern void set_debug_traps(void);
+ extern void rs_kgdb_hook(void);
+ if (gdb_enter) {
+ rs_kgdb_hook();
+ set_debug_traps();
+ printk("Waiting for connection from remote gdb... \n");
+ breakpoint();
+ }
+ #endif
+
+ #ifdef DEBUG_UNALIGNMENT_TEST
+ unaligned_test();
+ #endif
+
+ }
+
+
/* mem_init()
*
***************
*** 528,549 ****
initsize >> 10);
! /* We put the kgdb hook here, since we want it in arch-specific code, and after
! * the console has been initialized. Doing this right after the IRQs are
! * initialized would be ideal, but then the user wouldn't see the
! * "Waiting for..." message on the console. */
! #ifdef CONFIG_KGDB
! extern int gdb_enter;
! extern void breakpoint(void);
! extern void set_debug_traps(void);
! extern void rs_kgdb_hook(void);
! if (gdb_enter) {
! rs_kgdb_hook();
! set_debug_traps();
! printk("Waiting for connection from remote gdb... \n");
! breakpoint();
! }
! #endif
!
}
--- 561,569 ----
initsize >> 10);
! /* We put the debug hooks here, since we want it in
! * arch-specific code, and after the console has been
! * initialized. */
+ debug_hooks();
}
***************
*** 594,595 ****
--- 614,949 ----
return;
}
+
+
+
+ /***************************************************************************
+ * Debug code for unaligned-access exceptions
+ * ... from here on down
+ */
+
+ #ifdef DEBUG_UNALIGNMENT_TEST
+
+ static inline int get_byte (char *p)
+ {
+ int i;
+ asm volatile (" l8ui %0, %1, 0\n" : "=a" (i) : "a" (p));
+ return i;
+ }
+
+ static inline int get_hword (char *p)
+ {
+ int i;
+ asm volatile (" l16ui %0, %1, 0\n" : "=a" (i) : "a" (p));
+ return i;
+ }
+
+ static inline int get_shword (char *p)
+ {
+ int i;
+ asm volatile (" l16si %0, %1, 0\n" : "=a" (i) : "a" (p));
+ return i;
+ }
+
+ static inline int get_word (char *p)
+ {
+ int i;
+ asm volatile (" l32i %0, %1, 0\n" : "=a" (i) : "a" (p));
+ return i;
+ }
+
+ static inline int get_wordn (char *p)
+ {
+ int i;
+ asm volatile (" l32i.n %0, %1, 0\n" : "=a" (i) : "a" (p));
+ return i;
+ }
+
+ static inline int store_word (char *p, int val)
+ {
+ int i;
+ asm volatile (" s32i %0, %1, 0\n" : : "a" (val), "a" (p));
+ return i;
+ }
+
+ static inline int store_wordn (char *p, int val)
+ {
+ int i;
+ asm volatile (" s32i.n %0, %1, 0\n" : : "a" (val), "a" (p));
+ return i;
+ }
+
+ static inline int store_hword (char *p, int val)
+ {
+ int i;
+ asm volatile (" s16i %0, %1, 0\n" : : "a" (val), "a" (p));
+ return i;
+ }
+
+ static void test_l32i (char *p, int val)
+ {
+ int i = get_word(p);
+ printk ("loaded 0x%.8x, test %s\n", i, ((i == val) ? "passed" : "failed"));
+ }
+
+ static void test_l32in (char *p, int val)
+ {
+ int i = get_wordn(p);
+ printk ("loaded 0x%.8x, test %s\n", i, ((i == val) ? "passed" : "failed"));
+ }
+
+ static void test_l16ui (char *p, int val)
+ {
+ int i = get_hword(p);
+ printk ("loaded 0x%.8x, test %s\n", i, ((i == val) ? "passed" : "failed"));
+ }
+
+ static void test_l16si (char *p, int val)
+ {
+ int i = get_shword(p);
+ printk ("loaded 0x%.8x, test %s\n", i, ((i == val) ? "passed" : "failed"));
+ }
+
+ #define BYTE0(x) ((x)&0xff)
+ #define BYTE1(x) (((x)>>8)&0xff)
+ #define BYTE2(x) (((x)>>16)&0xff)
+ #define BYTE3(x) (((x)>>24)&0xff)
+
+ #define REVERSE(x) ( (BYTE0(x)<<24) | (BYTE1(x)<<16) | (BYTE2(x)<<8) | BYTE3(x) )
+ #define REVERSE16(x) ( ((BYTE0(x)<<8) | BYTE1(x)) & 0x0000ffff )
+
+ #ifdef __XTENSA_EB__
+ #define RESULT(x) (x)
+ #else
+ #define RESULT(x) REVERSE(x)
+ #endif
+
+ static void test_s16i (char *space, int offset, int val)
+ {
+ /* Byte ops are OK here. Calling this function on an IRAM is an error. */
+
+ int i;
+ char *s = "failed";
+ unsigned short *p = (unsigned short *)space;
+ for (i=0; i<8; i++)
+ space[i] = 0xcc;
+
+ store_hword(&space[offset], val);
+
+ switch (offset) {
+ case 0:
+ if ((p[0] == val) && (p[1] == 0xcccc))
+ s = "passed";
+ break;
+ case 1:
+ if ((space[0] == 0xcc) &&
+ #ifdef __XTENSA_EB__
+ (space[1] == (val>>8)) &&
+ (space[2] == (val & 0xff)) &&
+ #else
+ (space[1] == (val & 0xff)) &&
+ (space[2] == (val >> 8)) &&
+ #endif
+ (space[3] == 0xcc) )
+ s = "passed";
+ break;
+ default:
+ break;
+ }
+
+ printk ("stored val=0x%.4x to 0x%.8x, test %s\n", val, (int)(&space[offset]), s);
+ }
+
+ #ifdef __XTENSA_EB__
+ #define GET_WORD(x,arr,off) \
+ x = ((arr)[(off)] << 24) | ((arr)[(off)+1] << 16) | ((arr)[(off)+2] << 8) | (arr)[(off)+3]
+ #else
+ #define GET_WORD(x,arr,off) \
+ x = ((arr)[(off)+3] << 24) | ((arr)[(off)+2] << 16) | ((arr)[(off)+1] << 8) | (arr)[(off)]
+ #endif
+
+ static int extract_word (char *p, int off)
+ {
+ int *ip = (int *)p;
+ char temp[8];
+ int i;
+
+ /* p may address IRAM. Copy it to the stack, where we know we
+ * can do byte operations. */
+
+ int *it = (int *)temp;
+ it[0] = ip[0];
+ it[1] = ip[1];
+
+ GET_WORD(i,temp,off);
+ return i;
+ }
+
+ static void test_s32i (char *space, int offset, int val, int narrow)
+ {
+ int i, first, second;
+ char *s = "failed";
+ int *p = (int *)space;
+ p[0] = 0xcccccccc;
+ p[1] = 0xcccccccc;
+
+ if (narrow)
+ store_word(&space[offset], val);
+ else
+ store_wordn(&space[offset], val);
+
+ i = extract_word (space, offset);
+ first = p[0];
+ second = p[1];
+
+ switch (offset) {
+ case 0:
+ if ((first == val) && (second == 0xcccccccc))
+ s = "passed";
+ break;
+ case 1:
+ if ( (i == val) &&
+ ((first & RESULT(0xff000000)) == RESULT(0xcc000000)) &&
+ ((second & RESULT(0x00ffffff)) == RESULT(0x00cccccc)) )
+ s = "passed";
+ break;
+ case 2:
+ if ( (i == val) &&
+ ((first & RESULT(0xffff0000)) == RESULT(0xcccc0000)) &&
+ ((second & RESULT(0x0000ffff)) == RESULT(0x0000cccc)) )
+ s = "passed";
+ break;
+ case 3:
+ if ( (i == val) &&
+ ((first & RESULT(0xffffff00)) == RESULT(0xcccccc00)) &&
+ ((second & RESULT(0x000000ff)) == RESULT(0x000000cc)) )
+ s = "passed";
+ break;
+ default:
+ break;
+ }
+
+ printk ("stored val=0x%.8x to 0x%.8x, test %s\n", val, (int)(&space[offset]), s);
+ }
+
+ static char load_space[16];
+ static char store_space[16];
+
+ int unaexc_count;
+ static int iram_base;
+
+ static inline int result16s(int x)
+ {
+ #ifdef __XTENSA_EL__
+ x = REVERSE16(x);
+ #endif
+ if (x & 0x00008000)
+ x |= 0xffff0000;
+ return x;
+ }
+
+ static inline int result16u(int x)
+ {
+ #ifdef __XTENSA_EL__
+ x = REVERSE16(x);
+ #endif
+ return x & 0x0000ffff;
+ }
+
+ static void test_all_loads (char *p)
+ {
+ /* Init buffer, then test unaligned loads. We must use 32-bit
+ * stores because the pointer may address IRAM. We setup
+ * memory to look the same, byte by byte, independent of
+ * endianness. This approach simplifies prediction of the
+ * loaded value, at least for me. :) */
+
+ int *ip = (int *)p;
+ #ifdef __XTENSA_EB__
+ ip[0] = 0x01234567;
+ ip[1] = 0x4080aa22;
+ ip[2] = 0x897b3dbf;
+ ip[3] = 0x89abcdef;
+ #else
+ ip[0] = 0x67452301;
+ ip[1] = 0x22aa8040;
+ ip[2] = 0xbf3d7b89;
+ ip[3] = 0xefcdab89;
+ #endif
+
+ test_l32i (p, RESULT(0x01234567));
+ test_l32i (p+1, RESULT(0x23456740));
+ test_l32i (p+2, RESULT(0x45674080));
+ test_l32i (p+3, RESULT(0x674080aa));
+
+ test_l32in (p, RESULT(0x01234567));
+ test_l32in (p+1, RESULT(0x23456740));
+ test_l32in (p+2, RESULT(0x45674080));
+ test_l32in (p+3, RESULT(0x674080aa));
+
+ /* Insn that work on 16-bits are not allowed in IRAMs. */
+
+ if ( ! iram_base ) {
+ test_l16ui (p, result16u(0x0123));
+ test_l16ui (p+1, result16u(0x2345));
+ test_l16ui (p+4, result16u(0x4080));
+ test_l16ui (p+5, result16u(0x80aa));
+
+ test_l16si (p, result16s(0x0123));
+ test_l16si (p+1, result16s(0x2345));
+ test_l16si (p+4, result16s(0x4080));
+ test_l16si (p+5, result16s(0x80aa));
+ }
+ }
+
+ static void test_all_stores (char *p)
+ {
+ test_s32i (p, 0, 0x33557799, /* narrow = */ 0);
+ test_s32i (p, 1, 0x33557799, /* narrow = */ 0);
+ test_s32i (p, 2, 0x33557799, /* narrow = */ 0);
+ test_s32i (p, 3, 0x33557799, /* narrow = */ 0);
+
+ test_s32i (p, 0, 0x22446688, /* narrow = */ 1);
+ test_s32i (p, 1, 0x22446688, /* narrow = */ 1);
+ test_s32i (p, 2, 0x22446688, /* narrow = */ 1);
+ test_s32i (p, 3, 0x22446688, /* narrow = */ 1);
+
+ /* Insn that work on 16-bits are not allowed in IRAMs. */
+
+ if ( ! iram_base ) {
+ test_s16i (p, 0, 0xaadd);
+ test_s16i (p, 1, 0xaadd);
+ }
+ }
+
+ static void unaligned_test(void)
+ {
+ printk ("\nSTARTING UNALIGNMENT TEST, KERNEL ACCESSES\n\n");
+
+ printk ("** Testing load instructions with buffer 0x%.8x\n", (int)load_space);
+ if (((int)(load_space)) & 3)
+ printk ("WARNING: load_space array is not on a word boundary.\n");
+ test_all_loads (load_space);
+
+ printk ("** Testing store instructions with buffer 0x%.8x\n", (int)store_space);
+ if (((int)(store_space)) & 3)
+ printk ("WARNING: store_space array is not on a word boundary.\n");
+ test_all_stores (store_space);
+
+ #if XCHAL_NUM_INSTRAM
+ iram_base = (int) XCHAL_INSTRAM0_VADDR;
+ printk ("** Testing load instructions with IRAM buffer 0x%.8x\n", iram_base);
+ test_all_loads ((char *)iram_base);
+
+ printk ("** Testing store instructions with IRAM buffer 0x%.8x\n",
+ (int)XCHAL_INSTRAM0_VADDR);
+ test_all_stores ((char *)XCHAL_INSTRAM0_VADDR);
+ iram_base = 0; /* done testing IRAMs */
+ #endif
+
+ printk ("\n%d unaligned exceptions occured\n", unaexc_count);
+ printk ("\nEND UNALIGNMENT TEST\n\n");
+
+ panic ("Debugging halt request after unalignment test");
+ }
+
+ #endif /* DEBUG_UNALIGNMENT_TEST */
|