bedbug_405.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. * Bedbug Functions specific to the PPC405 chip
  3. */
  4. #include <common.h>
  5. #include <command.h>
  6. #include <linux/ctype.h>
  7. #include <bedbug/type.h>
  8. #include <bedbug/bedbug.h>
  9. #include <bedbug/regs.h>
  10. #include <bedbug/ppc.h>
  11. #if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx)
  12. #define MAX_BREAK_POINTS 4
  13. extern CPU_DEBUG_CTX bug_ctx;
  14. void bedbug405_init __P ((void));
  15. void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char *[]));
  16. void bedbug405_break_isr __P ((struct pt_regs *));
  17. int bedbug405_find_empty __P ((void));
  18. int bedbug405_set __P ((int, unsigned long));
  19. int bedbug405_clear __P ((int));
  20. /* ======================================================================
  21. * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
  22. * of the breakpoints.
  23. * ====================================================================== */
  24. void bedbug405_init (void)
  25. {
  26. int i;
  27. /* -------------------------------------------------- */
  28. bug_ctx.hw_debug_enabled = 0;
  29. bug_ctx.stopped = 0;
  30. bug_ctx.current_bp = 0;
  31. bug_ctx.regs = NULL;
  32. bug_ctx.do_break = bedbug405_do_break;
  33. bug_ctx.break_isr = bedbug405_break_isr;
  34. bug_ctx.find_empty = bedbug405_find_empty;
  35. bug_ctx.set = bedbug405_set;
  36. bug_ctx.clear = bedbug405_clear;
  37. for (i = 1; i <= MAX_BREAK_POINTS; ++i)
  38. (*bug_ctx.clear) (i);
  39. puts ("BEDBUG:ready\n");
  40. return;
  41. } /* bedbug_init_breakpoints */
  42. /* ======================================================================
  43. * Set/clear/show one of the hardware breakpoints for the 405. The "off"
  44. * string will disable a specific breakpoint. The "show" string will
  45. * display the current breakpoints. Otherwise an address will set a
  46. * breakpoint at that address. Setting a breakpoint uses the CPU-specific
  47. * set routine which will assign a breakpoint number.
  48. * ====================================================================== */
  49. void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  50. {
  51. long addr = 0; /* Address to break at */
  52. int which_bp; /* Breakpoint number */
  53. /* -------------------------------------------------- */
  54. if (argc < 2) {
  55. cmd_usage(cmdtp);
  56. return;
  57. }
  58. /* Turn off a breakpoint */
  59. if (strcmp (argv[1], "off") == 0) {
  60. if (bug_ctx.hw_debug_enabled == 0) {
  61. printf ("No breakpoints enabled\n");
  62. return;
  63. }
  64. which_bp = simple_strtoul (argv[2], NULL, 10);
  65. if (bug_ctx.clear)
  66. (*bug_ctx.clear) (which_bp);
  67. printf ("Breakpoint %d removed\n", which_bp);
  68. return;
  69. }
  70. /* Show a list of breakpoints */
  71. if (strcmp (argv[1], "show") == 0) {
  72. for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
  73. switch (which_bp) {
  74. case 1:
  75. addr = GET_IAC1 ();
  76. break;
  77. case 2:
  78. addr = GET_IAC2 ();
  79. break;
  80. case 3:
  81. addr = GET_IAC3 ();
  82. break;
  83. case 4:
  84. addr = GET_IAC4 ();
  85. break;
  86. }
  87. printf ("Breakpoint [%d]: ", which_bp);
  88. if (addr == 0)
  89. printf ("NOT SET\n");
  90. else
  91. disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
  92. F_RADHEX);
  93. }
  94. return;
  95. }
  96. /* Set a breakpoint at the address */
  97. if (!isdigit (argv[1][0])) {
  98. cmd_usage(cmdtp);
  99. return;
  100. }
  101. addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
  102. if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
  103. printf ("Breakpoint [%d]: ", which_bp);
  104. disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
  105. }
  106. return;
  107. } /* bedbug405_do_break */
  108. /* ======================================================================
  109. * Handle a breakpoint. First determine which breakpoint was hit by
  110. * looking at the DeBug Status Register (DBSR), clear the breakpoint
  111. * and enter a mini main loop. Stay in the loop until the stopped flag
  112. * in the debug context is cleared.
  113. * ====================================================================== */
  114. void bedbug405_break_isr (struct pt_regs *regs)
  115. {
  116. unsigned long dbsr_val; /* Value of the DBSR */
  117. unsigned long addr = 0; /* Address stopped at */
  118. /* -------------------------------------------------- */
  119. dbsr_val = GET_DBSR ();
  120. if (dbsr_val & DBSR_IA1) {
  121. bug_ctx.current_bp = 1;
  122. addr = GET_IAC1 ();
  123. SET_DBSR (DBSR_IA1); /* Write a 1 to clear */
  124. } else if (dbsr_val & DBSR_IA2) {
  125. bug_ctx.current_bp = 2;
  126. addr = GET_IAC2 ();
  127. SET_DBSR (DBSR_IA2); /* Write a 1 to clear */
  128. } else if (dbsr_val & DBSR_IA3) {
  129. bug_ctx.current_bp = 3;
  130. addr = GET_IAC3 ();
  131. SET_DBSR (DBSR_IA3); /* Write a 1 to clear */
  132. } else if (dbsr_val & DBSR_IA4) {
  133. bug_ctx.current_bp = 4;
  134. addr = GET_IAC4 ();
  135. SET_DBSR (DBSR_IA4); /* Write a 1 to clear */
  136. }
  137. bedbug_main_loop (addr, regs);
  138. return;
  139. } /* bedbug405_break_isr */
  140. /* ======================================================================
  141. * Look through all of the hardware breakpoints available to see if one
  142. * is unused.
  143. * ====================================================================== */
  144. int bedbug405_find_empty (void)
  145. {
  146. /* -------------------------------------------------- */
  147. if (GET_IAC1 () == 0)
  148. return 1;
  149. if (GET_IAC2 () == 0)
  150. return 2;
  151. if (GET_IAC3 () == 0)
  152. return 3;
  153. if (GET_IAC4 () == 0)
  154. return 4;
  155. return 0;
  156. } /* bedbug405_find_empty */
  157. /* ======================================================================
  158. * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
  159. * number, otherwise reassign the given breakpoint. If hardware debugging
  160. * is not enabled, then turn it on via the MSR and DBCR0. Set the break
  161. * address in the appropriate IACx register and enable proper address
  162. * beakpoint in DBCR0.
  163. * ====================================================================== */
  164. int bedbug405_set (int which_bp, unsigned long addr)
  165. {
  166. /* -------------------------------------------------- */
  167. /* Only look if which_bp == 0, else use which_bp */
  168. if ((bug_ctx.find_empty) && (!which_bp) &&
  169. (which_bp = (*bug_ctx.find_empty) ()) == 0) {
  170. printf ("All breakpoints in use\n");
  171. return 0;
  172. }
  173. if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
  174. printf ("Invalid break point # %d\n", which_bp);
  175. return 0;
  176. }
  177. if (!bug_ctx.hw_debug_enabled) {
  178. SET_MSR (GET_MSR () | 0x200); /* set MSR[ DE ] */
  179. SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
  180. bug_ctx.hw_debug_enabled = 1;
  181. }
  182. switch (which_bp) {
  183. case 1:
  184. SET_IAC1 (addr);
  185. SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
  186. break;
  187. case 2:
  188. SET_IAC2 (addr);
  189. SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
  190. break;
  191. case 3:
  192. SET_IAC3 (addr);
  193. SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
  194. break;
  195. case 4:
  196. SET_IAC4 (addr);
  197. SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
  198. break;
  199. }
  200. return which_bp;
  201. } /* bedbug405_set */
  202. /* ======================================================================
  203. * Disable a specific breakoint by setting the appropriate IACx register
  204. * to zero and claring the instruction address breakpoint in DBCR0.
  205. * ====================================================================== */
  206. int bedbug405_clear (int which_bp)
  207. {
  208. /* -------------------------------------------------- */
  209. if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
  210. printf ("Invalid break point # (%d)\n", which_bp);
  211. return -1;
  212. }
  213. switch (which_bp) {
  214. case 1:
  215. SET_IAC1 (0);
  216. SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
  217. break;
  218. case 2:
  219. SET_IAC2 (0);
  220. SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
  221. break;
  222. case 3:
  223. SET_IAC3 (0);
  224. SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
  225. break;
  226. case 4:
  227. SET_IAC4 (0);
  228. SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
  229. break;
  230. }
  231. return 0;
  232. } /* bedbug405_clear */
  233. /* ====================================================================== */
  234. #endif