blob: a3c2119764c9c1c5f60505ded11f8a73eef96a7c [file] [log] [blame]
wdenk1dda0b12002-08-27 10:52:29 +00001/*
2 * Bedbug Functions specific to the PPC405 chip
3 */
4
5#include <common.h>
6#include <command.h>
7#include <linux/ctype.h>
wdenk57b2d802003-06-27 21:31:46 +00008#include <bedbug/type.h>
wdenk1dda0b12002-08-27 10:52:29 +00009#include <bedbug/bedbug.h>
10#include <bedbug/regs.h>
11#include <bedbug/ppc.h>
12
13#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && defined(CONFIG_4xx)
14
15#define MAX_BREAK_POINTS 4
16
17extern CPU_DEBUG_CTX bug_ctx;
18
19void bedbug405_init __P ((void));
20void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char *[]));
21void bedbug405_break_isr __P ((struct pt_regs *));
22int bedbug405_find_empty __P ((void));
23int bedbug405_set __P ((int, unsigned long));
24int bedbug405_clear __P ((int));
25
26
27/* ======================================================================
Wolfgang Denk0ee70772005-09-23 11:05:55 +020028 * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
wdenk1dda0b12002-08-27 10:52:29 +000029 * of the breakpoints.
30 * ====================================================================== */
31
32void bedbug405_init (void)
33{
34 int i;
35
36 /* -------------------------------------------------- */
37
38 bug_ctx.hw_debug_enabled = 0;
39 bug_ctx.stopped = 0;
40 bug_ctx.current_bp = 0;
41 bug_ctx.regs = NULL;
42
43 bug_ctx.do_break = bedbug405_do_break;
44 bug_ctx.break_isr = bedbug405_break_isr;
45 bug_ctx.find_empty = bedbug405_find_empty;
46 bug_ctx.set = bedbug405_set;
47 bug_ctx.clear = bedbug405_clear;
48
49 for (i = 1; i <= MAX_BREAK_POINTS; ++i)
50 (*bug_ctx.clear) (i);
51
52 puts ("BEDBUG:ready\n");
53 return;
54} /* bedbug_init_breakpoints */
55
56
57
58/* ======================================================================
59 * Set/clear/show one of the hardware breakpoints for the 405. The "off"
60 * string will disable a specific breakpoint. The "show" string will
61 * display the current breakpoints. Otherwise an address will set a
62 * breakpoint at that address. Setting a breakpoint uses the CPU-specific
63 * set routine which will assign a breakpoint number.
64 * ====================================================================== */
65
66void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
67{
68 long addr = 0; /* Address to break at */
69 int which_bp; /* Breakpoint number */
70
71 /* -------------------------------------------------- */
72
73 if (argc < 2) {
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 if (bug_ctx.hw_debug_enabled == 0) {
82 printf ("No breakpoints enabled\n");
83 return;
84 }
85
86 which_bp = simple_strtoul (argv[2], NULL, 10);
87
88 if (bug_ctx.clear)
89 (*bug_ctx.clear) (which_bp);
90
91 printf ("Breakpoint %d removed\n", which_bp);
92 return;
93 }
94
95 /* Show a list of breakpoints */
96
97 if (strcmp (argv[1], "show") == 0) {
98 for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
99
100 switch (which_bp) {
101 case 1:
102 addr = GET_IAC1 ();
103 break;
104 case 2:
105 addr = GET_IAC2 ();
106 break;
107 case 3:
108 addr = GET_IAC3 ();
109 break;
110 case 4:
111 addr = GET_IAC4 ();
112 break;
113 }
114
115 printf ("Breakpoint [%d]: ", which_bp);
116 if (addr == 0)
117 printf ("NOT SET\n");
118 else
119 disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
120 F_RADHEX);
121 }
122 return;
123 }
124
125 /* Set a breakpoint at the address */
126
127 if (!isdigit (argv[1][0])) {
128 printf ("Usage:\n%s\n", cmdtp->usage);
129 return;
130 }
131
132 addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
133
134 if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
135 printf ("Breakpoint [%d]: ", which_bp);
136 disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
137 }
138
139 return;
140} /* bedbug405_do_break */
141
142
143
144/* ======================================================================
145 * Handle a breakpoint. First determine which breakpoint was hit by
146 * looking at the DeBug Status Register (DBSR), clear the breakpoint
147 * and enter a mini main loop. Stay in the loop until the stopped flag
148 * in the debug context is cleared.
149 * ====================================================================== */
150
151void bedbug405_break_isr (struct pt_regs *regs)
152{
153 unsigned long dbsr_val; /* Value of the DBSR */
154 unsigned long addr = 0; /* Address stopped at */
155
156 /* -------------------------------------------------- */
157
158 dbsr_val = GET_DBSR ();
159
160 if (dbsr_val & DBSR_IA1) {
161 bug_ctx.current_bp = 1;
162 addr = GET_IAC1 ();
163 SET_DBSR (DBSR_IA1); /* Write a 1 to clear */
164 } else if (dbsr_val & DBSR_IA2) {
165 bug_ctx.current_bp = 2;
166 addr = GET_IAC2 ();
167 SET_DBSR (DBSR_IA2); /* Write a 1 to clear */
168 } else if (dbsr_val & DBSR_IA3) {
169 bug_ctx.current_bp = 3;
170 addr = GET_IAC3 ();
171 SET_DBSR (DBSR_IA3); /* Write a 1 to clear */
172 } else if (dbsr_val & DBSR_IA4) {
173 bug_ctx.current_bp = 4;
174 addr = GET_IAC4 ();
175 SET_DBSR (DBSR_IA4); /* Write a 1 to clear */
176 }
177
178 bedbug_main_loop (addr, regs);
179 return;
180} /* bedbug405_break_isr */
181
182
183
184/* ======================================================================
185 * Look through all of the hardware breakpoints available to see if one
186 * is unused.
187 * ====================================================================== */
188
189int bedbug405_find_empty (void)
190{
191 /* -------------------------------------------------- */
192
193 if (GET_IAC1 () == 0)
194 return 1;
195
196 if (GET_IAC2 () == 0)
197 return 2;
198
199 if (GET_IAC3 () == 0)
200 return 3;
201
202 if (GET_IAC4 () == 0)
203 return 4;
204
205 return 0;
206} /* bedbug405_find_empty */
207
208
209
210/* ======================================================================
211 * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
212 * number, otherwise reassign the given breakpoint. If hardware debugging
213 * is not enabled, then turn it on via the MSR and DBCR0. Set the break
214 * address in the appropriate IACx register and enable proper address
215 * beakpoint in DBCR0.
216 * ====================================================================== */
217
218int bedbug405_set (int which_bp, unsigned long addr)
219{
220 /* -------------------------------------------------- */
221
222 /* Only look if which_bp == 0, else use which_bp */
223 if ((bug_ctx.find_empty) && (!which_bp) &&
224 (which_bp = (*bug_ctx.find_empty) ()) == 0) {
225 printf ("All breakpoints in use\n");
226 return 0;
227 }
228
229 if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
230 printf ("Invalid break point # %d\n", which_bp);
231 return 0;
232 }
233
234 if (!bug_ctx.hw_debug_enabled) {
235 SET_MSR (GET_MSR () | 0x200); /* set MSR[ DE ] */
236 SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
237 bug_ctx.hw_debug_enabled = 1;
238 }
239
240 switch (which_bp) {
241 case 1:
242 SET_IAC1 (addr);
243 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
244 break;
245
246 case 2:
247 SET_IAC2 (addr);
248 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
249 break;
250
251 case 3:
252 SET_IAC3 (addr);
253 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
254 break;
255
256 case 4:
257 SET_IAC4 (addr);
258 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
259 break;
260 }
261
262 return which_bp;
263} /* bedbug405_set */
264
265
266
267/* ======================================================================
268 * Disable a specific breakoint by setting the appropriate IACx register
269 * to zero and claring the instruction address breakpoint in DBCR0.
270 * ====================================================================== */
271
272int bedbug405_clear (int which_bp)
273{
274 /* -------------------------------------------------- */
275
276 if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
277 printf ("Invalid break point # (%d)\n", which_bp);
278 return -1;
279 }
280
281 switch (which_bp) {
282 case 1:
283 SET_IAC1 (0);
284 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
285 break;
286
287 case 2:
288 SET_IAC2 (0);
289 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
290 break;
291
292 case 3:
293 SET_IAC3 (0);
294 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
295 break;
296
297 case 4:
298 SET_IAC4 (0);
299 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
300 break;
301 }
302
303 return 0;
304} /* bedbug405_clear */
305
306
307/* ====================================================================== */
308#endif