uboot/arch/powerpc/cpu/ppc4xx/bedbug_405.c
<<
>>
Prefs
   1/*
   2 * Bedbug Functions specific to the PPC405 chip
   3 */
   4
   5#include <common.h>
   6#include <command.h>
   7#include <linux/ctype.h>
   8#include <bedbug/type.h>
   9#include <bedbug/bedbug.h>
  10#include <bedbug/regs.h>
  11#include <bedbug/ppc.h>
  12
  13#if defined(CONFIG_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 * const []));
  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/* ======================================================================
  28 * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
  29 * 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 * const argv[])
  67{
  68        long addr = 0;          /* Address to break at  */
  69        int which_bp;           /* Breakpoint number    */
  70
  71        /* -------------------------------------------------- */
  72
  73        if (argc < 2) {
  74                cmd_usage(cmdtp);
  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                cmd_usage(cmdtp);
 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
 309