]>
Commit | Line | Data |
---|---|---|
1dda0b1f WD |
1 | /* |
2 | * Bedbug Functions specific to the MPC860 chip | |
3 | */ | |
4 | ||
5 | #include <common.h> | |
6 | #include <command.h> | |
7 | #include <linux/ctype.h> | |
1dda0b1f WD |
8 | #include <bedbug/bedbug.h> |
9 | #include <bedbug/regs.h> | |
10 | #include <bedbug/ppc.h> | |
8bde7f77 | 11 | #include <bedbug/type.h> |
1dda0b1f | 12 | |
d126bfbd | 13 | #if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && defined(CONFIG_8xx) |
1dda0b1f WD |
14 | |
15 | #define MAX_BREAK_POINTS 2 | |
16 | ||
17 | extern CPU_DEBUG_CTX bug_ctx; | |
18 | ||
19 | void bedbug860_init __P((void)); | |
20 | void bedbug860_do_break __P((cmd_tbl_t*,int,int,char*[])); | |
21 | void bedbug860_break_isr __P((struct pt_regs*)); | |
22 | int bedbug860_find_empty __P((void)); | |
23 | int bedbug860_set __P((int,unsigned long)); | |
24 | int bedbug860_clear __P((int)); | |
25 | ||
26 | \f | |
27 | /* ====================================================================== | |
28 | * Initialize the global bug_ctx structure for the MPC860. Clear all | |
29 | * of the breakpoints. | |
30 | * ====================================================================== */ | |
31 | ||
32 | void bedbug860_init( void ) | |
33 | { | |
34 | int i; | |
35 | /* -------------------------------------------------- */ | |
36 | ||
37 | bug_ctx.hw_debug_enabled = 0; | |
38 | bug_ctx.stopped = 0; | |
39 | bug_ctx.current_bp = 0; | |
40 | bug_ctx.regs = NULL; | |
41 | ||
42 | bug_ctx.do_break = bedbug860_do_break; | |
43 | bug_ctx.break_isr = bedbug860_break_isr; | |
44 | bug_ctx.find_empty = bedbug860_find_empty; | |
45 | bug_ctx.set = bedbug860_set; | |
46 | bug_ctx.clear = bedbug860_clear; | |
47 | ||
48 | for( i = 1; i <= MAX_BREAK_POINTS; ++i ) | |
49 | (*bug_ctx.clear)( i ); | |
50 | ||
51 | puts ("BEDBUG:ready\n"); | |
52 | return; | |
53 | } /* bedbug_init_breakpoints */ | |
54 | ||
55 | ||
56 | \f | |
57 | /* ====================================================================== | |
58 | * Set/clear/show one of the hardware breakpoints for the 860. The "off" | |
59 | * string will disable a specific breakpoint. The "show" string will | |
60 | * display the current breakpoints. Otherwise an address will set a | |
61 | * breakpoint at that address. Setting a breakpoint uses the CPU-specific | |
62 | * set routine which will assign a breakpoint number. | |
63 | * ====================================================================== */ | |
64 | ||
65 | void bedbug860_do_break (cmd_tbl_t *cmdtp, int flag, int argc, | |
8bde7f77 | 66 | char *argv[]) |
1dda0b1f WD |
67 | { |
68 | long addr = 0; /* Address to break at */ | |
69 | int which_bp; /* Breakpoint number */ | |
70 | /* -------------------------------------------------- */ | |
71 | ||
72 | if (argc < 2) | |
73 | { | |
74 | printf ("Usage:\n%s\n", cmdtp->usage); | |
75 | return; | |
76 | } | |
77 | ||
78 | /* Turn off a breakpoint */ | |
79 | ||
80 | if( strcmp( argv[ 1 ], "off" ) == 0 ) | |
81 | { | |
82 | if( bug_ctx.hw_debug_enabled == 0 ) | |
83 | { | |
84 | printf( "No breakpoints enabled\n" ); | |
85 | return; | |
86 | } | |
87 | ||
88 | which_bp = simple_strtoul( argv[ 2 ], NULL, 10 ); | |
89 | ||
90 | if( bug_ctx.clear ) | |
91 | (*bug_ctx.clear)( which_bp ); | |
92 | ||
93 | printf( "Breakpoint %d removed\n", which_bp ); | |
94 | return; | |
95 | } | |
96 | ||
97 | /* Show a list of breakpoints */ | |
98 | ||
99 | if( strcmp( argv[ 1 ], "show" ) == 0 ) | |
100 | { | |
101 | for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp ) | |
102 | { | |
103 | ||
104 | switch( which_bp ) | |
105 | { | |
106 | case 1: addr = GET_CMPA(); break; | |
107 | case 2: addr = GET_CMPB(); break; | |
108 | case 3: addr = GET_CMPC(); break; | |
109 | case 4: addr = GET_CMPD(); break; | |
110 | } | |
111 | ||
112 | printf( "Breakpoint [%d]: ", which_bp ); | |
113 | if( addr == 0 ) | |
114 | printf( "NOT SET\n" ); | |
115 | else | |
116 | disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX ); | |
117 | } | |
118 | return; | |
119 | } | |
120 | ||
121 | /* Set a breakpoint at the address */ | |
122 | ||
123 | if( !isdigit( argv[ 1 ][ 0 ])) | |
124 | { | |
125 | printf ("Usage:\n%s\n", cmdtp->usage); | |
126 | return; | |
127 | } | |
128 | ||
129 | addr = simple_strtoul( argv[ 1 ], NULL, 16 ) & 0xfffffffc; | |
130 | ||
131 | if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 ) | |
132 | { | |
133 | printf( "Breakpoint [%d]: ", which_bp ); | |
134 | disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX ); | |
135 | } | |
136 | ||
137 | return; | |
138 | } /* bedbug860_do_break */ | |
139 | ||
140 | ||
141 | \f | |
142 | /* ====================================================================== | |
143 | * Handle a breakpoint. First determine which breakpoint was hit by | |
144 | * looking at the DeBug Status Register (DBSR), clear the breakpoint | |
145 | * and enter a mini main loop. Stay in the loop until the stopped flag | |
146 | * in the debug context is cleared. | |
147 | * ====================================================================== */ | |
148 | ||
149 | void bedbug860_break_isr( struct pt_regs *regs ) | |
150 | { | |
151 | unsigned long addr; /* Address stopped at */ | |
152 | unsigned long cause; /* Address stopped at */ | |
153 | /* -------------------------------------------------- */ | |
154 | ||
155 | cause = GET_ICR(); | |
156 | ||
157 | if( !(cause & 0x00000004)) { | |
158 | printf( "Not an instruction breakpoint (ICR 0x%08lx)\n", cause ); | |
159 | return; | |
160 | } | |
161 | ||
162 | addr = regs->nip; | |
163 | ||
164 | if( addr == GET_CMPA() ) | |
165 | { | |
166 | bug_ctx.current_bp = 1; | |
167 | } | |
168 | else if( addr == GET_CMPB() ) | |
169 | { | |
170 | bug_ctx.current_bp = 2; | |
171 | } | |
172 | else if( addr == GET_CMPC() ) | |
173 | { | |
174 | bug_ctx.current_bp = 3; | |
175 | } | |
176 | else if( addr == GET_CMPD() ) | |
177 | { | |
178 | bug_ctx.current_bp = 4; | |
179 | } | |
180 | ||
181 | bedbug_main_loop( addr, regs ); | |
182 | return; | |
183 | } /* bedbug860_break_isr */ | |
184 | ||
185 | ||
186 | \f | |
187 | /* ====================================================================== | |
188 | * Look through all of the hardware breakpoints available to see if one | |
189 | * is unused. | |
190 | * ====================================================================== */ | |
191 | ||
192 | int bedbug860_find_empty( void ) | |
193 | { | |
194 | /* -------------------------------------------------- */ | |
195 | ||
196 | if( GET_CMPA() == 0 ) | |
197 | return 1; | |
198 | ||
199 | if( GET_CMPB() == 0 ) | |
200 | return 2; | |
201 | ||
202 | if( GET_CMPC() == 0 ) | |
203 | return 3; | |
204 | ||
205 | if( GET_CMPD() == 0 ) | |
206 | return 4; | |
207 | ||
208 | return 0; | |
209 | } /* bedbug860_find_empty */ | |
210 | ||
211 | ||
212 | \f | |
213 | /* ====================================================================== | |
214 | * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint | |
215 | * number, otherwise reassign the given breakpoint. If hardware debugging | |
216 | * is not enabled, then turn it on via the MSR and DBCR0. Set the break | |
217 | * address in the appropriate IACx register and enable proper address | |
218 | * beakpoint in DBCR0. | |
219 | * ====================================================================== */ | |
220 | ||
221 | int bedbug860_set( int which_bp, unsigned long addr ) | |
222 | { | |
223 | /* -------------------------------------------------- */ | |
224 | ||
225 | /* Only look if which_bp == 0, else use which_bp */ | |
226 | if(( bug_ctx.find_empty ) && ( !which_bp ) && | |
227 | ( which_bp = (*bug_ctx.find_empty)()) == 0 ) | |
228 | { | |
229 | printf( "All breakpoints in use\n" ); | |
230 | return 0; | |
231 | } | |
232 | ||
233 | if( which_bp < 1 || which_bp > MAX_BREAK_POINTS ) | |
234 | { | |
235 | printf( "Invalid break point # %d\n", which_bp ); | |
236 | return 0; | |
237 | } | |
238 | ||
239 | if( ! bug_ctx.hw_debug_enabled ) | |
240 | { | |
241 | bug_ctx.hw_debug_enabled = 1; | |
242 | SET_DER( GET_DER() | 0x00000004 ); | |
243 | } | |
244 | ||
245 | switch( which_bp ) | |
246 | { | |
247 | case 1: | |
248 | SET_CMPA( addr ); | |
249 | SET_ICTRL( GET_ICTRL() | 0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */ | |
250 | break; | |
251 | ||
252 | case 2: | |
253 | SET_CMPB( addr ); | |
254 | SET_ICTRL( GET_ICTRL() | 0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */ | |
255 | break; | |
256 | ||
257 | case 3: | |
258 | SET_CMPC( addr ); | |
259 | SET_ICTRL( GET_ICTRL() | 0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */ | |
260 | break; | |
261 | ||
262 | case 4: | |
263 | SET_CMPD( addr ); | |
264 | SET_ICTRL( GET_ICTRL() | 0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */ | |
265 | break; | |
266 | } | |
267 | ||
268 | return which_bp; | |
269 | } /* bedbug860_set */ | |
270 | ||
271 | ||
272 | \f | |
273 | /* ====================================================================== | |
274 | * Disable a specific breakoint by setting the appropriate IACx register | |
275 | * to zero and claring the instruction address breakpoint in DBCR0. | |
276 | * ====================================================================== */ | |
277 | ||
278 | int bedbug860_clear( int which_bp ) | |
279 | { | |
280 | /* -------------------------------------------------- */ | |
281 | ||
282 | if( which_bp < 1 || which_bp > MAX_BREAK_POINTS ) | |
283 | { | |
284 | printf( "Invalid break point # (%d)\n", which_bp ); | |
285 | return -1; | |
286 | } | |
287 | ||
288 | switch( which_bp ) | |
289 | { | |
290 | case 1: | |
291 | SET_CMPA( 0 ); | |
292 | SET_ICTRL( GET_ICTRL() & ~0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */ | |
293 | break; | |
294 | ||
295 | case 2: | |
296 | SET_CMPB( 0 ); | |
297 | SET_ICTRL( GET_ICTRL() & ~0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */ | |
298 | break; | |
299 | ||
300 | case 3: | |
301 | SET_CMPC( 0 ); | |
302 | SET_ICTRL( GET_ICTRL() & ~0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */ | |
303 | break; | |
304 | ||
305 | case 4: | |
306 | SET_CMPD( 0 ); | |
307 | SET_ICTRL( GET_ICTRL() & ~0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */ | |
308 | break; | |
309 | } | |
310 | ||
311 | return 0; | |
312 | } /* bedbug860_clear */ | |
313 | ||
314 | ||
315 | /* ====================================================================== */ | |
316 | #endif |