1 | /* |
---|
2 | * Test low-level exception handling code: |
---|
3 | * |
---|
4 | * - hook an exception handler |
---|
5 | * - clobber (almost) all registers with a known value |
---|
6 | * - raise exception |
---|
7 | * - from exception handler, increment all saved register |
---|
8 | * contents by one (to ensure registers are not only |
---|
9 | * saved properly but also restored properly). |
---|
10 | * - resume execution |
---|
11 | * - verify registers are now 'clobber_value + 1' |
---|
12 | * |
---|
13 | * NOTE: cannot be used on PSIM because SYS exception is used |
---|
14 | * internally by simulator (but we could use a trap or |
---|
15 | * something else). |
---|
16 | * |
---|
17 | * Author: Till Straumann <strauman@slac.stanford.edu>, 2007 |
---|
18 | * |
---|
19 | * The license and distribution terms for this file may be |
---|
20 | * found in the file LICENSE in this distribution or at |
---|
21 | * http://www.rtems.com/license/LICENSE. |
---|
22 | * |
---|
23 | * $Id$ |
---|
24 | */ |
---|
25 | |
---|
26 | |
---|
27 | #include <inttypes.h> |
---|
28 | #include <stdio.h> |
---|
29 | #include <stdlib.h> |
---|
30 | #include <string.h> |
---|
31 | #include "vectors.h" |
---|
32 | |
---|
33 | |
---|
34 | typedef struct regs_ { |
---|
35 | uint32_t cr, xer, lr, ctr; |
---|
36 | uint32_t gpr0; |
---|
37 | uint32_t gpr1; |
---|
38 | uint32_t gpr2; |
---|
39 | uint32_t gpr3; |
---|
40 | uint32_t gpr4; |
---|
41 | uint32_t gpr5; |
---|
42 | uint32_t gpr6; |
---|
43 | uint32_t gpr7; |
---|
44 | uint32_t gpr8; |
---|
45 | uint32_t gpr9; |
---|
46 | uint32_t gpr10; |
---|
47 | uint32_t gpr11; |
---|
48 | uint32_t gpr12; |
---|
49 | uint32_t gpr13; |
---|
50 | uint32_t gpr14; |
---|
51 | uint32_t gpr15; |
---|
52 | uint32_t gpr16; |
---|
53 | uint32_t gpr17; |
---|
54 | uint32_t gpr18; |
---|
55 | uint32_t gpr19; |
---|
56 | uint32_t gpr20; |
---|
57 | uint32_t gpr21; |
---|
58 | uint32_t gpr22; |
---|
59 | uint32_t gpr23; |
---|
60 | uint32_t gpr24; |
---|
61 | uint32_t gpr25; |
---|
62 | uint32_t gpr26; |
---|
63 | uint32_t gpr27; |
---|
64 | uint32_t gpr28; |
---|
65 | uint32_t gpr29; |
---|
66 | uint32_t gpr30; |
---|
67 | uint32_t gpr31; |
---|
68 | } ppc_exc_int_regs; |
---|
69 | |
---|
70 | #define OFF(x) (uintptr_t)(&((ppc_exc_int_regs*)0)->x) |
---|
71 | |
---|
72 | void |
---|
73 | storegs(ppc_exc_int_regs *p0, ppc_exc_int_regs *p1) |
---|
74 | { |
---|
75 | asm volatile( |
---|
76 | " stmw 0, %6(%0) ;" |
---|
77 | " mfcr 0 ;" |
---|
78 | " stw 0, %2(%0) ;" |
---|
79 | " mflr 0 ;" |
---|
80 | " stw 0, %3(%0) ;" |
---|
81 | " mfxer 0 ;" |
---|
82 | " stw 0, %4(%0) ;" |
---|
83 | " mfctr 0 ;" |
---|
84 | " stw 0, %5(%0) ;" |
---|
85 | " lwz 0, %6(%0) ;" |
---|
86 | " trap ;" |
---|
87 | " stmw 0, %6(%1) ;" |
---|
88 | " mfcr 0 ;" |
---|
89 | " stw 0, %2(%1) ;" |
---|
90 | " mflr 0 ;" |
---|
91 | " stw 0, %3(%1) ;" |
---|
92 | " mfxer 0 ;" |
---|
93 | " stw 0, %4(%1) ;" |
---|
94 | " mfctr 0 ;" |
---|
95 | " stw 0, %5(%1) ;" |
---|
96 | : |
---|
97 | :"b"(p0),"b"(p1), |
---|
98 | "i"(OFF(cr)), "i"(OFF(lr)), "i"(OFF(xer)), "i"(OFF(ctr)), |
---|
99 | "i"(OFF(gpr0)) |
---|
100 | :"r0"); |
---|
101 | } |
---|
102 | |
---|
103 | /* Load up all registers from 'pre' issue system call and store |
---|
104 | * registers in 'post' |
---|
105 | */ |
---|
106 | |
---|
107 | ppc_exc_int_regs pre; |
---|
108 | ppc_exc_int_regs pst; |
---|
109 | |
---|
110 | void |
---|
111 | clobber() |
---|
112 | { |
---|
113 | asm volatile( |
---|
114 | " lis 2, pre@h ;" |
---|
115 | " ori 2, 2, pre@l ;" |
---|
116 | " lwz 3, %0(2) ;" |
---|
117 | " mtcr 3 ;" |
---|
118 | " lwz 3, %1(2) ;" |
---|
119 | " mtlr 3 ;" |
---|
120 | " lwz 3, %2(2) ;" |
---|
121 | " mtxer 3 ;" |
---|
122 | /* don't know which ones stick */ |
---|
123 | " mfxer 3 ;" |
---|
124 | " stw 3, %2(2) ;" |
---|
125 | " lwz 3, %3(2) ;" |
---|
126 | " mtctr 3 ;" |
---|
127 | " lwz 0, %4(2) ;" |
---|
128 | /* must not clobber R13, R1, R2 */ |
---|
129 | " stw 13, %6(2) ;" |
---|
130 | " lmw 3, %5(2) ;" |
---|
131 | " trap ;" |
---|
132 | " stmw 0, %4(2) ;" |
---|
133 | " mfcr 0 ;" |
---|
134 | " stw 0, %0(2) ;" |
---|
135 | " mflr 0 ;" |
---|
136 | " stw 0, %1(2) ;" |
---|
137 | " mfxer 0 ;" |
---|
138 | " stw 0, %2(2) ;" |
---|
139 | " mfctr 0 ;" |
---|
140 | " stw 0, %3(2) ;" |
---|
141 | : |
---|
142 | :"i"(OFF(cr)), "i"(OFF(lr)), "i"(OFF(xer)), "i"(OFF(ctr)), |
---|
143 | "i"(OFF(gpr0)), "i"(OFF(gpr3)), "i"(OFF(gpr13)) |
---|
144 | :"r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", |
---|
145 | "r10", "r11", "r12", "r14", "r15", "r16", |
---|
146 | "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
---|
147 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
---|
148 | "xer","lr","ctr", |
---|
149 | "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7", |
---|
150 | "memory"); |
---|
151 | } |
---|
152 | |
---|
153 | typedef union { uint32_t u; uint8_t c[4]; } u32_a_t; |
---|
154 | |
---|
155 | /* exception handler; adds 1 to all register contents (except r1,r2,r13) */ |
---|
156 | int |
---|
157 | handle_clobber_exc(BSP_Exception_frame *f, unsigned vector) |
---|
158 | { |
---|
159 | int i; |
---|
160 | u32_a_t *p = (u32_a_t*)&f->GPR0; |
---|
161 | for ( i=0; i<32; i++ ) { |
---|
162 | switch (i) { |
---|
163 | case 1: case 2: case 13: break; |
---|
164 | default: |
---|
165 | p[i].u++; |
---|
166 | break; |
---|
167 | } |
---|
168 | } |
---|
169 | f->GPR2 = (uint32_t)&pst; |
---|
170 | f->EXC_CR++; |
---|
171 | f->EXC_CTR++; |
---|
172 | f->EXC_XER++; |
---|
173 | f->EXC_LR++; |
---|
174 | f->EXC_SRR0 += 4; |
---|
175 | return 0; |
---|
176 | } |
---|
177 | |
---|
178 | |
---|
179 | /* This routine tests the raw exception code; |
---|
180 | * - hook 'handle_clobber_exc' to SYS exception handler |
---|
181 | * - clobber all registers with 0xaffe0000 + <index> |
---|
182 | * (except: r1, r2, r13, non-sticky bits in xer) |
---|
183 | * R2 is clobbered with the address of the pre area. |
---|
184 | * - issue 'trap' -> PROG exception |
---|
185 | * - exception handler increments all reg. contents by 1, |
---|
186 | * stores address of 'pst' area in R2 and returns control |
---|
187 | * to ppc_exc_clobber(). |
---|
188 | * - save all register contents to *R2 (should be &pst). |
---|
189 | * - test for mismatches (except R1, R2, R13 and parts of xer) |
---|
190 | */ |
---|
191 | void |
---|
192 | ppc_exc_clobber() |
---|
193 | { |
---|
194 | u32_a_t *a, *b; |
---|
195 | int i; |
---|
196 | a = (u32_a_t*)⪯ |
---|
197 | b = (u32_a_t*)&pst; |
---|
198 | for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { |
---|
199 | a[i].u = 0xaffe0000 + i; |
---|
200 | } |
---|
201 | ppc_exc_set_handler(ASM_PROG_VECTOR, handle_clobber_exc); |
---|
202 | clobber(); |
---|
203 | ppc_exc_set_handler(ASM_PROG_VECTOR, 0); |
---|
204 | for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { |
---|
205 | switch (i) { |
---|
206 | case OFF(gpr1)/sizeof(uint32_t): |
---|
207 | case OFF(gpr2)/sizeof(uint32_t): |
---|
208 | case OFF(gpr13)/sizeof(uint32_t): |
---|
209 | break; |
---|
210 | |
---|
211 | default: |
---|
212 | if ( a[i].u != b[i].u - 1 ) { |
---|
213 | printf("MISMATCH at %i: 0x%08"PRIx32" -- 0x%08"PRIx32"\n", |
---|
214 | i, a[i].u, b[i].u); |
---|
215 | } |
---|
216 | } |
---|
217 | } |
---|
218 | } |
---|
219 | |
---|
220 | #if 0 |
---|
221 | void |
---|
222 | ppc_exc_test() |
---|
223 | { |
---|
224 | ppc_exc_int_regs a, b; |
---|
225 | int i; |
---|
226 | memset(&a, 0xaa, sizeof(a)); |
---|
227 | memset(&b, 0x55, sizeof(b)); |
---|
228 | storegs(&a, &b); |
---|
229 | if ( memcmp(&a, &b, sizeof(a)) ) { |
---|
230 | printf("FAILURE: context prior and after exception don't match!\n"); |
---|
231 | } |
---|
232 | for ( i=0; i< sizeof(a)/sizeof(uint32_t); i++ ) { |
---|
233 | printf("0x%08"PRIx32" -- 0x%08"PRIx32"\n", |
---|
234 | ((uint32_t __attribute__((may_alias)) *)&a)[i], |
---|
235 | ((uint32_t __attribute__((may_alias)) *)&b)[i]); |
---|
236 | } |
---|
237 | } |
---|
238 | #endif |
---|