| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1 | /* MN10300 GDB stub | 
|  | 2 | * | 
|  | 3 | * Originally written by Glenn Engel, Lake Stevens Instrument Division | 
|  | 4 | * | 
|  | 5 | * Contributed by HP Systems | 
|  | 6 | * | 
|  | 7 | * Modified for SPARC by Stu Grossman, Cygnus Support. | 
|  | 8 | * | 
|  | 9 | * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse | 
|  | 10 | * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> | 
|  | 11 | * | 
|  | 12 | * Copyright (C) 1995 Andreas Busse | 
|  | 13 | * | 
|  | 14 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 
|  | 15 | * Modified for Linux/mn10300 by David Howells <dhowells@redhat.com> | 
|  | 16 | */ | 
|  | 17 |  | 
|  | 18 | /* | 
|  | 19 | *  To enable debugger support, two things need to happen.  One, a | 
|  | 20 | *  call to set_debug_traps() is necessary in order to allow any breakpoints | 
|  | 21 | *  or error conditions to be properly intercepted and reported to gdb. | 
|  | 22 | *  Two, a breakpoint needs to be generated to begin communication.  This | 
|  | 23 | *  is most easily accomplished by a call to breakpoint().  Breakpoint() | 
|  | 24 | *  simulates a breakpoint by executing a BREAK instruction. | 
|  | 25 | * | 
|  | 26 | * | 
|  | 27 | *    The following gdb commands are supported: | 
|  | 28 | * | 
|  | 29 | * command          function                               Return value | 
|  | 30 | * | 
|  | 31 | *    g             return the value of the CPU registers  hex data or ENN | 
|  | 32 | *    G             set the value of the CPU registers     OK or ENN | 
|  | 33 | * | 
|  | 34 | *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN | 
|  | 35 | *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN | 
|  | 36 | * | 
|  | 37 | *    c             Resume at current address              SNN   ( signal NN) | 
|  | 38 | *    cAA..AA       Continue at address AA..AA             SNN | 
|  | 39 | * | 
|  | 40 | *    s             Step one instruction                   SNN | 
|  | 41 | *    sAA..AA       Step one instruction from AA..AA       SNN | 
|  | 42 | * | 
|  | 43 | *    k             kill | 
|  | 44 | * | 
|  | 45 | *    ?             What was the last sigval ?             SNN   (signal NN) | 
|  | 46 | * | 
|  | 47 | *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets | 
|  | 48 | *							   baud rate | 
|  | 49 | * | 
|  | 50 | * All commands and responses are sent with a packet which includes a | 
|  | 51 | * checksum.  A packet consists of | 
|  | 52 | * | 
|  | 53 | * $<packet info>#<checksum>. | 
|  | 54 | * | 
|  | 55 | * where | 
|  | 56 | * <packet info> :: <characters representing the command or response> | 
|  | 57 | * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>> | 
|  | 58 | * | 
|  | 59 | * When a packet is received, it is first acknowledged with either '+' or '-'. | 
|  | 60 | * '+' indicates a successful transfer.  '-' indicates a failed transfer. | 
|  | 61 | * | 
|  | 62 | * Example: | 
|  | 63 | * | 
|  | 64 | * Host:                  Reply: | 
|  | 65 | * $m0,10#2a               +$00010203040506070809101112131415#42 | 
|  | 66 | * | 
|  | 67 | * | 
|  | 68 | *  ============== | 
|  | 69 | *  MORE EXAMPLES: | 
|  | 70 | *  ============== | 
|  | 71 | * | 
|  | 72 | *  For reference -- the following are the steps that one | 
|  | 73 | *  company took (RidgeRun Inc) to get remote gdb debugging | 
|  | 74 | *  going. In this scenario the host machine was a PC and the | 
|  | 75 | *  target platform was a Galileo EVB64120A MIPS evaluation | 
|  | 76 | *  board. | 
|  | 77 | * | 
|  | 78 | *  Step 1: | 
|  | 79 | *  First download gdb-5.0.tar.gz from the internet. | 
|  | 80 | *  and then build/install the package. | 
|  | 81 | * | 
|  | 82 | *  Example: | 
|  | 83 | *    $ tar zxf gdb-5.0.tar.gz | 
|  | 84 | *    $ cd gdb-5.0 | 
|  | 85 | *    $ ./configure --target=am33_2.0-linux-gnu | 
|  | 86 | *    $ make | 
|  | 87 | *    $ install | 
|  | 88 | *    am33_2.0-linux-gnu-gdb | 
|  | 89 | * | 
|  | 90 | *  Step 2: | 
|  | 91 | *  Configure linux for remote debugging and build it. | 
|  | 92 | * | 
|  | 93 | *  Example: | 
|  | 94 | *    $ cd ~/linux | 
|  | 95 | *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging> | 
|  | 96 | *    $ make dep; make vmlinux | 
|  | 97 | * | 
|  | 98 | *  Step 3: | 
|  | 99 | *  Download the kernel to the remote target and start | 
|  | 100 | *  the kernel running. It will promptly halt and wait | 
|  | 101 | *  for the host gdb session to connect. It does this | 
|  | 102 | *  since the "Kernel Hacking" option has defined | 
|  | 103 | *  CONFIG_REMOTE_DEBUG which in turn enables your calls | 
|  | 104 | *  to: | 
|  | 105 | *     set_debug_traps(); | 
|  | 106 | *     breakpoint(); | 
|  | 107 | * | 
|  | 108 | *  Step 4: | 
|  | 109 | *  Start the gdb session on the host. | 
|  | 110 | * | 
|  | 111 | *  Example: | 
|  | 112 | *    $ am33_2.0-linux-gnu-gdb vmlinux | 
|  | 113 | *    (gdb) set remotebaud 115200 | 
|  | 114 | *    (gdb) target remote /dev/ttyS1 | 
|  | 115 | *    ...at this point you are connected to | 
|  | 116 | *       the remote target and can use gdb | 
|  | 117 | *       in the normal fasion. Setting | 
|  | 118 | *       breakpoints, single stepping, | 
|  | 119 | *       printing variables, etc. | 
|  | 120 | * | 
|  | 121 | */ | 
|  | 122 |  | 
|  | 123 | #include <linux/string.h> | 
|  | 124 | #include <linux/kernel.h> | 
|  | 125 | #include <linux/signal.h> | 
|  | 126 | #include <linux/sched.h> | 
|  | 127 | #include <linux/mm.h> | 
|  | 128 | #include <linux/console.h> | 
|  | 129 | #include <linux/init.h> | 
|  | 130 | #include <linux/bug.h> | 
|  | 131 |  | 
|  | 132 | #include <asm/pgtable.h> | 
|  | 133 | #include <asm/system.h> | 
|  | 134 | #include <asm/gdb-stub.h> | 
|  | 135 | #include <asm/exceptions.h> | 
|  | 136 | #include <asm/cacheflush.h> | 
|  | 137 | #include <asm/serial-regs.h> | 
|  | 138 | #include <asm/busctl-regs.h> | 
|  | 139 | #include <asm/unit/leds.h> | 
|  | 140 | #include <asm/unit/serial.h> | 
|  | 141 |  | 
|  | 142 | /* define to use F7F7 rather than FF which is subverted by JTAG debugger */ | 
|  | 143 | #undef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 144 |  | 
|  | 145 | /* | 
|  | 146 | * BUFMAX defines the maximum number of characters in inbound/outbound buffers | 
|  | 147 | * at least NUMREGBYTES*2 are needed for register packets | 
|  | 148 | */ | 
|  | 149 | #define BUFMAX 2048 | 
|  | 150 |  | 
|  | 151 | static const char gdbstub_banner[] = | 
|  | 152 | "Linux/MN10300 GDB Stub (c) RedHat 2007\n"; | 
|  | 153 |  | 
|  | 154 | u8	gdbstub_rx_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); | 
|  | 155 | u32	gdbstub_rx_inp; | 
|  | 156 | u32	gdbstub_rx_outp; | 
|  | 157 | u8	gdbstub_busy; | 
|  | 158 | u8	gdbstub_rx_overflow; | 
|  | 159 | u8	gdbstub_rx_unget; | 
|  | 160 |  | 
|  | 161 | static u8	gdbstub_flush_caches; | 
|  | 162 | static char	input_buffer[BUFMAX]; | 
|  | 163 | static char	output_buffer[BUFMAX]; | 
|  | 164 | static char	trans_buffer[BUFMAX]; | 
|  | 165 |  | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 166 | struct gdbstub_bkpt { | 
|  | 167 | u8	*addr;		/* address of breakpoint */ | 
|  | 168 | u8	len;		/* size of breakpoint */ | 
|  | 169 | u8	origbytes[7];	/* original bytes */ | 
|  | 170 | }; | 
|  | 171 |  | 
|  | 172 | static struct gdbstub_bkpt gdbstub_bkpts[256]; | 
|  | 173 |  | 
|  | 174 | /* | 
|  | 175 | * local prototypes | 
|  | 176 | */ | 
|  | 177 | static void getpacket(char *buffer); | 
|  | 178 | static int putpacket(char *buffer); | 
|  | 179 | static int computeSignal(enum exception_code excep); | 
|  | 180 | static int hex(unsigned char ch); | 
|  | 181 | static int hexToInt(char **ptr, int *intValue); | 
|  | 182 | static unsigned char *mem2hex(const void *mem, char *buf, int count, | 
|  | 183 | int may_fault); | 
|  | 184 | static const char *hex2mem(const char *buf, void *_mem, int count, | 
|  | 185 | int may_fault); | 
|  | 186 |  | 
|  | 187 | /* | 
|  | 188 | * Convert ch from a hex digit to an int | 
|  | 189 | */ | 
|  | 190 | static int hex(unsigned char ch) | 
|  | 191 | { | 
|  | 192 | if (ch >= 'a' && ch <= 'f') | 
|  | 193 | return ch - 'a' + 10; | 
|  | 194 | if (ch >= '0' && ch <= '9') | 
|  | 195 | return ch - '0'; | 
|  | 196 | if (ch >= 'A' && ch <= 'F') | 
|  | 197 | return ch - 'A' + 10; | 
|  | 198 | return -1; | 
|  | 199 | } | 
|  | 200 |  | 
|  | 201 | #ifdef CONFIG_GDBSTUB_DEBUGGING | 
|  | 202 |  | 
|  | 203 | void debug_to_serial(const char *p, int n) | 
|  | 204 | { | 
|  | 205 | __debug_to_serial(p, n); | 
|  | 206 | /* gdbstub_console_write(NULL, p, n); */ | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | void gdbstub_printk(const char *fmt, ...) | 
|  | 210 | { | 
|  | 211 | va_list args; | 
|  | 212 | int len; | 
|  | 213 |  | 
|  | 214 | /* Emit the output into the temporary buffer */ | 
|  | 215 | va_start(args, fmt); | 
|  | 216 | len = vsnprintf(trans_buffer, sizeof(trans_buffer), fmt, args); | 
|  | 217 | va_end(args); | 
|  | 218 | debug_to_serial(trans_buffer, len); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | #endif | 
|  | 222 |  | 
|  | 223 | static inline char *gdbstub_strcpy(char *dst, const char *src) | 
|  | 224 | { | 
|  | 225 | int loop = 0; | 
|  | 226 | while ((dst[loop] = src[loop])) | 
|  | 227 | loop++; | 
|  | 228 | return dst; | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | /* | 
|  | 232 | * scan for the sequence $<data>#<checksum> | 
|  | 233 | */ | 
|  | 234 | static void getpacket(char *buffer) | 
|  | 235 | { | 
|  | 236 | unsigned char checksum; | 
|  | 237 | unsigned char xmitcsum; | 
|  | 238 | unsigned char ch; | 
|  | 239 | int count, i, ret, error; | 
|  | 240 |  | 
|  | 241 | for (;;) { | 
|  | 242 | /* | 
|  | 243 | * wait around for the start character, | 
|  | 244 | * ignore all other characters | 
|  | 245 | */ | 
|  | 246 | do { | 
|  | 247 | gdbstub_io_rx_char(&ch, 0); | 
|  | 248 | } while (ch != '$'); | 
|  | 249 |  | 
|  | 250 | checksum = 0; | 
|  | 251 | xmitcsum = -1; | 
|  | 252 | count = 0; | 
|  | 253 | error = 0; | 
|  | 254 |  | 
|  | 255 | /* | 
|  | 256 | * now, read until a # or end of buffer is found | 
|  | 257 | */ | 
|  | 258 | while (count < BUFMAX) { | 
|  | 259 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 260 | if (ret < 0) | 
|  | 261 | error = ret; | 
|  | 262 |  | 
|  | 263 | if (ch == '#') | 
|  | 264 | break; | 
|  | 265 | checksum += ch; | 
|  | 266 | buffer[count] = ch; | 
|  | 267 | count++; | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | if (error == -EIO) { | 
|  | 271 | gdbstub_proto("### GDB Rx Error - Skipping packet" | 
|  | 272 | " ###\n"); | 
|  | 273 | gdbstub_proto("### GDB Tx NAK\n"); | 
|  | 274 | gdbstub_io_tx_char('-'); | 
|  | 275 | continue; | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | if (count >= BUFMAX || error) | 
|  | 279 | continue; | 
|  | 280 |  | 
|  | 281 | buffer[count] = 0; | 
|  | 282 |  | 
|  | 283 | /* read the checksum */ | 
|  | 284 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 285 | if (ret < 0) | 
|  | 286 | error = ret; | 
|  | 287 | xmitcsum = hex(ch) << 4; | 
|  | 288 |  | 
|  | 289 | ret = gdbstub_io_rx_char(&ch, 0); | 
|  | 290 | if (ret < 0) | 
|  | 291 | error = ret; | 
|  | 292 | xmitcsum |= hex(ch); | 
|  | 293 |  | 
|  | 294 | if (error) { | 
|  | 295 | if (error == -EIO) | 
|  | 296 | gdbstub_io("### GDB Rx Error -" | 
|  | 297 | " Skipping packet\n"); | 
|  | 298 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 299 | gdbstub_io_tx_char('-'); | 
|  | 300 | continue; | 
|  | 301 | } | 
|  | 302 |  | 
|  | 303 | /* check the checksum */ | 
|  | 304 | if (checksum != xmitcsum) { | 
|  | 305 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 306 | gdbstub_io_tx_char('-');	/* failed checksum */ | 
|  | 307 | continue; | 
|  | 308 | } | 
|  | 309 |  | 
|  | 310 | gdbstub_proto("### GDB Rx '$%s#%02x' ###\n", buffer, checksum); | 
|  | 311 | gdbstub_io("### GDB Tx ACK\n"); | 
|  | 312 | gdbstub_io_tx_char('+'); /* successful transfer */ | 
|  | 313 |  | 
|  | 314 | /* | 
|  | 315 | * if a sequence char is present, | 
|  | 316 | * reply the sequence ID | 
|  | 317 | */ | 
|  | 318 | if (buffer[2] == ':') { | 
|  | 319 | gdbstub_io_tx_char(buffer[0]); | 
|  | 320 | gdbstub_io_tx_char(buffer[1]); | 
|  | 321 |  | 
|  | 322 | /* | 
|  | 323 | * remove sequence chars from buffer | 
|  | 324 | */ | 
|  | 325 | count = 0; | 
|  | 326 | while (buffer[count]) | 
|  | 327 | count++; | 
|  | 328 | for (i = 3; i <= count; i++) | 
|  | 329 | buffer[i - 3] = buffer[i]; | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | break; | 
|  | 333 | } | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | /* | 
|  | 337 | * send the packet in buffer. | 
|  | 338 | * - return 0 if successfully ACK'd | 
|  | 339 | * - return 1 if abandoned due to new incoming packet | 
|  | 340 | */ | 
|  | 341 | static int putpacket(char *buffer) | 
|  | 342 | { | 
|  | 343 | unsigned char checksum; | 
|  | 344 | unsigned char ch; | 
|  | 345 | int count; | 
|  | 346 |  | 
|  | 347 | /* | 
|  | 348 | * $<packet info>#<checksum>. | 
|  | 349 | */ | 
|  | 350 | gdbstub_proto("### GDB Tx $'%s'#?? ###\n", buffer); | 
|  | 351 |  | 
|  | 352 | do { | 
|  | 353 | gdbstub_io_tx_char('$'); | 
|  | 354 | checksum = 0; | 
|  | 355 | count = 0; | 
|  | 356 |  | 
|  | 357 | while ((ch = buffer[count]) != 0) { | 
|  | 358 | gdbstub_io_tx_char(ch); | 
|  | 359 | checksum += ch; | 
|  | 360 | count += 1; | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 | gdbstub_io_tx_char('#'); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 364 | gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
|  | 365 | gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 366 |  | 
|  | 367 | } while (gdbstub_io_rx_char(&ch, 0), | 
|  | 368 | ch == '-' && (gdbstub_io("### GDB Rx NAK\n"), 0), | 
|  | 369 | ch != '-' && ch != '+' && | 
|  | 370 | (gdbstub_io("### GDB Rx ??? %02x\n", ch), 0), | 
|  | 371 | ch != '+' && ch != '$'); | 
|  | 372 |  | 
|  | 373 | if (ch == '+') { | 
|  | 374 | gdbstub_io("### GDB Rx ACK\n"); | 
|  | 375 | return 0; | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | gdbstub_io("### GDB Tx Abandoned\n"); | 
|  | 379 | gdbstub_rx_unget = ch; | 
|  | 380 | return 1; | 
|  | 381 | } | 
|  | 382 |  | 
|  | 383 | /* | 
|  | 384 | * While we find nice hex chars, build an int. | 
|  | 385 | * Return number of chars processed. | 
|  | 386 | */ | 
|  | 387 | static int hexToInt(char **ptr, int *intValue) | 
|  | 388 | { | 
|  | 389 | int numChars = 0; | 
|  | 390 | int hexValue; | 
|  | 391 |  | 
|  | 392 | *intValue = 0; | 
|  | 393 |  | 
|  | 394 | while (**ptr) { | 
|  | 395 | hexValue = hex(**ptr); | 
|  | 396 | if (hexValue < 0) | 
|  | 397 | break; | 
|  | 398 |  | 
|  | 399 | *intValue = (*intValue << 4) | hexValue; | 
|  | 400 | numChars++; | 
|  | 401 |  | 
|  | 402 | (*ptr)++; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | return (numChars); | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | /* | 
|  | 409 | * We single-step by setting breakpoints. When an exception | 
|  | 410 | * is handled, we need to restore the instructions hoisted | 
|  | 411 | * when the breakpoints were set. | 
|  | 412 | * | 
|  | 413 | * This is where we save the original instructions. | 
|  | 414 | */ | 
|  | 415 | static struct gdb_bp_save { | 
|  | 416 | u8	*addr; | 
|  | 417 | u8	opcode[2]; | 
|  | 418 | } step_bp[2]; | 
|  | 419 |  | 
|  | 420 | static const unsigned char gdbstub_insn_sizes[256] = | 
|  | 421 | { | 
|  | 422 | /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */ | 
|  | 423 | 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3,	/* 0 */ | 
|  | 424 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ | 
|  | 425 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ | 
|  | 426 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ | 
|  | 427 | 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ | 
|  | 428 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ | 
|  | 429 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | 
|  | 430 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | 
|  | 431 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ | 
|  | 432 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ | 
|  | 433 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ | 
|  | 434 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ | 
|  | 435 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ | 
|  | 436 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | 
|  | 437 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | 
|  | 438 | 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */ | 
|  | 439 | }; | 
|  | 440 |  | 
|  | 441 | static int __gdbstub_mark_bp(u8 *addr, int ix) | 
|  | 442 | { | 
|  | 443 | if (addr < (u8 *) 0x70000000UL) | 
|  | 444 | return 0; | 
|  | 445 | /* 70000000-7fffffff: vmalloc area */ | 
|  | 446 | if (addr < (u8 *) 0x80000000UL) | 
|  | 447 | goto okay; | 
|  | 448 | if (addr < (u8 *) 0x8c000000UL) | 
|  | 449 | return 0; | 
|  | 450 | /* 8c000000-93ffffff: SRAM, SDRAM */ | 
|  | 451 | if (addr < (u8 *) 0x94000000UL) | 
|  | 452 | goto okay; | 
|  | 453 | return 0; | 
|  | 454 |  | 
|  | 455 | okay: | 
|  | 456 | if (gdbstub_read_byte(addr + 0, &step_bp[ix].opcode[0]) < 0 || | 
|  | 457 | gdbstub_read_byte(addr + 1, &step_bp[ix].opcode[1]) < 0) | 
|  | 458 | return 0; | 
|  | 459 |  | 
|  | 460 | step_bp[ix].addr = addr; | 
|  | 461 | return 1; | 
|  | 462 | } | 
|  | 463 |  | 
|  | 464 | static inline void __gdbstub_restore_bp(void) | 
|  | 465 | { | 
|  | 466 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 467 | if (step_bp[0].addr) { | 
|  | 468 | gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
|  | 469 | gdbstub_write_byte(step_bp[0].opcode[1], step_bp[0].addr + 1); | 
|  | 470 | } | 
|  | 471 | if (step_bp[1].addr) { | 
|  | 472 | gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
|  | 473 | gdbstub_write_byte(step_bp[1].opcode[1], step_bp[1].addr + 1); | 
|  | 474 | } | 
|  | 475 | #else | 
|  | 476 | if (step_bp[0].addr) | 
|  | 477 | gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0); | 
|  | 478 | if (step_bp[1].addr) | 
|  | 479 | gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0); | 
|  | 480 | #endif | 
|  | 481 |  | 
|  | 482 | gdbstub_flush_caches = 1; | 
|  | 483 |  | 
|  | 484 | step_bp[0].addr		= NULL; | 
|  | 485 | step_bp[0].opcode[0]	= 0; | 
|  | 486 | step_bp[0].opcode[1]	= 0; | 
|  | 487 | step_bp[1].addr		= NULL; | 
|  | 488 | step_bp[1].opcode[0]	= 0; | 
|  | 489 | step_bp[1].opcode[1]	= 0; | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | /* | 
|  | 493 | * emulate single stepping by means of breakpoint instructions | 
|  | 494 | */ | 
|  | 495 | static int gdbstub_single_step(struct pt_regs *regs) | 
|  | 496 | { | 
|  | 497 | unsigned size; | 
|  | 498 | uint32_t x; | 
|  | 499 | uint8_t cur, *pc, *sp; | 
|  | 500 |  | 
|  | 501 | step_bp[0].addr		= NULL; | 
|  | 502 | step_bp[0].opcode[0]	= 0; | 
|  | 503 | step_bp[0].opcode[1]	= 0; | 
|  | 504 | step_bp[1].addr		= NULL; | 
|  | 505 | step_bp[1].opcode[0]	= 0; | 
|  | 506 | step_bp[1].opcode[1]	= 0; | 
|  | 507 | x = 0; | 
|  | 508 |  | 
|  | 509 | pc = (u8 *) regs->pc; | 
|  | 510 | sp = (u8 *) (regs + 1); | 
|  | 511 | if (gdbstub_read_byte(pc, &cur) < 0) | 
|  | 512 | return -EFAULT; | 
|  | 513 |  | 
|  | 514 | gdbstub_bkpt("Single Step from %p { %02x }\n", pc, cur); | 
|  | 515 |  | 
|  | 516 | gdbstub_flush_caches = 1; | 
|  | 517 |  | 
|  | 518 | size = gdbstub_insn_sizes[cur]; | 
|  | 519 | if (size > 0) { | 
|  | 520 | if (!__gdbstub_mark_bp(pc + size, 0)) | 
|  | 521 | goto fault; | 
|  | 522 | } else { | 
|  | 523 | switch (cur) { | 
|  | 524 | /* Bxx (d8,PC) */ | 
|  | 525 | case 0xc0: | 
|  | 526 | case 0xc1: | 
|  | 527 | case 0xc2: | 
|  | 528 | case 0xc3: | 
|  | 529 | case 0xc4: | 
|  | 530 | case 0xc5: | 
|  | 531 | case 0xc6: | 
|  | 532 | case 0xc7: | 
|  | 533 | case 0xc8: | 
|  | 534 | case 0xc9: | 
|  | 535 | case 0xca: | 
|  | 536 | if (gdbstub_read_byte(pc + 1, (u8 *) &x) < 0) | 
|  | 537 | goto fault; | 
|  | 538 | if (!__gdbstub_mark_bp(pc + 2, 0)) | 
|  | 539 | goto fault; | 
|  | 540 | if ((x < 0 || x > 2) && | 
|  | 541 | !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
|  | 542 | goto fault; | 
|  | 543 | break; | 
|  | 544 |  | 
|  | 545 | /* LXX (d8,PC) */ | 
|  | 546 | case 0xd0: | 
|  | 547 | case 0xd1: | 
|  | 548 | case 0xd2: | 
|  | 549 | case 0xd3: | 
|  | 550 | case 0xd4: | 
|  | 551 | case 0xd5: | 
|  | 552 | case 0xd6: | 
|  | 553 | case 0xd7: | 
|  | 554 | case 0xd8: | 
|  | 555 | case 0xd9: | 
|  | 556 | case 0xda: | 
|  | 557 | if (!__gdbstub_mark_bp(pc + 1, 0)) | 
|  | 558 | goto fault; | 
|  | 559 | if (regs->pc != regs->lar && | 
|  | 560 | !__gdbstub_mark_bp((u8 *) regs->lar, 1)) | 
|  | 561 | goto fault; | 
|  | 562 | break; | 
|  | 563 |  | 
|  | 564 | /* SETLB - loads the next for bytes into the LIR | 
|  | 565 | * register */ | 
|  | 566 | case 0xdb: | 
|  | 567 | if (!__gdbstub_mark_bp(pc + 1, 0)) | 
|  | 568 | goto fault; | 
|  | 569 | break; | 
|  | 570 |  | 
|  | 571 | /* JMP (d16,PC) or CALL (d16,PC) */ | 
|  | 572 | case 0xcc: | 
|  | 573 | case 0xcd: | 
|  | 574 | if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
|  | 575 | gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0) | 
|  | 576 | goto fault; | 
|  | 577 | if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
|  | 578 | goto fault; | 
|  | 579 | break; | 
|  | 580 |  | 
|  | 581 | /* JMP (d32,PC) or CALL (d32,PC) */ | 
|  | 582 | case 0xdc: | 
|  | 583 | case 0xdd: | 
|  | 584 | if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 || | 
|  | 585 | gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0 || | 
|  | 586 | gdbstub_read_byte(pc + 3, ((u8 *) &x) + 2) < 0 || | 
|  | 587 | gdbstub_read_byte(pc + 4, ((u8 *) &x) + 3) < 0) | 
|  | 588 | goto fault; | 
|  | 589 | if (!__gdbstub_mark_bp(pc + (s32) x, 0)) | 
|  | 590 | goto fault; | 
|  | 591 | break; | 
|  | 592 |  | 
|  | 593 | /* RETF */ | 
|  | 594 | case 0xde: | 
|  | 595 | if (!__gdbstub_mark_bp((u8 *) regs->mdr, 0)) | 
|  | 596 | goto fault; | 
|  | 597 | break; | 
|  | 598 |  | 
|  | 599 | /* RET */ | 
|  | 600 | case 0xdf: | 
|  | 601 | if (gdbstub_read_byte(pc + 2, (u8 *) &x) < 0) | 
|  | 602 | goto fault; | 
|  | 603 | sp += (s8)x; | 
|  | 604 | if (gdbstub_read_byte(sp + 0, ((u8 *) &x) + 0) < 0 || | 
|  | 605 | gdbstub_read_byte(sp + 1, ((u8 *) &x) + 1) < 0 || | 
|  | 606 | gdbstub_read_byte(sp + 2, ((u8 *) &x) + 2) < 0 || | 
|  | 607 | gdbstub_read_byte(sp + 3, ((u8 *) &x) + 3) < 0) | 
|  | 608 | goto fault; | 
|  | 609 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 610 | goto fault; | 
|  | 611 | break; | 
|  | 612 |  | 
|  | 613 | case 0xf0: | 
|  | 614 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 615 | goto fault; | 
|  | 616 |  | 
|  | 617 | if (cur >= 0xf0 && cur <= 0xf7) { | 
|  | 618 | /* JMP (An) / CALLS (An) */ | 
|  | 619 | switch (cur & 3) { | 
|  | 620 | case 0: x = regs->a0; break; | 
|  | 621 | case 1: x = regs->a1; break; | 
|  | 622 | case 2: x = regs->a2; break; | 
|  | 623 | case 3: x = regs->a3; break; | 
|  | 624 | } | 
|  | 625 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 626 | goto fault; | 
|  | 627 | } else if (cur == 0xfc) { | 
|  | 628 | /* RETS */ | 
|  | 629 | if (gdbstub_read_byte( | 
|  | 630 | sp + 0, ((u8 *) &x) + 0) < 0 || | 
|  | 631 | gdbstub_read_byte( | 
|  | 632 | sp + 1, ((u8 *) &x) + 1) < 0 || | 
|  | 633 | gdbstub_read_byte( | 
|  | 634 | sp + 2, ((u8 *) &x) + 2) < 0 || | 
|  | 635 | gdbstub_read_byte( | 
|  | 636 | sp + 3, ((u8 *) &x) + 3) < 0) | 
|  | 637 | goto fault; | 
|  | 638 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 639 | goto fault; | 
|  | 640 | } else if (cur == 0xfd) { | 
|  | 641 | /* RTI */ | 
|  | 642 | if (gdbstub_read_byte( | 
|  | 643 | sp + 4, ((u8 *) &x) + 0) < 0 || | 
|  | 644 | gdbstub_read_byte( | 
|  | 645 | sp + 5, ((u8 *) &x) + 1) < 0 || | 
|  | 646 | gdbstub_read_byte( | 
|  | 647 | sp + 6, ((u8 *) &x) + 2) < 0 || | 
|  | 648 | gdbstub_read_byte( | 
|  | 649 | sp + 7, ((u8 *) &x) + 3) < 0) | 
|  | 650 | goto fault; | 
|  | 651 | if (!__gdbstub_mark_bp((u8 *) x, 0)) | 
|  | 652 | goto fault; | 
|  | 653 | } else { | 
|  | 654 | if (!__gdbstub_mark_bp(pc + 2, 0)) | 
|  | 655 | goto fault; | 
|  | 656 | } | 
|  | 657 |  | 
|  | 658 | break; | 
|  | 659 |  | 
|  | 660 | /* potential 3-byte conditional branches */ | 
|  | 661 | case 0xf8: | 
|  | 662 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 663 | goto fault; | 
|  | 664 | if (!__gdbstub_mark_bp(pc + 3, 0)) | 
|  | 665 | goto fault; | 
|  | 666 |  | 
|  | 667 | if (cur >= 0xe8 && cur <= 0xeb) { | 
|  | 668 | if (gdbstub_read_byte( | 
|  | 669 | pc + 2, ((u8 *) &x) + 0) < 0) | 
|  | 670 | goto fault; | 
|  | 671 | if ((x < 0 || x > 3) && | 
|  | 672 | !__gdbstub_mark_bp(pc + (s8) x, 1)) | 
|  | 673 | goto fault; | 
|  | 674 | } | 
|  | 675 | break; | 
|  | 676 |  | 
|  | 677 | case 0xfa: | 
|  | 678 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 679 | goto fault; | 
|  | 680 |  | 
|  | 681 | if (cur == 0xff) { | 
|  | 682 | /* CALLS (d16,PC) */ | 
|  | 683 | if (gdbstub_read_byte( | 
|  | 684 | pc + 2, ((u8 *) &x) + 0) < 0 || | 
|  | 685 | gdbstub_read_byte( | 
|  | 686 | pc + 3, ((u8 *) &x) + 1) < 0) | 
|  | 687 | goto fault; | 
|  | 688 | if (!__gdbstub_mark_bp(pc + (s16) x, 0)) | 
|  | 689 | goto fault; | 
|  | 690 | } else { | 
|  | 691 | if (!__gdbstub_mark_bp(pc + 4, 0)) | 
|  | 692 | goto fault; | 
|  | 693 | } | 
|  | 694 | break; | 
|  | 695 |  | 
|  | 696 | case 0xfc: | 
|  | 697 | if (gdbstub_read_byte(pc + 1, &cur) < 0) | 
|  | 698 | goto fault; | 
|  | 699 | if (cur == 0xff) { | 
|  | 700 | /* CALLS (d32,PC) */ | 
|  | 701 | if (gdbstub_read_byte( | 
|  | 702 | pc + 2, ((u8 *) &x) + 0) < 0 || | 
|  | 703 | gdbstub_read_byte( | 
|  | 704 | pc + 3, ((u8 *) &x) + 1) < 0 || | 
|  | 705 | gdbstub_read_byte( | 
|  | 706 | pc + 4, ((u8 *) &x) + 2) < 0 || | 
|  | 707 | gdbstub_read_byte( | 
|  | 708 | pc + 5, ((u8 *) &x) + 3) < 0) | 
|  | 709 | goto fault; | 
|  | 710 | if (!__gdbstub_mark_bp( | 
|  | 711 | pc + (s32) x, 0)) | 
|  | 712 | goto fault; | 
|  | 713 | } else { | 
|  | 714 | if (!__gdbstub_mark_bp( | 
|  | 715 | pc + 6, 0)) | 
|  | 716 | goto fault; | 
|  | 717 | } | 
|  | 718 | break; | 
|  | 719 |  | 
|  | 720 | } | 
|  | 721 | } | 
|  | 722 |  | 
|  | 723 | gdbstub_bkpt("Step: %02x at %p; %02x at %p\n", | 
|  | 724 | step_bp[0].opcode[0], step_bp[0].addr, | 
|  | 725 | step_bp[1].opcode[0], step_bp[1].addr); | 
|  | 726 |  | 
|  | 727 | if (step_bp[0].addr) { | 
|  | 728 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 729 | if (gdbstub_write_byte(0xF7, step_bp[0].addr + 0) < 0 || | 
|  | 730 | gdbstub_write_byte(0xF7, step_bp[0].addr + 1) < 0) | 
|  | 731 | goto fault; | 
|  | 732 | #else | 
|  | 733 | if (gdbstub_write_byte(0xFF, step_bp[0].addr + 0) < 0) | 
|  | 734 | goto fault; | 
|  | 735 | #endif | 
|  | 736 | } | 
|  | 737 |  | 
|  | 738 | if (step_bp[1].addr) { | 
|  | 739 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 740 | if (gdbstub_write_byte(0xF7, step_bp[1].addr + 0) < 0 || | 
|  | 741 | gdbstub_write_byte(0xF7, step_bp[1].addr + 1) < 0) | 
|  | 742 | goto fault; | 
|  | 743 | #else | 
|  | 744 | if (gdbstub_write_byte(0xFF, step_bp[1].addr + 0) < 0) | 
|  | 745 | goto fault; | 
|  | 746 | #endif | 
|  | 747 | } | 
|  | 748 |  | 
|  | 749 | return 0; | 
|  | 750 |  | 
|  | 751 | fault: | 
|  | 752 | /* uh-oh - silly address alert, try and restore things */ | 
|  | 753 | __gdbstub_restore_bp(); | 
|  | 754 | return -EFAULT; | 
|  | 755 | } | 
|  | 756 |  | 
|  | 757 | #ifdef CONFIG_GDBSTUB_CONSOLE | 
|  | 758 |  | 
|  | 759 | void gdbstub_console_write(struct console *con, const char *p, unsigned n) | 
|  | 760 | { | 
|  | 761 | static const char gdbstub_cr[] = { 0x0d }; | 
|  | 762 | char outbuf[26]; | 
|  | 763 | int qty; | 
|  | 764 | u8 busy; | 
|  | 765 |  | 
|  | 766 | busy = gdbstub_busy; | 
|  | 767 | gdbstub_busy = 1; | 
|  | 768 |  | 
|  | 769 | outbuf[0] = 'O'; | 
|  | 770 |  | 
|  | 771 | while (n > 0) { | 
|  | 772 | qty = 1; | 
|  | 773 |  | 
|  | 774 | while (n > 0 && qty < 20) { | 
|  | 775 | mem2hex(p, outbuf + qty, 2, 0); | 
|  | 776 | qty += 2; | 
|  | 777 | if (*p == 0x0a) { | 
|  | 778 | mem2hex(gdbstub_cr, outbuf + qty, 2, 0); | 
|  | 779 | qty += 2; | 
|  | 780 | } | 
|  | 781 | p++; | 
|  | 782 | n--; | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | outbuf[qty] = 0; | 
|  | 786 | putpacket(outbuf); | 
|  | 787 | } | 
|  | 788 |  | 
|  | 789 | gdbstub_busy = busy; | 
|  | 790 | } | 
|  | 791 |  | 
|  | 792 | static kdev_t gdbstub_console_dev(struct console *con) | 
|  | 793 | { | 
|  | 794 | return MKDEV(1, 3); /* /dev/null */ | 
|  | 795 | } | 
|  | 796 |  | 
|  | 797 | static struct console gdbstub_console = { | 
|  | 798 | .name	= "gdb", | 
|  | 799 | .write	= gdbstub_console_write, | 
|  | 800 | .device	= gdbstub_console_dev, | 
|  | 801 | .flags	= CON_PRINTBUFFER, | 
|  | 802 | .index	= -1, | 
|  | 803 | }; | 
|  | 804 |  | 
|  | 805 | #endif | 
|  | 806 |  | 
|  | 807 | /* | 
|  | 808 | * Convert the memory pointed to by mem into hex, placing result in buf. | 
|  | 809 | * - if successful, return a pointer to the last char put in buf (NUL) | 
|  | 810 | * - in case of mem fault, return NULL | 
|  | 811 | * may_fault is non-zero if we are reading from arbitrary memory, but is | 
|  | 812 | * currently not used. | 
|  | 813 | */ | 
|  | 814 | static | 
|  | 815 | unsigned char *mem2hex(const void *_mem, char *buf, int count, int may_fault) | 
|  | 816 | { | 
|  | 817 | const u8 *mem = _mem; | 
|  | 818 | u8 ch[4]; | 
|  | 819 |  | 
|  | 820 | if ((u32) mem & 1 && count >= 1) { | 
|  | 821 | if (gdbstub_read_byte(mem, ch) != 0) | 
|  | 822 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 823 | buf = pack_hex_byte(buf, ch[0]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 824 | mem++; | 
|  | 825 | count--; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 | if ((u32) mem & 3 && count >= 2) { | 
|  | 829 | if (gdbstub_read_word(mem, ch) != 0) | 
|  | 830 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 831 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 832 | buf = pack_hex_byte(buf, ch[1]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 833 | mem += 2; | 
|  | 834 | count -= 2; | 
|  | 835 | } | 
|  | 836 |  | 
|  | 837 | while (count >= 4) { | 
|  | 838 | if (gdbstub_read_dword(mem, ch) != 0) | 
|  | 839 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 840 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 841 | buf = pack_hex_byte(buf, ch[1]); | 
|  | 842 | buf = pack_hex_byte(buf, ch[2]); | 
|  | 843 | buf = pack_hex_byte(buf, ch[3]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 844 | mem += 4; | 
|  | 845 | count -= 4; | 
|  | 846 | } | 
|  | 847 |  | 
|  | 848 | if (count >= 2) { | 
|  | 849 | if (gdbstub_read_word(mem, ch) != 0) | 
|  | 850 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 851 | buf = pack_hex_byte(buf, ch[0]); | 
|  | 852 | buf = pack_hex_byte(buf, ch[1]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 853 | mem += 2; | 
|  | 854 | count -= 2; | 
|  | 855 | } | 
|  | 856 |  | 
|  | 857 | if (count >= 1) { | 
|  | 858 | if (gdbstub_read_byte(mem, ch) != 0) | 
|  | 859 | return 0; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 860 | buf = pack_hex_byte(buf, ch[0]); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 861 | } | 
|  | 862 |  | 
|  | 863 | *buf = 0; | 
|  | 864 | return buf; | 
|  | 865 | } | 
|  | 866 |  | 
|  | 867 | /* | 
|  | 868 | * convert the hex array pointed to by buf into binary to be placed in mem | 
|  | 869 | * return a pointer to the character AFTER the last byte written | 
|  | 870 | * may_fault is non-zero if we are reading from arbitrary memory, but is | 
|  | 871 | * currently not used. | 
|  | 872 | */ | 
|  | 873 | static | 
|  | 874 | const char *hex2mem(const char *buf, void *_mem, int count, int may_fault) | 
|  | 875 | { | 
|  | 876 | u8 *mem = _mem; | 
|  | 877 | union { | 
|  | 878 | u32 val; | 
|  | 879 | u8 b[4]; | 
|  | 880 | } ch; | 
|  | 881 |  | 
|  | 882 | if ((u32) mem & 1 && count >= 1) { | 
|  | 883 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 884 | ch.b[0] |= hex(*buf++); | 
|  | 885 | if (gdbstub_write_byte(ch.val, mem) != 0) | 
|  | 886 | return 0; | 
|  | 887 | mem++; | 
|  | 888 | count--; | 
|  | 889 | } | 
|  | 890 |  | 
|  | 891 | if ((u32) mem & 3 && count >= 2) { | 
|  | 892 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 893 | ch.b[0] |= hex(*buf++); | 
|  | 894 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 895 | ch.b[1] |= hex(*buf++); | 
|  | 896 | if (gdbstub_write_word(ch.val, mem) != 0) | 
|  | 897 | return 0; | 
|  | 898 | mem += 2; | 
|  | 899 | count -= 2; | 
|  | 900 | } | 
|  | 901 |  | 
|  | 902 | while (count >= 4) { | 
|  | 903 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 904 | ch.b[0] |= hex(*buf++); | 
|  | 905 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 906 | ch.b[1] |= hex(*buf++); | 
|  | 907 | ch.b[2]  = hex(*buf++) << 4; | 
|  | 908 | ch.b[2] |= hex(*buf++); | 
|  | 909 | ch.b[3]  = hex(*buf++) << 4; | 
|  | 910 | ch.b[3] |= hex(*buf++); | 
|  | 911 | if (gdbstub_write_dword(ch.val, mem) != 0) | 
|  | 912 | return 0; | 
|  | 913 | mem += 4; | 
|  | 914 | count -= 4; | 
|  | 915 | } | 
|  | 916 |  | 
|  | 917 | if (count >= 2) { | 
|  | 918 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 919 | ch.b[0] |= hex(*buf++); | 
|  | 920 | ch.b[1]  = hex(*buf++) << 4; | 
|  | 921 | ch.b[1] |= hex(*buf++); | 
|  | 922 | if (gdbstub_write_word(ch.val, mem) != 0) | 
|  | 923 | return 0; | 
|  | 924 | mem += 2; | 
|  | 925 | count -= 2; | 
|  | 926 | } | 
|  | 927 |  | 
|  | 928 | if (count >= 1) { | 
|  | 929 | ch.b[0]  = hex(*buf++) << 4; | 
|  | 930 | ch.b[0] |= hex(*buf++); | 
|  | 931 | if (gdbstub_write_byte(ch.val, mem) != 0) | 
|  | 932 | return 0; | 
|  | 933 | } | 
|  | 934 |  | 
|  | 935 | return buf; | 
|  | 936 | } | 
|  | 937 |  | 
|  | 938 | /* | 
|  | 939 | * This table contains the mapping between MN10300 exception codes, and | 
|  | 940 | * signals, which are primarily what GDB understands.  It also indicates | 
|  | 941 | * which hardware traps we need to commandeer when initializing the stub. | 
|  | 942 | */ | 
|  | 943 | static const struct excep_to_sig_map { | 
|  | 944 | enum exception_code	excep;	/* MN10300 exception code */ | 
|  | 945 | unsigned char		signo;	/* Signal that we map this into */ | 
|  | 946 | } excep_to_sig_map[] = { | 
|  | 947 | { EXCEP_ITLBMISS,	SIGSEGV		}, | 
|  | 948 | { EXCEP_DTLBMISS,	SIGSEGV		}, | 
|  | 949 | { EXCEP_TRAP,		SIGTRAP		}, | 
|  | 950 | { EXCEP_ISTEP,		SIGTRAP		}, | 
|  | 951 | { EXCEP_IBREAK,		SIGTRAP		}, | 
|  | 952 | { EXCEP_OBREAK,		SIGTRAP		}, | 
|  | 953 | { EXCEP_UNIMPINS,	SIGILL		}, | 
|  | 954 | { EXCEP_UNIMPEXINS,	SIGILL		}, | 
|  | 955 | { EXCEP_MEMERR,		SIGSEGV		}, | 
|  | 956 | { EXCEP_MISALIGN,	SIGSEGV		}, | 
|  | 957 | { EXCEP_BUSERROR,	SIGBUS		}, | 
|  | 958 | { EXCEP_ILLINSACC,	SIGSEGV		}, | 
|  | 959 | { EXCEP_ILLDATACC,	SIGSEGV		}, | 
|  | 960 | { EXCEP_IOINSACC,	SIGSEGV		}, | 
|  | 961 | { EXCEP_PRIVINSACC,	SIGSEGV		}, | 
|  | 962 | { EXCEP_PRIVDATACC,	SIGSEGV		}, | 
|  | 963 | { EXCEP_FPU_DISABLED,	SIGFPE		}, | 
|  | 964 | { EXCEP_FPU_UNIMPINS,	SIGFPE		}, | 
|  | 965 | { EXCEP_FPU_OPERATION,	SIGFPE		}, | 
|  | 966 | { EXCEP_WDT,		SIGALRM		}, | 
|  | 967 | { EXCEP_NMI,		SIGQUIT		}, | 
|  | 968 | { EXCEP_IRQ_LEVEL0,	SIGINT		}, | 
|  | 969 | { EXCEP_IRQ_LEVEL1,	SIGINT		}, | 
|  | 970 | { EXCEP_IRQ_LEVEL2,	SIGINT		}, | 
|  | 971 | { EXCEP_IRQ_LEVEL3,	SIGINT		}, | 
|  | 972 | { EXCEP_IRQ_LEVEL4,	SIGINT		}, | 
|  | 973 | { EXCEP_IRQ_LEVEL5,	SIGINT		}, | 
|  | 974 | { EXCEP_IRQ_LEVEL6,	SIGINT		}, | 
|  | 975 | { 0, 0} | 
|  | 976 | }; | 
|  | 977 |  | 
|  | 978 | /* | 
|  | 979 | * convert the MN10300 exception code into a UNIX signal number | 
|  | 980 | */ | 
|  | 981 | static int computeSignal(enum exception_code excep) | 
|  | 982 | { | 
|  | 983 | const struct excep_to_sig_map *map; | 
|  | 984 |  | 
|  | 985 | for (map = excep_to_sig_map; map->signo; map++) | 
|  | 986 | if (map->excep == excep) | 
|  | 987 | return map->signo; | 
|  | 988 |  | 
|  | 989 | return SIGHUP; /* default for things we don't know about */ | 
|  | 990 | } | 
|  | 991 |  | 
|  | 992 | static u32 gdbstub_fpcr, gdbstub_fpufs_array[32]; | 
|  | 993 |  | 
|  | 994 | /* | 
|  | 995 | * | 
|  | 996 | */ | 
|  | 997 | static void gdbstub_store_fpu(void) | 
|  | 998 | { | 
|  | 999 | #ifdef CONFIG_FPU | 
|  | 1000 |  | 
|  | 1001 | asm volatile( | 
|  | 1002 | "or %2,epsw\n" | 
|  | 1003 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 
|  | 1004 | "nop\n" | 
|  | 1005 | "nop\n" | 
|  | 1006 | #endif | 
|  | 1007 | "mov %1, a1\n" | 
|  | 1008 | "fmov fs0,  (a1+)\n" | 
|  | 1009 | "fmov fs1,  (a1+)\n" | 
|  | 1010 | "fmov fs2,  (a1+)\n" | 
|  | 1011 | "fmov fs3,  (a1+)\n" | 
|  | 1012 | "fmov fs4,  (a1+)\n" | 
|  | 1013 | "fmov fs5,  (a1+)\n" | 
|  | 1014 | "fmov fs6,  (a1+)\n" | 
|  | 1015 | "fmov fs7,  (a1+)\n" | 
|  | 1016 | "fmov fs8,  (a1+)\n" | 
|  | 1017 | "fmov fs9,  (a1+)\n" | 
|  | 1018 | "fmov fs10, (a1+)\n" | 
|  | 1019 | "fmov fs11, (a1+)\n" | 
|  | 1020 | "fmov fs12, (a1+)\n" | 
|  | 1021 | "fmov fs13, (a1+)\n" | 
|  | 1022 | "fmov fs14, (a1+)\n" | 
|  | 1023 | "fmov fs15, (a1+)\n" | 
|  | 1024 | "fmov fs16, (a1+)\n" | 
|  | 1025 | "fmov fs17, (a1+)\n" | 
|  | 1026 | "fmov fs18, (a1+)\n" | 
|  | 1027 | "fmov fs19, (a1+)\n" | 
|  | 1028 | "fmov fs20, (a1+)\n" | 
|  | 1029 | "fmov fs21, (a1+)\n" | 
|  | 1030 | "fmov fs22, (a1+)\n" | 
|  | 1031 | "fmov fs23, (a1+)\n" | 
|  | 1032 | "fmov fs24, (a1+)\n" | 
|  | 1033 | "fmov fs25, (a1+)\n" | 
|  | 1034 | "fmov fs26, (a1+)\n" | 
|  | 1035 | "fmov fs27, (a1+)\n" | 
|  | 1036 | "fmov fs28, (a1+)\n" | 
|  | 1037 | "fmov fs29, (a1+)\n" | 
|  | 1038 | "fmov fs30, (a1+)\n" | 
|  | 1039 | "fmov fs31, (a1+)\n" | 
|  | 1040 | "fmov fpcr, %0\n" | 
|  | 1041 | : "=d"(gdbstub_fpcr) | 
|  | 1042 | : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE) | 
|  | 1043 | : "a1" | 
|  | 1044 | ); | 
|  | 1045 | #endif | 
|  | 1046 | } | 
|  | 1047 |  | 
|  | 1048 | /* | 
|  | 1049 | * | 
|  | 1050 | */ | 
|  | 1051 | static void gdbstub_load_fpu(void) | 
|  | 1052 | { | 
|  | 1053 | #ifdef CONFIG_FPU | 
|  | 1054 |  | 
|  | 1055 | asm volatile( | 
|  | 1056 | "or %1,epsw\n" | 
|  | 1057 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 
|  | 1058 | "nop\n" | 
|  | 1059 | "nop\n" | 
|  | 1060 | #endif | 
|  | 1061 | "mov %0, a1\n" | 
|  | 1062 | "fmov (a1+), fs0\n" | 
|  | 1063 | "fmov (a1+), fs1\n" | 
|  | 1064 | "fmov (a1+), fs2\n" | 
|  | 1065 | "fmov (a1+), fs3\n" | 
|  | 1066 | "fmov (a1+), fs4\n" | 
|  | 1067 | "fmov (a1+), fs5\n" | 
|  | 1068 | "fmov (a1+), fs6\n" | 
|  | 1069 | "fmov (a1+), fs7\n" | 
|  | 1070 | "fmov (a1+), fs8\n" | 
|  | 1071 | "fmov (a1+), fs9\n" | 
|  | 1072 | "fmov (a1+), fs10\n" | 
|  | 1073 | "fmov (a1+), fs11\n" | 
|  | 1074 | "fmov (a1+), fs12\n" | 
|  | 1075 | "fmov (a1+), fs13\n" | 
|  | 1076 | "fmov (a1+), fs14\n" | 
|  | 1077 | "fmov (a1+), fs15\n" | 
|  | 1078 | "fmov (a1+), fs16\n" | 
|  | 1079 | "fmov (a1+), fs17\n" | 
|  | 1080 | "fmov (a1+), fs18\n" | 
|  | 1081 | "fmov (a1+), fs19\n" | 
|  | 1082 | "fmov (a1+), fs20\n" | 
|  | 1083 | "fmov (a1+), fs21\n" | 
|  | 1084 | "fmov (a1+), fs22\n" | 
|  | 1085 | "fmov (a1+), fs23\n" | 
|  | 1086 | "fmov (a1+), fs24\n" | 
|  | 1087 | "fmov (a1+), fs25\n" | 
|  | 1088 | "fmov (a1+), fs26\n" | 
|  | 1089 | "fmov (a1+), fs27\n" | 
|  | 1090 | "fmov (a1+), fs28\n" | 
|  | 1091 | "fmov (a1+), fs29\n" | 
|  | 1092 | "fmov (a1+), fs30\n" | 
|  | 1093 | "fmov (a1+), fs31\n" | 
|  | 1094 | "fmov %2, fpcr\n" | 
|  | 1095 | : | 
|  | 1096 | : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE), "d"(gdbstub_fpcr) | 
|  | 1097 | : "a1" | 
|  | 1098 | ); | 
|  | 1099 | #endif | 
|  | 1100 | } | 
|  | 1101 |  | 
|  | 1102 | /* | 
|  | 1103 | * set a software breakpoint | 
|  | 1104 | */ | 
|  | 1105 | int gdbstub_set_breakpoint(u8 *addr, int len) | 
|  | 1106 | { | 
|  | 1107 | int bkpt, loop, xloop; | 
|  | 1108 |  | 
|  | 1109 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1110 | len = (len + 1) & ~1; | 
|  | 1111 | #endif | 
|  | 1112 |  | 
|  | 1113 | gdbstub_bkpt("setbkpt(%p,%d)\n", addr, len); | 
|  | 1114 |  | 
|  | 1115 | for (bkpt = 255; bkpt >= 0; bkpt--) | 
|  | 1116 | if (!gdbstub_bkpts[bkpt].addr) | 
|  | 1117 | break; | 
|  | 1118 | if (bkpt < 0) | 
|  | 1119 | return -ENOSPC; | 
|  | 1120 |  | 
|  | 1121 | for (loop = 0; loop < len; loop++) | 
|  | 1122 | if (gdbstub_read_byte(&addr[loop], | 
|  | 1123 | &gdbstub_bkpts[bkpt].origbytes[loop] | 
|  | 1124 | ) < 0) | 
|  | 1125 | return -EFAULT; | 
|  | 1126 |  | 
|  | 1127 | gdbstub_flush_caches = 1; | 
|  | 1128 |  | 
|  | 1129 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1130 | for (loop = 0; loop < len; loop++) | 
|  | 1131 | if (gdbstub_write_byte(0xF7, &addr[loop]) < 0) | 
|  | 1132 | goto restore; | 
|  | 1133 | #else | 
|  | 1134 | for (loop = 0; loop < len; loop++) | 
|  | 1135 | if (gdbstub_write_byte(0xFF, &addr[loop]) < 0) | 
|  | 1136 | goto restore; | 
|  | 1137 | #endif | 
|  | 1138 |  | 
|  | 1139 | gdbstub_bkpts[bkpt].addr = addr; | 
|  | 1140 | gdbstub_bkpts[bkpt].len = len; | 
|  | 1141 |  | 
|  | 1142 | gdbstub_bkpt("Set BKPT[%02x]: %p-%p {%02x%02x%02x%02x%02x%02x%02x}\n", | 
|  | 1143 | bkpt, | 
|  | 1144 | gdbstub_bkpts[bkpt].addr, | 
|  | 1145 | gdbstub_bkpts[bkpt].addr + gdbstub_bkpts[bkpt].len - 1, | 
|  | 1146 | gdbstub_bkpts[bkpt].origbytes[0], | 
|  | 1147 | gdbstub_bkpts[bkpt].origbytes[1], | 
|  | 1148 | gdbstub_bkpts[bkpt].origbytes[2], | 
|  | 1149 | gdbstub_bkpts[bkpt].origbytes[3], | 
|  | 1150 | gdbstub_bkpts[bkpt].origbytes[4], | 
|  | 1151 | gdbstub_bkpts[bkpt].origbytes[5], | 
|  | 1152 | gdbstub_bkpts[bkpt].origbytes[6] | 
|  | 1153 | ); | 
|  | 1154 |  | 
|  | 1155 | return 0; | 
|  | 1156 |  | 
|  | 1157 | restore: | 
|  | 1158 | for (xloop = 0; xloop < loop; xloop++) | 
|  | 1159 | gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[xloop], | 
|  | 1160 | addr + xloop); | 
|  | 1161 | return -EFAULT; | 
|  | 1162 | } | 
|  | 1163 |  | 
|  | 1164 | /* | 
|  | 1165 | * clear a software breakpoint | 
|  | 1166 | */ | 
|  | 1167 | int gdbstub_clear_breakpoint(u8 *addr, int len) | 
|  | 1168 | { | 
|  | 1169 | int bkpt, loop; | 
|  | 1170 |  | 
|  | 1171 | #ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT | 
|  | 1172 | len = (len + 1) & ~1; | 
|  | 1173 | #endif | 
|  | 1174 |  | 
|  | 1175 | gdbstub_bkpt("clearbkpt(%p,%d)\n", addr, len); | 
|  | 1176 |  | 
|  | 1177 | for (bkpt = 255; bkpt >= 0; bkpt--) | 
|  | 1178 | if (gdbstub_bkpts[bkpt].addr == addr && | 
|  | 1179 | gdbstub_bkpts[bkpt].len == len) | 
|  | 1180 | break; | 
|  | 1181 | if (bkpt < 0) | 
|  | 1182 | return -ENOENT; | 
|  | 1183 |  | 
|  | 1184 | gdbstub_bkpts[bkpt].addr = NULL; | 
|  | 1185 |  | 
|  | 1186 | gdbstub_flush_caches = 1; | 
|  | 1187 |  | 
|  | 1188 | for (loop = 0; loop < len; loop++) | 
|  | 1189 | if (gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[loop], | 
|  | 1190 | addr + loop) < 0) | 
|  | 1191 | return -EFAULT; | 
|  | 1192 |  | 
|  | 1193 | return 0; | 
|  | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | /* | 
|  | 1197 | * This function does all command processing for interfacing to gdb | 
|  | 1198 | * - returns 1 if the exception should be skipped, 0 otherwise. | 
|  | 1199 | */ | 
|  | 1200 | static int gdbstub(struct pt_regs *regs, enum exception_code excep) | 
|  | 1201 | { | 
|  | 1202 | unsigned long *stack; | 
|  | 1203 | unsigned long epsw, mdr; | 
|  | 1204 | uint32_t zero, ssp; | 
|  | 1205 | uint8_t broke; | 
|  | 1206 | char *ptr; | 
|  | 1207 | int sigval; | 
|  | 1208 | int addr; | 
|  | 1209 | int length; | 
|  | 1210 | int loop; | 
|  | 1211 |  | 
|  | 1212 | if (excep == EXCEP_FPU_DISABLED) | 
|  | 1213 | return 0; | 
|  | 1214 |  | 
|  | 1215 | gdbstub_flush_caches = 0; | 
|  | 1216 |  | 
|  | 1217 | mn10300_set_gdbleds(1); | 
|  | 1218 |  | 
|  | 1219 | asm volatile("mov mdr,%0" : "=d"(mdr)); | 
|  | 1220 | asm volatile("mov epsw,%0" : "=d"(epsw)); | 
|  | 1221 | asm volatile("mov %0,epsw" | 
|  | 1222 | :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1)); | 
|  | 1223 |  | 
|  | 1224 | gdbstub_store_fpu(); | 
|  | 1225 |  | 
|  | 1226 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1227 | /* skip the initial pause loop */ | 
|  | 1228 | if (regs->pc == (unsigned long) __gdbstub_pause) | 
|  | 1229 | regs->pc = (unsigned long) start_kernel; | 
|  | 1230 | #endif | 
|  | 1231 |  | 
|  | 1232 | /* if we were single stepping, restore the opcodes hoisted for the | 
|  | 1233 | * breakpoint[s] */ | 
|  | 1234 | broke = 0; | 
|  | 1235 | if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) || | 
|  | 1236 | (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc)) | 
|  | 1237 | broke = 1; | 
|  | 1238 |  | 
|  | 1239 | __gdbstub_restore_bp(); | 
|  | 1240 |  | 
|  | 1241 | if (gdbstub_rx_unget) { | 
|  | 1242 | sigval = SIGINT; | 
|  | 1243 | if (gdbstub_rx_unget != 3) | 
|  | 1244 | goto packet_waiting; | 
|  | 1245 | gdbstub_rx_unget = 0; | 
|  | 1246 | } | 
|  | 1247 |  | 
|  | 1248 | stack = (unsigned long *) regs->sp; | 
|  | 1249 | sigval = broke ? SIGTRAP : computeSignal(excep); | 
|  | 1250 |  | 
|  | 1251 | /* send information about a BUG() */ | 
|  | 1252 | if (!user_mode(regs) && excep == EXCEP_SYSCALL15) { | 
|  | 1253 | const struct bug_entry *bug; | 
|  | 1254 |  | 
|  | 1255 | bug = find_bug(regs->pc); | 
|  | 1256 | if (bug) | 
|  | 1257 | goto found_bug; | 
|  | 1258 | length = snprintf(trans_buffer, sizeof(trans_buffer), | 
|  | 1259 | "BUG() at address %lx\n", regs->pc); | 
|  | 1260 | goto send_bug_pkt; | 
|  | 1261 |  | 
|  | 1262 | found_bug: | 
|  | 1263 | length = snprintf(trans_buffer, sizeof(trans_buffer), | 
|  | 1264 | "BUG() at address %lx (%s:%d)\n", | 
|  | 1265 | regs->pc, bug->file, bug->line); | 
|  | 1266 |  | 
|  | 1267 | send_bug_pkt: | 
|  | 1268 | ptr = output_buffer; | 
|  | 1269 | *ptr++ = 'O'; | 
|  | 1270 | ptr = mem2hex(trans_buffer, ptr, length, 0); | 
|  | 1271 | *ptr = 0; | 
|  | 1272 | putpacket(output_buffer); | 
|  | 1273 |  | 
|  | 1274 | regs->pc -= 2; | 
|  | 1275 | sigval = SIGABRT; | 
|  | 1276 | } else if (regs->pc == (unsigned long) __gdbstub_bug_trap) { | 
|  | 1277 | regs->pc = regs->mdr; | 
|  | 1278 | sigval = SIGABRT; | 
|  | 1279 | } | 
|  | 1280 |  | 
|  | 1281 | /* | 
|  | 1282 | * send a message to the debugger's user saying what happened if it may | 
|  | 1283 | * not be clear cut (we can't map exceptions onto signals properly) | 
|  | 1284 | */ | 
|  | 1285 | if (sigval != SIGINT && sigval != SIGTRAP && sigval != SIGILL) { | 
|  | 1286 | static const char title[] = "Excep ", tbcberr[] = "BCBERR "; | 
|  | 1287 | static const char crlf[] = "\r\n"; | 
|  | 1288 | char hx; | 
|  | 1289 | u32 bcberr = BCBERR; | 
|  | 1290 |  | 
|  | 1291 | ptr = output_buffer; | 
|  | 1292 | *ptr++ = 'O'; | 
|  | 1293 | ptr = mem2hex(title, ptr, sizeof(title) - 1, 0); | 
|  | 1294 |  | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1295 | hx = hex_asc_hi(excep >> 8); | 
|  | 1296 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1297 | hx = hex_asc_lo(excep >> 8); | 
|  | 1298 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1299 | hx = hex_asc_hi(excep); | 
|  | 1300 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1301 | hx = hex_asc_lo(excep); | 
|  | 1302 | ptr = pack_hex_byte(ptr, hx); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1303 |  | 
|  | 1304 | ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
|  | 1305 | *ptr = 0; | 
|  | 1306 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1307 |  | 
|  | 1308 | /* BCBERR */ | 
|  | 1309 | ptr = output_buffer; | 
|  | 1310 | *ptr++ = 'O'; | 
|  | 1311 | ptr = mem2hex(tbcberr, ptr, sizeof(tbcberr) - 1, 0); | 
|  | 1312 |  | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1313 | hx = hex_asc_hi(bcberr >> 24); | 
|  | 1314 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1315 | hx = hex_asc_lo(bcberr >> 24); | 
|  | 1316 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1317 | hx = hex_asc_hi(bcberr >> 16); | 
|  | 1318 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1319 | hx = hex_asc_lo(bcberr >> 16); | 
|  | 1320 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1321 | hx = hex_asc_hi(bcberr >> 8); | 
|  | 1322 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1323 | hx = hex_asc_lo(bcberr >> 8); | 
|  | 1324 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1325 | hx = hex_asc_hi(bcberr); | 
|  | 1326 | ptr = pack_hex_byte(ptr, hx); | 
|  | 1327 | hx = hex_asc_lo(bcberr); | 
|  | 1328 | ptr = pack_hex_byte(ptr, hx); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1329 |  | 
|  | 1330 | ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0); | 
|  | 1331 | *ptr = 0; | 
|  | 1332 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1333 | } | 
|  | 1334 |  | 
|  | 1335 | /* | 
|  | 1336 | * tell the debugger that an exception has occurred | 
|  | 1337 | */ | 
|  | 1338 | ptr = output_buffer; | 
|  | 1339 |  | 
|  | 1340 | /* | 
|  | 1341 | * Send trap type (converted to signal) | 
|  | 1342 | */ | 
|  | 1343 | *ptr++ = 'T'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1344 | ptr = pack_hex_byte(ptr, sigval); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1345 |  | 
|  | 1346 | /* | 
|  | 1347 | * Send Error PC | 
|  | 1348 | */ | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1349 | ptr = pack_hex_byte(ptr, GDB_REGID_PC); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1350 | *ptr++ = ':'; | 
|  | 1351 | ptr = mem2hex(®s->pc, ptr, 4, 0); | 
|  | 1352 | *ptr++ = ';'; | 
|  | 1353 |  | 
|  | 1354 | /* | 
|  | 1355 | * Send frame pointer | 
|  | 1356 | */ | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1357 | ptr = pack_hex_byte(ptr, GDB_REGID_FP); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1358 | *ptr++ = ':'; | 
|  | 1359 | ptr = mem2hex(®s->a3, ptr, 4, 0); | 
|  | 1360 | *ptr++ = ';'; | 
|  | 1361 |  | 
|  | 1362 | /* | 
|  | 1363 | * Send stack pointer | 
|  | 1364 | */ | 
|  | 1365 | ssp = (unsigned long) (regs + 1); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1366 | ptr = pack_hex_byte(ptr, GDB_REGID_SP); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1367 | *ptr++ = ':'; | 
|  | 1368 | ptr = mem2hex(&ssp, ptr, 4, 0); | 
|  | 1369 | *ptr++ = ';'; | 
|  | 1370 |  | 
|  | 1371 | *ptr++ = 0; | 
|  | 1372 | putpacket(output_buffer);	/* send it off... */ | 
|  | 1373 |  | 
|  | 1374 | packet_waiting: | 
|  | 1375 | /* | 
|  | 1376 | * Wait for input from remote GDB | 
|  | 1377 | */ | 
|  | 1378 | while (1) { | 
|  | 1379 | output_buffer[0] = 0; | 
|  | 1380 | getpacket(input_buffer); | 
|  | 1381 |  | 
|  | 1382 | switch (input_buffer[0]) { | 
|  | 1383 | /* request repeat of last signal number */ | 
|  | 1384 | case '?': | 
|  | 1385 | output_buffer[0] = 'S'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1386 | output_buffer[1] = hex_asc_hi(sigval); | 
|  | 1387 | output_buffer[2] = hex_asc_lo(sigval); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1388 | output_buffer[3] = 0; | 
|  | 1389 | break; | 
|  | 1390 |  | 
|  | 1391 | case 'd': | 
|  | 1392 | /* toggle debug flag */ | 
|  | 1393 | break; | 
|  | 1394 |  | 
|  | 1395 | /* | 
|  | 1396 | * Return the value of the CPU registers | 
|  | 1397 | */ | 
|  | 1398 | case 'g': | 
|  | 1399 | zero = 0; | 
|  | 1400 | ssp = (u32) (regs + 1); | 
|  | 1401 | ptr = output_buffer; | 
|  | 1402 | ptr = mem2hex(®s->d0, ptr, 4, 0); | 
|  | 1403 | ptr = mem2hex(®s->d1, ptr, 4, 0); | 
|  | 1404 | ptr = mem2hex(®s->d2, ptr, 4, 0); | 
|  | 1405 | ptr = mem2hex(®s->d3, ptr, 4, 0); | 
|  | 1406 | ptr = mem2hex(®s->a0, ptr, 4, 0); | 
|  | 1407 | ptr = mem2hex(®s->a1, ptr, 4, 0); | 
|  | 1408 | ptr = mem2hex(®s->a2, ptr, 4, 0); | 
|  | 1409 | ptr = mem2hex(®s->a3, ptr, 4, 0); | 
|  | 1410 |  | 
|  | 1411 | ptr = mem2hex(&ssp, ptr, 4, 0);		/* 8 */ | 
|  | 1412 | ptr = mem2hex(®s->pc, ptr, 4, 0); | 
|  | 1413 | ptr = mem2hex(®s->mdr, ptr, 4, 0); | 
|  | 1414 | ptr = mem2hex(®s->epsw, ptr, 4, 0); | 
|  | 1415 | ptr = mem2hex(®s->lir, ptr, 4, 0); | 
|  | 1416 | ptr = mem2hex(®s->lar, ptr, 4, 0); | 
|  | 1417 | ptr = mem2hex(®s->mdrq, ptr, 4, 0); | 
|  | 1418 |  | 
|  | 1419 | ptr = mem2hex(®s->e0, ptr, 4, 0);	/* 15 */ | 
|  | 1420 | ptr = mem2hex(®s->e1, ptr, 4, 0); | 
|  | 1421 | ptr = mem2hex(®s->e2, ptr, 4, 0); | 
|  | 1422 | ptr = mem2hex(®s->e3, ptr, 4, 0); | 
|  | 1423 | ptr = mem2hex(®s->e4, ptr, 4, 0); | 
|  | 1424 | ptr = mem2hex(®s->e5, ptr, 4, 0); | 
|  | 1425 | ptr = mem2hex(®s->e6, ptr, 4, 0); | 
|  | 1426 | ptr = mem2hex(®s->e7, ptr, 4, 0); | 
|  | 1427 |  | 
|  | 1428 | ptr = mem2hex(&ssp, ptr, 4, 0); | 
|  | 1429 | ptr = mem2hex(®s, ptr, 4, 0); | 
|  | 1430 | ptr = mem2hex(®s->sp, ptr, 4, 0); | 
|  | 1431 | ptr = mem2hex(®s->mcrh, ptr, 4, 0);	/* 26 */ | 
|  | 1432 | ptr = mem2hex(®s->mcrl, ptr, 4, 0); | 
|  | 1433 | ptr = mem2hex(®s->mcvf, ptr, 4, 0); | 
|  | 1434 |  | 
|  | 1435 | ptr = mem2hex(&gdbstub_fpcr, ptr, 4, 0); /* 29 - FPCR */ | 
|  | 1436 | ptr = mem2hex(&zero, ptr, 4, 0); | 
|  | 1437 | ptr = mem2hex(&zero, ptr, 4, 0); | 
|  | 1438 | for (loop = 0; loop < 32; loop++) | 
|  | 1439 | ptr = mem2hex(&gdbstub_fpufs_array[loop], | 
|  | 1440 | ptr, 4, 0); /* 32 - FS0-31 */ | 
|  | 1441 |  | 
|  | 1442 | break; | 
|  | 1443 |  | 
|  | 1444 | /* | 
|  | 1445 | * set the value of the CPU registers - return OK | 
|  | 1446 | */ | 
|  | 1447 | case 'G': | 
|  | 1448 | { | 
|  | 1449 | const char *ptr; | 
|  | 1450 |  | 
|  | 1451 | ptr = &input_buffer[1]; | 
|  | 1452 | ptr = hex2mem(ptr, ®s->d0, 4, 0); | 
|  | 1453 | ptr = hex2mem(ptr, ®s->d1, 4, 0); | 
|  | 1454 | ptr = hex2mem(ptr, ®s->d2, 4, 0); | 
|  | 1455 | ptr = hex2mem(ptr, ®s->d3, 4, 0); | 
|  | 1456 | ptr = hex2mem(ptr, ®s->a0, 4, 0); | 
|  | 1457 | ptr = hex2mem(ptr, ®s->a1, 4, 0); | 
|  | 1458 | ptr = hex2mem(ptr, ®s->a2, 4, 0); | 
|  | 1459 | ptr = hex2mem(ptr, ®s->a3, 4, 0); | 
|  | 1460 |  | 
|  | 1461 | ptr = hex2mem(ptr, &ssp, 4, 0);		/* 8 */ | 
|  | 1462 | ptr = hex2mem(ptr, ®s->pc, 4, 0); | 
|  | 1463 | ptr = hex2mem(ptr, ®s->mdr, 4, 0); | 
|  | 1464 | ptr = hex2mem(ptr, ®s->epsw, 4, 0); | 
|  | 1465 | ptr = hex2mem(ptr, ®s->lir, 4, 0); | 
|  | 1466 | ptr = hex2mem(ptr, ®s->lar, 4, 0); | 
|  | 1467 | ptr = hex2mem(ptr, ®s->mdrq, 4, 0); | 
|  | 1468 |  | 
|  | 1469 | ptr = hex2mem(ptr, ®s->e0, 4, 0);	/* 15 */ | 
|  | 1470 | ptr = hex2mem(ptr, ®s->e1, 4, 0); | 
|  | 1471 | ptr = hex2mem(ptr, ®s->e2, 4, 0); | 
|  | 1472 | ptr = hex2mem(ptr, ®s->e3, 4, 0); | 
|  | 1473 | ptr = hex2mem(ptr, ®s->e4, 4, 0); | 
|  | 1474 | ptr = hex2mem(ptr, ®s->e5, 4, 0); | 
|  | 1475 | ptr = hex2mem(ptr, ®s->e6, 4, 0); | 
|  | 1476 | ptr = hex2mem(ptr, ®s->e7, 4, 0); | 
|  | 1477 |  | 
|  | 1478 | ptr = hex2mem(ptr, &ssp, 4, 0); | 
|  | 1479 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1480 | ptr = hex2mem(ptr, ®s->sp, 4, 0); | 
|  | 1481 | ptr = hex2mem(ptr, ®s->mcrh, 4, 0);	/* 26 */ | 
|  | 1482 | ptr = hex2mem(ptr, ®s->mcrl, 4, 0); | 
|  | 1483 | ptr = hex2mem(ptr, ®s->mcvf, 4, 0); | 
|  | 1484 |  | 
|  | 1485 | ptr = hex2mem(ptr, &zero, 4, 0);	/* 29 - FPCR */ | 
|  | 1486 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1487 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1488 | for (loop = 0; loop < 32; loop++)     /* 32 - FS0-31 */ | 
|  | 1489 | ptr = hex2mem(ptr, &zero, 4, 0); | 
|  | 1490 |  | 
|  | 1491 | #if 0 | 
|  | 1492 | /* | 
|  | 1493 | * See if the stack pointer has moved. If so, then copy | 
|  | 1494 | * the saved locals and ins to the new location. | 
|  | 1495 | */ | 
|  | 1496 | unsigned long *newsp = (unsigned long *) registers[SP]; | 
|  | 1497 | if (sp != newsp) | 
|  | 1498 | sp = memcpy(newsp, sp, 16 * 4); | 
|  | 1499 | #endif | 
|  | 1500 |  | 
|  | 1501 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1502 | } | 
|  | 1503 | break; | 
|  | 1504 |  | 
|  | 1505 | /* | 
|  | 1506 | * mAA..AA,LLLL  Read LLLL bytes at address AA..AA | 
|  | 1507 | */ | 
|  | 1508 | case 'm': | 
|  | 1509 | ptr = &input_buffer[1]; | 
|  | 1510 |  | 
|  | 1511 | if (hexToInt(&ptr, &addr) && | 
|  | 1512 | *ptr++ == ',' && | 
|  | 1513 | hexToInt(&ptr, &length) | 
|  | 1514 | ) { | 
|  | 1515 | if (mem2hex((char *) addr, output_buffer, | 
|  | 1516 | length, 1)) | 
|  | 1517 | break; | 
|  | 1518 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1519 | } else { | 
|  | 1520 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1521 | } | 
|  | 1522 | break; | 
|  | 1523 |  | 
|  | 1524 | /* | 
|  | 1525 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA | 
|  | 1526 | * return OK | 
|  | 1527 | */ | 
|  | 1528 | case 'M': | 
|  | 1529 | ptr = &input_buffer[1]; | 
|  | 1530 |  | 
|  | 1531 | if (hexToInt(&ptr, &addr) && | 
|  | 1532 | *ptr++ == ',' && | 
|  | 1533 | hexToInt(&ptr, &length) && | 
|  | 1534 | *ptr++ == ':' | 
|  | 1535 | ) { | 
|  | 1536 | if (hex2mem(ptr, (char *) addr, length, 1)) | 
|  | 1537 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1538 | else | 
|  | 1539 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1540 |  | 
|  | 1541 | gdbstub_flush_caches = 1; | 
|  | 1542 | } else { | 
|  | 1543 | gdbstub_strcpy(output_buffer, "E02"); | 
|  | 1544 | } | 
|  | 1545 | break; | 
|  | 1546 |  | 
|  | 1547 | /* | 
|  | 1548 | * cAA..AA    Continue at address AA..AA(optional) | 
|  | 1549 | */ | 
|  | 1550 | case 'c': | 
|  | 1551 | /* try to read optional parameter, pc unchanged if no | 
|  | 1552 | * parm */ | 
|  | 1553 |  | 
|  | 1554 | ptr = &input_buffer[1]; | 
|  | 1555 | if (hexToInt(&ptr, &addr)) | 
|  | 1556 | regs->pc = addr; | 
|  | 1557 | goto done; | 
|  | 1558 |  | 
|  | 1559 | /* | 
|  | 1560 | * kill the program | 
|  | 1561 | */ | 
|  | 1562 | case 'k' : | 
|  | 1563 | goto done;	/* just continue */ | 
|  | 1564 |  | 
|  | 1565 | /* | 
|  | 1566 | * Reset the whole machine (FIXME: system dependent) | 
|  | 1567 | */ | 
|  | 1568 | case 'r': | 
|  | 1569 | break; | 
|  | 1570 |  | 
|  | 1571 | /* | 
|  | 1572 | * Step to next instruction | 
|  | 1573 | */ | 
|  | 1574 | case 's': | 
|  | 1575 | /* | 
|  | 1576 | * using the T flag doesn't seem to perform single | 
|  | 1577 | * stepping (it seems to wind up being caught by the | 
|  | 1578 | * JTAG unit), so we have to use breakpoints and | 
|  | 1579 | * continue instead. | 
|  | 1580 | */ | 
|  | 1581 | if (gdbstub_single_step(regs) < 0) | 
|  | 1582 | /* ignore any fault error for now */ | 
|  | 1583 | gdbstub_printk("unable to set single-step" | 
|  | 1584 | " bp\n"); | 
|  | 1585 | goto done; | 
|  | 1586 |  | 
|  | 1587 | /* | 
|  | 1588 | * Set baud rate (bBB) | 
|  | 1589 | */ | 
|  | 1590 | case 'b': | 
|  | 1591 | do { | 
|  | 1592 | int baudrate; | 
|  | 1593 |  | 
|  | 1594 | ptr = &input_buffer[1]; | 
|  | 1595 | if (!hexToInt(&ptr, &baudrate)) { | 
|  | 1596 | gdbstub_strcpy(output_buffer, "B01"); | 
|  | 1597 | break; | 
|  | 1598 | } | 
|  | 1599 |  | 
|  | 1600 | if (baudrate) { | 
|  | 1601 | /* ACK before changing speed */ | 
|  | 1602 | putpacket("OK"); | 
|  | 1603 | gdbstub_io_set_baud(baudrate); | 
|  | 1604 | } | 
|  | 1605 | } while (0); | 
|  | 1606 | break; | 
|  | 1607 |  | 
|  | 1608 | /* | 
|  | 1609 | * Set breakpoint | 
|  | 1610 | */ | 
|  | 1611 | case 'Z': | 
|  | 1612 | ptr = &input_buffer[1]; | 
|  | 1613 |  | 
|  | 1614 | if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
|  | 1615 | !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
|  | 1616 | !hexToInt(&ptr, &length) | 
|  | 1617 | ) { | 
|  | 1618 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1619 | break; | 
|  | 1620 | } | 
|  | 1621 |  | 
|  | 1622 | /* only support software breakpoints */ | 
|  | 1623 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1624 | if (loop != 0 || | 
|  | 1625 | length < 1 || | 
|  | 1626 | length > 7 || | 
|  | 1627 | (unsigned long) addr < 4096) | 
|  | 1628 | break; | 
|  | 1629 |  | 
|  | 1630 | if (gdbstub_set_breakpoint((u8 *) addr, length) < 0) | 
|  | 1631 | break; | 
|  | 1632 |  | 
|  | 1633 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1634 | break; | 
|  | 1635 |  | 
|  | 1636 | /* | 
|  | 1637 | * Clear breakpoint | 
|  | 1638 | */ | 
|  | 1639 | case 'z': | 
|  | 1640 | ptr = &input_buffer[1]; | 
|  | 1641 |  | 
|  | 1642 | if (!hexToInt(&ptr, &loop) || *ptr++ != ',' || | 
|  | 1643 | !hexToInt(&ptr, &addr) || *ptr++ != ',' || | 
|  | 1644 | !hexToInt(&ptr, &length) | 
|  | 1645 | ) { | 
|  | 1646 | gdbstub_strcpy(output_buffer, "E01"); | 
|  | 1647 | break; | 
|  | 1648 | } | 
|  | 1649 |  | 
|  | 1650 | /* only support software breakpoints */ | 
|  | 1651 | gdbstub_strcpy(output_buffer, "E03"); | 
|  | 1652 | if (loop != 0 || | 
|  | 1653 | length < 1 || | 
|  | 1654 | length > 7 || | 
|  | 1655 | (unsigned long) addr < 4096) | 
|  | 1656 | break; | 
|  | 1657 |  | 
|  | 1658 | if (gdbstub_clear_breakpoint((u8 *) addr, length) < 0) | 
|  | 1659 | break; | 
|  | 1660 |  | 
|  | 1661 | gdbstub_strcpy(output_buffer, "OK"); | 
|  | 1662 | break; | 
|  | 1663 |  | 
|  | 1664 | default: | 
|  | 1665 | gdbstub_proto("### GDB Unsupported Cmd '%s'\n", | 
|  | 1666 | input_buffer); | 
|  | 1667 | break; | 
|  | 1668 | } | 
|  | 1669 |  | 
|  | 1670 | /* reply to the request */ | 
|  | 1671 | putpacket(output_buffer); | 
|  | 1672 | } | 
|  | 1673 |  | 
|  | 1674 | done: | 
|  | 1675 | /* | 
|  | 1676 | * Need to flush the instruction cache here, as we may | 
|  | 1677 | * have deposited a breakpoint, and the icache probably | 
|  | 1678 | * has no way of knowing that a data ref to some location | 
|  | 1679 | * may have changed something that is in the instruction | 
|  | 1680 | * cache. | 
|  | 1681 | * NB: We flush both caches, just to be sure... | 
|  | 1682 | */ | 
|  | 1683 | if (gdbstub_flush_caches) | 
|  | 1684 | gdbstub_purge_cache(); | 
|  | 1685 |  | 
|  | 1686 | gdbstub_load_fpu(); | 
|  | 1687 | mn10300_set_gdbleds(0); | 
|  | 1688 | if (excep == EXCEP_NMI) | 
|  | 1689 | NMICR = NMICR_NMIF; | 
|  | 1690 |  | 
|  | 1691 | touch_softlockup_watchdog(); | 
|  | 1692 |  | 
|  | 1693 | local_irq_restore(epsw); | 
|  | 1694 | return 1; | 
|  | 1695 | } | 
|  | 1696 |  | 
|  | 1697 | /* | 
|  | 1698 | * handle event interception | 
|  | 1699 | */ | 
|  | 1700 | asmlinkage int gdbstub_intercept(struct pt_regs *regs, | 
|  | 1701 | enum exception_code excep) | 
|  | 1702 | { | 
|  | 1703 | static u8 notfirst = 1; | 
|  | 1704 | int ret; | 
|  | 1705 |  | 
|  | 1706 | if (gdbstub_busy) | 
|  | 1707 | gdbstub_printk("--> gdbstub reentered itself\n"); | 
|  | 1708 | gdbstub_busy = 1; | 
|  | 1709 |  | 
|  | 1710 | if (notfirst) { | 
|  | 1711 | unsigned long mdr; | 
|  | 1712 | asm("mov mdr,%0" : "=d"(mdr)); | 
|  | 1713 |  | 
|  | 1714 | gdbstub_entry( | 
|  | 1715 | "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n", | 
|  | 1716 | regs, excep, mdr, regs->pc); | 
|  | 1717 |  | 
|  | 1718 | gdbstub_entry( | 
|  | 1719 | "PC:  %08lx EPSW:  %08lx  SSP: %08lx mode: %s\n", | 
|  | 1720 | regs->pc, regs->epsw, (unsigned long) &ret, | 
|  | 1721 | user_mode(regs) ? "User" : "Super"); | 
|  | 1722 | gdbstub_entry( | 
|  | 1723 | "d0:  %08lx   d1:  %08lx   d2: %08lx   d3: %08lx\n", | 
|  | 1724 | regs->d0, regs->d1, regs->d2, regs->d3); | 
|  | 1725 | gdbstub_entry( | 
|  | 1726 | "a0:  %08lx   a1:  %08lx   a2: %08lx   a3: %08lx\n", | 
|  | 1727 | regs->a0, regs->a1, regs->a2, regs->a3); | 
|  | 1728 | gdbstub_entry( | 
|  | 1729 | "e0:  %08lx   e1:  %08lx   e2: %08lx   e3: %08lx\n", | 
|  | 1730 | regs->e0, regs->e1, regs->e2, regs->e3); | 
|  | 1731 | gdbstub_entry( | 
|  | 1732 | "e4:  %08lx   e5:  %08lx   e6: %08lx   e7: %08lx\n", | 
|  | 1733 | regs->e4, regs->e5, regs->e6, regs->e7); | 
|  | 1734 | gdbstub_entry( | 
|  | 1735 | "lar: %08lx   lir: %08lx  mdr: %08lx  usp: %08lx\n", | 
|  | 1736 | regs->lar, regs->lir, regs->mdr, regs->sp); | 
|  | 1737 | gdbstub_entry( | 
|  | 1738 | "cvf: %08lx   crl: %08lx  crh: %08lx  drq: %08lx\n", | 
|  | 1739 | regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq); | 
|  | 1740 | gdbstub_entry( | 
|  | 1741 | "threadinfo=%p task=%p)\n", | 
|  | 1742 | current_thread_info(), current); | 
|  | 1743 | } else { | 
|  | 1744 | notfirst = 1; | 
|  | 1745 | } | 
|  | 1746 |  | 
|  | 1747 | ret = gdbstub(regs, excep); | 
|  | 1748 |  | 
|  | 1749 | gdbstub_entry("<-- gdbstub_intercept()\n"); | 
|  | 1750 | gdbstub_busy = 0; | 
|  | 1751 | return ret; | 
|  | 1752 | } | 
|  | 1753 |  | 
|  | 1754 | /* | 
|  | 1755 | * handle the GDB stub itself causing an exception | 
|  | 1756 | */ | 
|  | 1757 | asmlinkage void gdbstub_exception(struct pt_regs *regs, | 
|  | 1758 | enum exception_code excep) | 
|  | 1759 | { | 
|  | 1760 | unsigned long mdr; | 
|  | 1761 |  | 
|  | 1762 | asm("mov mdr,%0" : "=d"(mdr)); | 
|  | 1763 | gdbstub_entry("--> gdbstub exception({%p},%04x) [MDR=%lx]\n", | 
|  | 1764 | regs, excep, mdr); | 
|  | 1765 |  | 
|  | 1766 | while ((unsigned long) regs == 0xffffffff) {} | 
|  | 1767 |  | 
|  | 1768 | /* handle guarded memory accesses where we know it might fault */ | 
|  | 1769 | if (regs->pc == (unsigned) gdbstub_read_byte_guard) { | 
|  | 1770 | regs->pc = (unsigned) gdbstub_read_byte_cont; | 
|  | 1771 | goto fault; | 
|  | 1772 | } | 
|  | 1773 |  | 
|  | 1774 | if (regs->pc == (unsigned) gdbstub_read_word_guard) { | 
|  | 1775 | regs->pc = (unsigned) gdbstub_read_word_cont; | 
|  | 1776 | goto fault; | 
|  | 1777 | } | 
|  | 1778 |  | 
|  | 1779 | if (regs->pc == (unsigned) gdbstub_read_dword_guard) { | 
|  | 1780 | regs->pc = (unsigned) gdbstub_read_dword_cont; | 
|  | 1781 | goto fault; | 
|  | 1782 | } | 
|  | 1783 |  | 
|  | 1784 | if (regs->pc == (unsigned) gdbstub_write_byte_guard) { | 
|  | 1785 | regs->pc = (unsigned) gdbstub_write_byte_cont; | 
|  | 1786 | goto fault; | 
|  | 1787 | } | 
|  | 1788 |  | 
|  | 1789 | if (regs->pc == (unsigned) gdbstub_write_word_guard) { | 
|  | 1790 | regs->pc = (unsigned) gdbstub_write_word_cont; | 
|  | 1791 | goto fault; | 
|  | 1792 | } | 
|  | 1793 |  | 
|  | 1794 | if (regs->pc == (unsigned) gdbstub_write_dword_guard) { | 
|  | 1795 | regs->pc = (unsigned) gdbstub_write_dword_cont; | 
|  | 1796 | goto fault; | 
|  | 1797 | } | 
|  | 1798 |  | 
|  | 1799 | gdbstub_printk("\n### GDB stub caused an exception ###\n"); | 
|  | 1800 |  | 
|  | 1801 | /* something went horribly wrong */ | 
|  | 1802 | console_verbose(); | 
|  | 1803 | show_registers(regs); | 
|  | 1804 |  | 
|  | 1805 | panic("GDB Stub caused an unexpected exception - can't continue\n"); | 
|  | 1806 |  | 
|  | 1807 | /* we caught an attempt by the stub to access silly memory */ | 
|  | 1808 | fault: | 
|  | 1809 | gdbstub_entry("<-- gdbstub exception() = EFAULT\n"); | 
|  | 1810 | regs->d0 = -EFAULT; | 
|  | 1811 | return; | 
|  | 1812 | } | 
|  | 1813 |  | 
|  | 1814 | /* | 
|  | 1815 | * send an exit message to GDB | 
|  | 1816 | */ | 
|  | 1817 | void gdbstub_exit(int status) | 
|  | 1818 | { | 
|  | 1819 | unsigned char checksum; | 
|  | 1820 | unsigned char ch; | 
|  | 1821 | int count; | 
|  | 1822 |  | 
|  | 1823 | gdbstub_busy = 1; | 
|  | 1824 | output_buffer[0] = 'W'; | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1825 | output_buffer[1] = hex_asc_hi(status); | 
|  | 1826 | output_buffer[2] = hex_asc_lo(status); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1827 | output_buffer[3] = 0; | 
|  | 1828 |  | 
|  | 1829 | gdbstub_io_tx_char('$'); | 
|  | 1830 | checksum = 0; | 
|  | 1831 | count = 0; | 
|  | 1832 |  | 
|  | 1833 | while ((ch = output_buffer[count]) != 0) { | 
|  | 1834 | gdbstub_io_tx_char(ch); | 
|  | 1835 | checksum += ch; | 
|  | 1836 | count += 1; | 
|  | 1837 | } | 
|  | 1838 |  | 
|  | 1839 | gdbstub_io_tx_char('#'); | 
| Harvey Harrison | 2682497 | 2008-07-25 19:45:20 -0700 | [diff] [blame] | 1840 | gdbstub_io_tx_char(hex_asc_hi(checksum)); | 
|  | 1841 | gdbstub_io_tx_char(hex_asc_lo(checksum)); | 
| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1842 |  | 
|  | 1843 | /* make sure the output is flushed, or else RedBoot might clobber it */ | 
|  | 1844 | gdbstub_io_tx_flush(); | 
|  | 1845 |  | 
|  | 1846 | gdbstub_busy = 0; | 
|  | 1847 | } | 
|  | 1848 |  | 
|  | 1849 | /* | 
|  | 1850 | * initialise the GDB stub | 
|  | 1851 | */ | 
|  | 1852 | asmlinkage void __init gdbstub_init(void) | 
|  | 1853 | { | 
|  | 1854 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1855 | unsigned char ch; | 
|  | 1856 | int ret; | 
|  | 1857 | #endif | 
|  | 1858 |  | 
|  | 1859 | gdbstub_busy = 1; | 
|  | 1860 |  | 
|  | 1861 | printk(KERN_INFO "%s", gdbstub_banner); | 
|  | 1862 |  | 
|  | 1863 | gdbstub_io_init(); | 
|  | 1864 |  | 
|  | 1865 | gdbstub_entry("--> gdbstub_init\n"); | 
|  | 1866 |  | 
|  | 1867 | /* try to talk to GDB (or anyone insane enough to want to type GDB | 
|  | 1868 | * protocol by hand) */ | 
|  | 1869 | gdbstub_io("### GDB Tx ACK\n"); | 
|  | 1870 | gdbstub_io_tx_char('+'); /* 'hello world' */ | 
|  | 1871 |  | 
|  | 1872 | #ifdef CONFIG_GDBSTUB_IMMEDIATE | 
|  | 1873 | gdbstub_printk("GDB Stub waiting for packet\n"); | 
|  | 1874 |  | 
|  | 1875 | /* in case GDB is started before us, ACK any packets that are already | 
|  | 1876 | * sitting there (presumably "$?#xx") | 
|  | 1877 | */ | 
|  | 1878 | do { gdbstub_io_rx_char(&ch, 0); } while (ch != '$'); | 
|  | 1879 | do { gdbstub_io_rx_char(&ch, 0); } while (ch != '#'); | 
|  | 1880 | /* eat first csum byte */ | 
|  | 1881 | do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
|  | 1882 | /* eat second csum byte */ | 
|  | 1883 | do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0); | 
|  | 1884 |  | 
|  | 1885 | gdbstub_io("### GDB Tx NAK\n"); | 
|  | 1886 | gdbstub_io_tx_char('-'); /* NAK it */ | 
|  | 1887 |  | 
|  | 1888 | #else | 
|  | 1889 | printk("GDB Stub ready\n"); | 
|  | 1890 | #endif | 
|  | 1891 |  | 
|  | 1892 | gdbstub_busy = 0; | 
|  | 1893 | gdbstub_entry("<-- gdbstub_init\n"); | 
|  | 1894 | } | 
|  | 1895 |  | 
|  | 1896 | /* | 
|  | 1897 | * register the console at a more appropriate time | 
|  | 1898 | */ | 
|  | 1899 | #ifdef CONFIG_GDBSTUB_CONSOLE | 
|  | 1900 | static int __init gdbstub_postinit(void) | 
|  | 1901 | { | 
|  | 1902 | printk(KERN_NOTICE "registering console\n"); | 
|  | 1903 | register_console(&gdbstub_console); | 
|  | 1904 | return 0; | 
|  | 1905 | } | 
|  | 1906 |  | 
|  | 1907 | __initcall(gdbstub_postinit); | 
|  | 1908 | #endif | 
|  | 1909 |  | 
|  | 1910 | /* | 
|  | 1911 | * handle character reception on GDB serial port | 
|  | 1912 | * - jump into the GDB stub if BREAK is detected on the serial line | 
|  | 1913 | */ | 
|  | 1914 | asmlinkage void gdbstub_rx_irq(struct pt_regs *regs, enum exception_code excep) | 
|  | 1915 | { | 
|  | 1916 | char ch; | 
|  | 1917 | int ret; | 
|  | 1918 |  | 
|  | 1919 | gdbstub_entry("--> gdbstub_rx_irq\n"); | 
|  | 1920 |  | 
|  | 1921 | do { | 
|  | 1922 | ret = gdbstub_io_rx_char(&ch, 1); | 
|  | 1923 | if (ret != -EIO && ret != -EAGAIN) { | 
|  | 1924 | if (ret != -EINTR) | 
|  | 1925 | gdbstub_rx_unget = ch; | 
|  | 1926 | gdbstub(regs, excep); | 
|  | 1927 | } | 
|  | 1928 | } while (ret != -EAGAIN); | 
|  | 1929 |  | 
|  | 1930 | gdbstub_entry("<-- gdbstub_rx_irq\n"); | 
|  | 1931 | } |