1/* $Id: sparc-stub.c,v 1.1.1.1 2007/08/03 18:52:17 Exp $ 2 * sparc-stub.c: KGDB support for the Linux kernel. 3 * 4 * Modifications to run under Linux 5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6 * 7 * This file originally came from the gdb sources, and the 8 * copyright notices have been retained below. 9 */ 10 11/**************************************************************************** 12 13 THIS SOFTWARE IS NOT COPYRIGHTED 14 15 HP offers the following for use in the public domain. HP makes no 16 warranty with regard to the software or its performance and the 17 user accepts the software "AS IS" with all faults. 18 19 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD 20 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 23****************************************************************************/ 24 25/**************************************************************************** 26 * Header: remcom.c,v 1.34 91/03/09 12:29:49 Exp $ 27 * 28 * Module name: remcom.c $ 29 * Revision: 1.34 $ 30 * Date: 91/03/09 12:29:49 $ 31 * Contributor: Lake Stevens Instrument Division$ 32 * 33 * Description: low level support for gdb debugger. $ 34 * 35 * Considerations: only works on target hardware $ 36 * 37 * Written by: Glenn Engel $ 38 * ModuleState: Experimental $ 39 * 40 * NOTES: See Below $ 41 * 42 * Modified for SPARC by Stu Grossman, Cygnus Support. 43 * 44 * This code has been extensively tested on the Fujitsu SPARClite demo board. 45 * 46 * To enable debugger support, two things need to happen. One, a 47 * call to set_debug_traps() is necessary in order to allow any breakpoints 48 * or error conditions to be properly intercepted and reported to gdb. 49 * Two, a breakpoint needs to be generated to begin communication. This 50 * is most easily accomplished by a call to breakpoint(). Breakpoint() 51 * simulates a breakpoint by executing a trap #1. 52 * 53 ************* 54 * 55 * The following gdb commands are supported: 56 * 57 * command function Return value 58 * 59 * g return the value of the CPU registers hex data or ENN 60 * G set the value of the CPU registers OK or ENN 61 * 62 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN 63 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN 64 * 65 * c Resume at current address SNN ( signal NN) 66 * cAA..AA Continue at address AA..AA SNN 67 * 68 * s Step one instruction SNN 69 * sAA..AA Step one instruction from AA..AA SNN 70 * 71 * k kill 72 * 73 * ? What was the last sigval ? SNN (signal NN) 74 * 75 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets 76 * baud rate 77 * 78 * All commands and responses are sent with a packet which includes a 79 * checksum. A packet consists of 80 * 81 * $<packet info>#<checksum>. 82 * 83 * where 84 * <packet info> :: <characters representing the command or response> 85 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> 86 * 87 * When a packet is received, it is first acknowledged with either '+' or '-'. 88 * '+' indicates a successful transfer. '-' indicates a failed transfer. 89 * 90 * Example: 91 * 92 * Host: Reply: 93 * $m0,10#2a +$00010203040506070809101112131415#42 94 * 95 ****************************************************************************/ 96 97#include <linux/kernel.h> 98#include <linux/string.h> 99#include <linux/mm.h> 100#include <linux/smp.h> 101#include <linux/smp_lock.h> 102 103#include <asm/system.h> 104#include <asm/signal.h> 105#include <asm/oplib.h> 106#include <asm/head.h> 107#include <asm/traps.h> 108#include <asm/vac-ops.h> 109#include <asm/kgdb.h> 110#include <asm/pgalloc.h> 111#include <asm/pgtable.h> 112#include <asm/cacheflush.h> 113 114/* 115 * 116 * external low-level support routines 117 */ 118 119extern void putDebugChar(char); /* write a single character */ 120extern char getDebugChar(void); /* read and return a single char */ 121 122/* 123 * BUFMAX defines the maximum number of characters in inbound/outbound buffers 124 * at least NUMREGBYTES*2 are needed for register packets 125 */ 126#define BUFMAX 2048 127 128static int initialized; /* !0 means we've been initialized */ 129 130static const char hexchars[]="0123456789abcdef"; 131 132#define NUMREGS 72 133 134/* Number of bytes of registers. */ 135#define NUMREGBYTES (NUMREGS * 4) 136enum regnames {G0, G1, G2, G3, G4, G5, G6, G7, 137 O0, O1, O2, O3, O4, O5, SP, O7, 138 L0, L1, L2, L3, L4, L5, L6, L7, 139 I0, I1, I2, I3, I4, I5, FP, I7, 140 141 F0, F1, F2, F3, F4, F5, F6, F7, 142 F8, F9, F10, F11, F12, F13, F14, F15, 143 F16, F17, F18, F19, F20, F21, F22, F23, 144 F24, F25, F26, F27, F28, F29, F30, F31, 145 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR }; 146 147 148extern void trap_low(void); /* In arch/sparc/kernel/entry.S */ 149 150unsigned long get_sun4cpte(unsigned long addr) 151{ 152 unsigned long entry; 153 154 __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 155 "=r" (entry) : 156 "r" (addr), "i" (ASI_PTE)); 157 return entry; 158} 159 160unsigned long get_sun4csegmap(unsigned long addr) 161{ 162 unsigned long entry; 163 164 __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : 165 "=r" (entry) : 166 "r" (addr), "i" (ASI_SEGMAP)); 167 return entry; 168} 169 170 171/* Place where we save old trap entries for restoration */ 172struct tt_entry kgdb_savettable[256]; 173typedef void (*trapfunc_t)(void); 174 175/* Helper routine for manipulation of kgdb_savettable */ 176static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest) 177{ 178 dest->inst_one = src->inst_one; 179 dest->inst_two = src->inst_two; 180 dest->inst_three = src->inst_three; 181 dest->inst_four = src->inst_four; 182} 183 184/* Initialize the kgdb_savettable so that debugging can commence */ 185static void eh_init(void) 186{ 187 int i; 188 189 for(i=0; i < 256; i++) 190 copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]); 191} 192 193/* Install an exception handler for kgdb */ 194static void exceptionHandler(int tnum, trapfunc_t trap_entry) 195{ 196 unsigned long te_addr = (unsigned long) trap_entry; 197 198 /* Make new vector */ 199 sparc_ttable[tnum].inst_one = 200 SPARC_BRANCH((unsigned long) te_addr, 201 (unsigned long) &sparc_ttable[tnum].inst_one); 202 sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0; 203 sparc_ttable[tnum].inst_three = SPARC_NOP; 204 sparc_ttable[tnum].inst_four = SPARC_NOP; 205} 206 207/* Convert ch from a hex digit to an int */ 208static int 209hex(unsigned char ch) 210{ 211 if (ch >= 'a' && ch <= 'f') 212 return ch-'a'+10; 213 if (ch >= '0' && ch <= '9') 214 return ch-'0'; 215 if (ch >= 'A' && ch <= 'F') 216 return ch-'A'+10; 217 return -1; 218} 219 220/* scan for the sequence $<data>#<checksum> */ 221static void 222getpacket(char *buffer) 223{ 224 unsigned char checksum; 225 unsigned char xmitcsum; 226 int i; 227 int count; 228 unsigned char ch; 229 230 do { 231 /* wait around for the start character, ignore all other characters */ 232 while ((ch = (getDebugChar() & 0x7f)) != '$') ; 233 234 checksum = 0; 235 xmitcsum = -1; 236 237 count = 0; 238 239 /* now, read until a # or end of buffer is found */ 240 while (count < BUFMAX) { 241 ch = getDebugChar() & 0x7f; 242 if (ch == '#') 243 break; 244 checksum = checksum + ch; 245 buffer[count] = ch; 246 count = count + 1; 247 } 248 249 if (count >= BUFMAX) 250 continue; 251 252 buffer[count] = 0; 253 254 if (ch == '#') { 255 xmitcsum = hex(getDebugChar() & 0x7f) << 4; 256 xmitcsum |= hex(getDebugChar() & 0x7f); 257 if (checksum != xmitcsum) 258 putDebugChar('-'); /* failed checksum */ 259 else { 260 putDebugChar('+'); /* successful transfer */ 261 /* if a sequence char is present, reply the ID */ 262 if (buffer[2] == ':') { 263 putDebugChar(buffer[0]); 264 putDebugChar(buffer[1]); 265 /* remove sequence chars from buffer */ 266 count = strlen(buffer); 267 for (i=3; i <= count; i++) 268 buffer[i-3] = buffer[i]; 269 } 270 } 271 } 272 } while (checksum != xmitcsum); 273} 274 275/* send the packet in buffer. */ 276 277static void 278putpacket(unsigned char *buffer) 279{ 280 unsigned char checksum; 281 int count; 282 unsigned char ch, recv; 283 284 /* $<packet info>#<checksum>. */ 285 do { 286 putDebugChar('$'); 287 checksum = 0; 288 count = 0; 289 290 while ((ch = buffer[count])) { 291 putDebugChar(ch); 292 checksum += ch; 293 count += 1; 294 } 295 296 putDebugChar('#'); 297 putDebugChar(hexchars[checksum >> 4]); 298 putDebugChar(hexchars[checksum & 0xf]); 299 recv = getDebugChar(); 300 } while ((recv & 0x7f) != '+'); 301} 302 303static char remcomInBuffer[BUFMAX]; 304static char remcomOutBuffer[BUFMAX]; 305 306/* Convert the memory pointed to by mem into hex, placing result in buf. 307 * Return a pointer to the last char put in buf (null), in case of mem fault, 308 * return 0. 309 */ 310 311static unsigned char * 312mem2hex(char *mem, char *buf, int count) 313{ 314 unsigned char ch; 315 316 while (count-- > 0) { 317 /* This assembler code is basically: ch = *mem++; 318 * except that we use the SPARC/Linux exception table 319 * mechanism (see how "fixup" works in kernel_mna_trap_fault) 320 * to arrange for a "return 0" upon a memory fault 321 */ 322 __asm__( 323 "\n1:\n\t" 324 "ldub [%0], %1\n\t" 325 "inc %0\n\t" 326 ".section .fixup,#alloc,#execinstr\n\t" 327 ".align 4\n" 328 "2:\n\t" 329 "retl\n\t" 330 " mov 0, %%o0\n\t" 331 ".section __ex_table, #alloc\n\t" 332 ".align 4\n\t" 333 ".word 1b, 2b\n\t" 334 ".text\n" 335 : "=r" (mem), "=r" (ch) : "0" (mem)); 336 *buf++ = hexchars[ch >> 4]; 337 *buf++ = hexchars[ch & 0xf]; 338 } 339 340 *buf = 0; 341 return buf; 342} 343 344/* convert the hex array pointed to by buf into binary to be placed in mem 345 * return a pointer to the character AFTER the last byte written. 346*/ 347static char * 348hex2mem(char *buf, char *mem, int count) 349{ 350 int i; 351 unsigned char ch; 352 353 for (i=0; i<count; i++) { 354 355 ch = hex(*buf++) << 4; 356 ch |= hex(*buf++); 357 /* Assembler code is *mem++ = ch; with return 0 on fault */ 358 __asm__( 359 "\n1:\n\t" 360 "stb %1, [%0]\n\t" 361 "inc %0\n\t" 362 ".section .fixup,#alloc,#execinstr\n\t" 363 ".align 4\n" 364 "2:\n\t" 365 "retl\n\t" 366 " mov 0, %%o0\n\t" 367 ".section __ex_table, #alloc\n\t" 368 ".align 4\n\t" 369 ".word 1b, 2b\n\t" 370 ".text\n" 371 : "=r" (mem) : "r" (ch) , "0" (mem)); 372 } 373 return mem; 374} 375 376/* This table contains the mapping between SPARC hardware trap types, and 377 signals, which are primarily what GDB understands. It also indicates 378 which hardware traps we need to commandeer when initializing the stub. */ 379 380static struct hard_trap_info 381{ 382 unsigned char tt; /* Trap type code for SPARC */ 383 unsigned char signo; /* Signal that we map this trap into */ 384} hard_trap_info[] = { 385 {SP_TRAP_SBPT, SIGTRAP}, /* ta 1 - Linux/KGDB software breakpoint */ 386 {0, 0} /* Must be last */ 387}; 388 389/* Set up exception handlers for tracing and breakpoints */ 390 391void 392set_debug_traps(void) 393{ 394 struct hard_trap_info *ht; 395 unsigned long flags; 396 397 local_irq_save(flags); 398 399 /* Initialize our copy of the Linux Sparc trap table */ 400 eh_init(); 401 402 for (ht = hard_trap_info; ht->tt && ht->signo; ht++) { 403 /* Only if it doesn't destroy our fault handlers */ 404 if((ht->tt != SP_TRAP_TFLT) && 405 (ht->tt != SP_TRAP_DFLT)) 406 exceptionHandler(ht->tt, trap_low); 407 } 408 409 /* In case GDB is started before us, ack any packets (presumably 410 * "$?#xx") sitting there. 411 * 412 * I've found this code causes more problems than it solves, 413 * so that's why it's commented out. GDB seems to work fine 414 * now starting either before or after the kernel -bwb 415 */ 416 417 initialized = 1; /* connect! */ 418 local_irq_restore(flags); 419} 420 421/* Convert the SPARC hardware trap type code to a unix signal number. */ 422 423static int 424computeSignal(int tt) 425{ 426 struct hard_trap_info *ht; 427 428 for (ht = hard_trap_info; ht->tt && ht->signo; ht++) 429 if (ht->tt == tt) 430 return ht->signo; 431 432 return SIGHUP; /* default for things we don't know about */ 433} 434 435/* 436 * While we find nice hex chars, build an int. 437 * Return number of chars processed. 438 */ 439 440static int 441hexToInt(char **ptr, int *intValue) 442{ 443 int numChars = 0; 444 int hexValue; 445 446 *intValue = 0; 447 448 while (**ptr) { 449 hexValue = hex(**ptr); 450 if (hexValue < 0) 451 break; 452 453 *intValue = (*intValue << 4) | hexValue; 454 numChars ++; 455 456 (*ptr)++; 457 } 458 459 return (numChars); 460} 461 462/* 463 * This function does all command processing for interfacing to gdb. It 464 * returns 1 if you should skip the instruction at the trap address, 0 465 * otherwise. 466 */ 467 468extern void breakinst(void); 469 470void 471handle_exception (unsigned long *registers) 472{ 473 int tt; /* Trap type */ 474 int sigval; 475 int addr; 476 int length; 477 char *ptr; 478 unsigned long *sp; 479 480 /* First, we must force all of the windows to be spilled out */ 481 482 asm("save %sp, -64, %sp\n\t" 483 "save %sp, -64, %sp\n\t" 484 "save %sp, -64, %sp\n\t" 485 "save %sp, -64, %sp\n\t" 486 "save %sp, -64, %sp\n\t" 487 "save %sp, -64, %sp\n\t" 488 "save %sp, -64, %sp\n\t" 489 "save %sp, -64, %sp\n\t" 490 "restore\n\t" 491 "restore\n\t" 492 "restore\n\t" 493 "restore\n\t" 494 "restore\n\t" 495 "restore\n\t" 496 "restore\n\t" 497 "restore\n\t"); 498 499 lock_kernel(); 500 if (registers[PC] == (unsigned long)breakinst) { 501 /* Skip over breakpoint trap insn */ 502 registers[PC] = registers[NPC]; 503 registers[NPC] += 4; 504 } 505 506 sp = (unsigned long *)registers[SP]; 507 508 tt = (registers[TBR] >> 4) & 0xff; 509 510 /* reply to host that an exception has occurred */ 511 sigval = computeSignal(tt); 512 ptr = remcomOutBuffer; 513 514 *ptr++ = 'T'; 515 *ptr++ = hexchars[sigval >> 4]; 516 *ptr++ = hexchars[sigval & 0xf]; 517 518 *ptr++ = hexchars[PC >> 4]; 519 *ptr++ = hexchars[PC & 0xf]; 520 *ptr++ = ':'; 521 ptr = mem2hex((char *)®isters[PC], ptr, 4); 522 *ptr++ = ';'; 523 524 *ptr++ = hexchars[FP >> 4]; 525 *ptr++ = hexchars[FP & 0xf]; 526 *ptr++ = ':'; 527 ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */ 528 *ptr++ = ';'; 529 530 *ptr++ = hexchars[SP >> 4]; 531 *ptr++ = hexchars[SP & 0xf]; 532 *ptr++ = ':'; 533 ptr = mem2hex((char *)&sp, ptr, 4); 534 *ptr++ = ';'; 535 536 *ptr++ = hexchars[NPC >> 4]; 537 *ptr++ = hexchars[NPC & 0xf]; 538 *ptr++ = ':'; 539 ptr = mem2hex((char *)®isters[NPC], ptr, 4); 540 *ptr++ = ';'; 541 542 *ptr++ = hexchars[O7 >> 4]; 543 *ptr++ = hexchars[O7 & 0xf]; 544 *ptr++ = ':'; 545 ptr = mem2hex((char *)®isters[O7], ptr, 4); 546 *ptr++ = ';'; 547 548 *ptr++ = 0; 549 550 putpacket(remcomOutBuffer); 551 552 553 while (1) { 554 remcomOutBuffer[0] = 0; 555 556 getpacket(remcomInBuffer); 557 switch (remcomInBuffer[0]) { 558 case '?': 559 remcomOutBuffer[0] = 'S'; 560 remcomOutBuffer[1] = hexchars[sigval >> 4]; 561 remcomOutBuffer[2] = hexchars[sigval & 0xf]; 562 remcomOutBuffer[3] = 0; 563 break; 564 565 case 'd': 566 /* toggle debug flag */ 567 break; 568 569 case 'g': /* return the value of the CPU registers */ 570 { 571 ptr = remcomOutBuffer; 572 /* G & O regs */ 573 ptr = mem2hex((char *)registers, ptr, 16 * 4); 574 /* L & I regs */ 575 ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4); 576 /* Floating point */ 577 memset(ptr, '0', 32 * 8); 578 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ 579 mem2hex((char *)®isters[Y], (ptr + 32 * 4 * 2), (8 * 4)); 580 } 581 break; 582 583 case 'G': /* set the value of the CPU registers - return OK */ 584 { 585 unsigned long *newsp, psr; 586 587 psr = registers[PSR]; 588 589 ptr = &remcomInBuffer[1]; 590 /* G & O regs */ 591 hex2mem(ptr, (char *)registers, 16 * 4); 592 /* L & I regs */ 593 hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4); 594 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ 595 hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], 8 * 4); 596 597 /* See if the stack pointer has moved. If so, 598 * then copy the saved locals and ins to the 599 * new location. This keeps the window 600 * overflow and underflow routines happy. 601 */ 602 603 newsp = (unsigned long *)registers[SP]; 604 if (sp != newsp) 605 sp = memcpy(newsp, sp, 16 * 4); 606 607 /* Don't allow CWP to be modified. */ 608 609 if (psr != registers[PSR]) 610 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f); 611 612 strcpy(remcomOutBuffer,"OK"); 613 } 614 break; 615 616 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 617 /* Try to read %x,%x. */ 618 619 ptr = &remcomInBuffer[1]; 620 621 if (hexToInt(&ptr, &addr) 622 && *ptr++ == ',' 623 && hexToInt(&ptr, &length)) { 624 if (mem2hex((char *)addr, remcomOutBuffer, length)) 625 break; 626 627 strcpy (remcomOutBuffer, "E03"); 628 } else { 629 strcpy(remcomOutBuffer,"E01"); 630 } 631 break; 632 633 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 634 /* Try to read '%x,%x:'. */ 635 636 ptr = &remcomInBuffer[1]; 637 638 if (hexToInt(&ptr, &addr) 639 && *ptr++ == ',' 640 && hexToInt(&ptr, &length) 641 && *ptr++ == ':') { 642 if (hex2mem(ptr, (char *)addr, length)) { 643 strcpy(remcomOutBuffer, "OK"); 644 } else { 645 strcpy(remcomOutBuffer, "E03"); 646 } 647 } else { 648 strcpy(remcomOutBuffer, "E02"); 649 } 650 break; 651 652 case 'c': /* cAA..AA Continue at address AA..AA(optional) */ 653 /* try to read optional parameter, pc unchanged if no parm */ 654 655 ptr = &remcomInBuffer[1]; 656 if (hexToInt(&ptr, &addr)) { 657 registers[PC] = addr; 658 registers[NPC] = addr + 4; 659 } 660 661/* Need to flush the instruction cache here, as we may have deposited a 662 * breakpoint, and the icache probably has no way of knowing that a data ref to 663 * some location may have changed something that is in the instruction cache. 664 */ 665 flush_cache_all(); 666 unlock_kernel(); 667 return; 668 669 /* kill the program */ 670 case 'k' : /* do nothing */ 671 break; 672 case 'r': /* Reset */ 673 asm ("call 0\n\t" 674 "nop\n\t"); 675 break; 676 } /* switch */ 677 678 /* reply to the request */ 679 putpacket(remcomOutBuffer); 680 } /* while(1) */ 681} 682 683/* This function will generate a breakpoint exception. It is used at the 684 beginning of a program to sync up with a debugger and can be used 685 otherwise as a quick means to stop program execution and "break" into 686 the debugger. */ 687 688void 689breakpoint(void) 690{ 691 if (!initialized) 692 return; 693 694 /* Again, watch those c-prefixes for ELF kernels */ 695#if defined(__svr4__) || defined(__ELF__) 696 asm(".globl breakinst\n" 697 "breakinst:\n\t" 698 "ta 1\n"); 699#else 700 asm(".globl _breakinst\n" 701 "_breakinst:\n\t" 702 "ta 1\n"); 703#endif 704} 705