linux/arch/sparc/kernel/sparc-stub.c
<<
>>
Prefs
   1/* $Id: sparc-stub.c,v 1.28 2001/10/30 04:54:21 davem 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 glenne 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#if 0
 171/* Have to sort this out. This cannot be done after initialization. */
 172static void flush_cache_all_nop(void) {}
 173#endif
 174
 175/* Place where we save old trap entries for restoration */
 176struct tt_entry kgdb_savettable[256];
 177typedef void (*trapfunc_t)(void);
 178
 179/* Helper routine for manipulation of kgdb_savettable */
 180static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest)
 181{
 182        dest->inst_one = src->inst_one;
 183        dest->inst_two = src->inst_two;
 184        dest->inst_three = src->inst_three;
 185        dest->inst_four = src->inst_four;
 186}
 187
 188/* Initialize the kgdb_savettable so that debugging can commence */
 189static void eh_init(void)
 190{
 191        int i;
 192
 193        for(i=0; i < 256; i++)
 194                copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]);
 195}
 196
 197/* Install an exception handler for kgdb */
 198static void exceptionHandler(int tnum, trapfunc_t trap_entry)
 199{
 200        unsigned long te_addr = (unsigned long) trap_entry;
 201
 202        /* Make new vector */
 203        sparc_ttable[tnum].inst_one =
 204                SPARC_BRANCH((unsigned long) te_addr,
 205                             (unsigned long) &sparc_ttable[tnum].inst_one);
 206        sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0;
 207        sparc_ttable[tnum].inst_three = SPARC_NOP;
 208        sparc_ttable[tnum].inst_four = SPARC_NOP;
 209}
 210
 211/* Convert ch from a hex digit to an int */
 212static int
 213hex(unsigned char ch)
 214{
 215        if (ch >= 'a' && ch <= 'f')
 216                return ch-'a'+10;
 217        if (ch >= '0' && ch <= '9')
 218                return ch-'0';
 219        if (ch >= 'A' && ch <= 'F')
 220                return ch-'A'+10;
 221        return -1;
 222}
 223
 224/* scan for the sequence $<data>#<checksum>     */
 225static void
 226getpacket(char *buffer)
 227{
 228        unsigned char checksum;
 229        unsigned char xmitcsum;
 230        int i;
 231        int count;
 232        unsigned char ch;
 233
 234        do {
 235                /* wait around for the start character, ignore all other characters */
 236                while ((ch = (getDebugChar() & 0x7f)) != '$') ;
 237
 238                checksum = 0;
 239                xmitcsum = -1;
 240
 241                count = 0;
 242
 243                /* now, read until a # or end of buffer is found */
 244                while (count < BUFMAX) {
 245                        ch = getDebugChar() & 0x7f;
 246                        if (ch == '#')
 247                                break;
 248                        checksum = checksum + ch;
 249                        buffer[count] = ch;
 250                        count = count + 1;
 251                }
 252
 253                if (count >= BUFMAX)
 254                        continue;
 255
 256                buffer[count] = 0;
 257
 258                if (ch == '#') {
 259                        xmitcsum = hex(getDebugChar() & 0x7f) << 4;
 260                        xmitcsum |= hex(getDebugChar() & 0x7f);
 261                        if (checksum != xmitcsum)
 262                                putDebugChar('-');      /* failed checksum */
 263                        else {
 264                                putDebugChar('+'); /* successful transfer */
 265                                /* if a sequence char is present, reply the ID */
 266                                if (buffer[2] == ':') {
 267                                        putDebugChar(buffer[0]);
 268                                        putDebugChar(buffer[1]);
 269                                        /* remove sequence chars from buffer */
 270                                        count = strlen(buffer);
 271                                        for (i=3; i <= count; i++)
 272                                                buffer[i-3] = buffer[i];
 273                                }
 274                        }
 275                }
 276        } while (checksum != xmitcsum);
 277}
 278
 279/* send the packet in buffer.  */
 280
 281static void
 282putpacket(unsigned char *buffer)
 283{
 284        unsigned char checksum;
 285        int count;
 286        unsigned char ch, recv;
 287
 288        /*  $<packet info>#<checksum>. */
 289        do {
 290                putDebugChar('$');
 291                checksum = 0;
 292                count = 0;
 293
 294                while ((ch = buffer[count])) {
 295                        putDebugChar(ch);
 296                        checksum += ch;
 297                        count += 1;
 298                }
 299
 300                putDebugChar('#');
 301                putDebugChar(hexchars[checksum >> 4]);
 302                putDebugChar(hexchars[checksum & 0xf]);
 303                recv = getDebugChar();
 304        } while ((recv & 0x7f) != '+');
 305}
 306
 307static char remcomInBuffer[BUFMAX];
 308static char remcomOutBuffer[BUFMAX];
 309
 310/* Convert the memory pointed to by mem into hex, placing result in buf.
 311 * Return a pointer to the last char put in buf (null), in case of mem fault,
 312 * return 0.
 313 */
 314
 315static unsigned char *
 316mem2hex(char *mem, char *buf, int count)
 317{
 318        unsigned char ch;
 319
 320        while (count-- > 0) {
 321                /* This assembler code is basically:  ch = *mem++;
 322                 * except that we use the SPARC/Linux exception table
 323                 * mechanism (see how "fixup" works in kernel_mna_trap_fault)
 324                 * to arrange for a "return 0" upon a memory fault
 325                 */
 326                __asm__(
 327                        "\n1:\n\t"
 328                        "ldub [%0], %1\n\t"
 329                        "inc %0\n\t"
 330                        ".section .fixup,#alloc,#execinstr\n\t"
 331                        ".align 4\n"
 332                        "2:\n\t"
 333                        "retl\n\t"
 334                        " mov 0, %%o0\n\t"
 335                        ".section __ex_table, #alloc\n\t"
 336                        ".align 4\n\t"
 337                        ".word 1b, 2b\n\t"
 338                        ".text\n"
 339                        : "=r" (mem), "=r" (ch) : "0" (mem));
 340                *buf++ = hexchars[ch >> 4];
 341                *buf++ = hexchars[ch & 0xf];
 342        }
 343
 344        *buf = 0;
 345        return buf;
 346}
 347
 348/* convert the hex array pointed to by buf into binary to be placed in mem
 349 * return a pointer to the character AFTER the last byte written.
 350*/
 351static char *
 352hex2mem(char *buf, char *mem, int count)
 353{
 354        int i;
 355        unsigned char ch;
 356
 357        for (i=0; i<count; i++) {
 358
 359                ch = hex(*buf++) << 4;
 360                ch |= hex(*buf++);
 361                /* Assembler code is   *mem++ = ch;   with return 0 on fault */
 362                __asm__(
 363                        "\n1:\n\t"
 364                        "stb %1, [%0]\n\t"
 365                        "inc %0\n\t"
 366                        ".section .fixup,#alloc,#execinstr\n\t"
 367                        ".align 4\n"
 368                        "2:\n\t"
 369                        "retl\n\t"
 370                        " mov 0, %%o0\n\t"
 371                        ".section __ex_table, #alloc\n\t"
 372                        ".align 4\n\t"
 373                        ".word 1b, 2b\n\t"
 374                        ".text\n"
 375                        : "=r" (mem) : "r" (ch) , "0" (mem));
 376        }
 377        return mem;
 378}
 379
 380/* This table contains the mapping between SPARC hardware trap types, and
 381   signals, which are primarily what GDB understands.  It also indicates
 382   which hardware traps we need to commandeer when initializing the stub. */
 383
 384static struct hard_trap_info
 385{
 386  unsigned char tt;             /* Trap type code for SPARC */
 387  unsigned char signo;          /* Signal that we map this trap into */
 388} hard_trap_info[] = {
 389  {SP_TRAP_SBPT, SIGTRAP},      /* ta 1 - Linux/KGDB software breakpoint */
 390  {0, 0}                        /* Must be last */
 391};
 392
 393/* Set up exception handlers for tracing and breakpoints */
 394
 395void
 396set_debug_traps(void)
 397{
 398        struct hard_trap_info *ht;
 399        unsigned long flags;
 400
 401        local_irq_save(flags);
 402#if 0   
 403/* Have to sort this out. This cannot be done after initialization. */
 404        BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
 405#endif
 406
 407        /* Initialize our copy of the Linux Sparc trap table */
 408        eh_init();
 409
 410        for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
 411                /* Only if it doesn't destroy our fault handlers */
 412                if((ht->tt != SP_TRAP_TFLT) && 
 413                   (ht->tt != SP_TRAP_DFLT))
 414                        exceptionHandler(ht->tt, trap_low);
 415        }
 416
 417        /* In case GDB is started before us, ack any packets (presumably
 418         * "$?#xx") sitting there.
 419         *
 420         * I've found this code causes more problems than it solves,
 421         * so that's why it's commented out.  GDB seems to work fine
 422         * now starting either before or after the kernel   -bwb
 423         */
 424#if 0
 425        while((c = getDebugChar()) != '$');
 426        while((c = getDebugChar()) != '#');
 427        c = getDebugChar(); /* eat first csum byte */
 428        c = getDebugChar(); /* eat second csum byte */
 429        putDebugChar('+'); /* ack it */
 430#endif
 431
 432        initialized = 1; /* connect! */
 433        local_irq_restore(flags);
 434}
 435
 436/* Convert the SPARC hardware trap type code to a unix signal number. */
 437
 438static int
 439computeSignal(int tt)
 440{
 441        struct hard_trap_info *ht;
 442
 443        for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
 444                if (ht->tt == tt)
 445                        return ht->signo;
 446
 447        return SIGHUP;         /* default for things we don't know about */
 448}
 449
 450/*
 451 * While we find nice hex chars, build an int.
 452 * Return number of chars processed.
 453 */
 454
 455static int
 456hexToInt(char **ptr, int *intValue)
 457{
 458        int numChars = 0;
 459        int hexValue;
 460
 461        *intValue = 0;
 462
 463        while (**ptr) {
 464                hexValue = hex(**ptr);
 465                if (hexValue < 0)
 466                        break;
 467
 468                *intValue = (*intValue << 4) | hexValue;
 469                numChars ++;
 470
 471                (*ptr)++;
 472        }
 473
 474        return (numChars);
 475}
 476
 477/*
 478 * This function does all command processing for interfacing to gdb.  It
 479 * returns 1 if you should skip the instruction at the trap address, 0
 480 * otherwise.
 481 */
 482
 483extern void breakinst(void);
 484
 485void
 486handle_exception (unsigned long *registers)
 487{
 488        int tt;       /* Trap type */
 489        int sigval;
 490        int addr;
 491        int length;
 492        char *ptr;
 493        unsigned long *sp;
 494
 495        /* First, we must force all of the windows to be spilled out */
 496
 497        asm("save %sp, -64, %sp\n\t"
 498            "save %sp, -64, %sp\n\t"
 499            "save %sp, -64, %sp\n\t"
 500            "save %sp, -64, %sp\n\t"
 501            "save %sp, -64, %sp\n\t"
 502            "save %sp, -64, %sp\n\t"
 503            "save %sp, -64, %sp\n\t"
 504            "save %sp, -64, %sp\n\t"
 505            "restore\n\t"
 506            "restore\n\t"
 507            "restore\n\t"
 508            "restore\n\t"
 509            "restore\n\t"
 510            "restore\n\t"
 511            "restore\n\t"
 512            "restore\n\t");
 513
 514        lock_kernel();
 515        if (registers[PC] == (unsigned long)breakinst) {
 516                /* Skip over breakpoint trap insn */
 517                registers[PC] = registers[NPC];
 518                registers[NPC] += 4;
 519        }
 520
 521        sp = (unsigned long *)registers[SP];
 522
 523        tt = (registers[TBR] >> 4) & 0xff;
 524
 525        /* reply to host that an exception has occurred */
 526        sigval = computeSignal(tt);
 527        ptr = remcomOutBuffer;
 528
 529        *ptr++ = 'T';
 530        *ptr++ = hexchars[sigval >> 4];
 531        *ptr++ = hexchars[sigval & 0xf];
 532
 533        *ptr++ = hexchars[PC >> 4];
 534        *ptr++ = hexchars[PC & 0xf];
 535        *ptr++ = ':';
 536        ptr = mem2hex((char *)&registers[PC], ptr, 4);
 537        *ptr++ = ';';
 538
 539        *ptr++ = hexchars[FP >> 4];
 540        *ptr++ = hexchars[FP & 0xf];
 541        *ptr++ = ':';
 542        ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */
 543        *ptr++ = ';';
 544
 545        *ptr++ = hexchars[SP >> 4];
 546        *ptr++ = hexchars[SP & 0xf];
 547        *ptr++ = ':';
 548        ptr = mem2hex((char *)&sp, ptr, 4);
 549        *ptr++ = ';';
 550
 551        *ptr++ = hexchars[NPC >> 4];
 552        *ptr++ = hexchars[NPC & 0xf];
 553        *ptr++ = ':';
 554        ptr = mem2hex((char *)&registers[NPC], ptr, 4);
 555        *ptr++ = ';';
 556
 557        *ptr++ = hexchars[O7 >> 4];
 558        *ptr++ = hexchars[O7 & 0xf];
 559        *ptr++ = ':';
 560        ptr = mem2hex((char *)&registers[O7], ptr, 4);
 561        *ptr++ = ';';
 562
 563        *ptr++ = 0;
 564
 565        putpacket(remcomOutBuffer);
 566
 567        /* XXX We may want to add some features dealing with poking the
 568         * XXX page tables, the real ones on the srmmu, and what is currently
 569         * XXX loaded in the sun4/sun4c tlb at this point in time.  But this
 570         * XXX also required hacking to the gdb sources directly...
 571         */
 572
 573        while (1) {
 574                remcomOutBuffer[0] = 0;
 575
 576                getpacket(remcomInBuffer);
 577                switch (remcomInBuffer[0]) {
 578                case '?':
 579                        remcomOutBuffer[0] = 'S';
 580                        remcomOutBuffer[1] = hexchars[sigval >> 4];
 581                        remcomOutBuffer[2] = hexchars[sigval & 0xf];
 582                        remcomOutBuffer[3] = 0;
 583                        break;
 584
 585                case 'd':
 586                        /* toggle debug flag */
 587                        break;
 588
 589                case 'g':               /* return the value of the CPU registers */
 590                {
 591                        ptr = remcomOutBuffer;
 592                        /* G & O regs */
 593                        ptr = mem2hex((char *)registers, ptr, 16 * 4);
 594                        /* L & I regs */
 595                        ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4);
 596                        /* Floating point */
 597                        memset(ptr, '0', 32 * 8);
 598                        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
 599                        mem2hex((char *)&registers[Y], (ptr + 32 * 4 * 2), (8 * 4));
 600                }
 601                        break;
 602
 603                case 'G':          /* set the value of the CPU registers - return OK */
 604                {
 605                        unsigned long *newsp, psr;
 606
 607                        psr = registers[PSR];
 608
 609                        ptr = &remcomInBuffer[1];
 610                        /* G & O regs */
 611                        hex2mem(ptr, (char *)registers, 16 * 4);
 612                        /* L & I regs */
 613                        hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4);
 614                        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
 615                        hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y], 8 * 4);
 616
 617                        /* See if the stack pointer has moved.  If so,
 618                         * then copy the saved locals and ins to the
 619                         * new location.  This keeps the window
 620                         * overflow and underflow routines happy.
 621                         */
 622
 623                        newsp = (unsigned long *)registers[SP];
 624                        if (sp != newsp)
 625                                sp = memcpy(newsp, sp, 16 * 4);
 626
 627                        /* Don't allow CWP to be modified. */
 628
 629                        if (psr != registers[PSR])
 630                                registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
 631
 632                        strcpy(remcomOutBuffer,"OK");
 633                }
 634                        break;
 635
 636                case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
 637                        /* Try to read %x,%x.  */
 638
 639                        ptr = &remcomInBuffer[1];
 640
 641                        if (hexToInt(&ptr, &addr)
 642                            && *ptr++ == ','
 643                            && hexToInt(&ptr, &length)) {
 644                                if (mem2hex((char *)addr, remcomOutBuffer, length))
 645                                        break;
 646
 647                                strcpy (remcomOutBuffer, "E03");
 648                        } else {
 649                                strcpy(remcomOutBuffer,"E01");
 650                        }
 651                        break;
 652
 653                case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
 654                        /* Try to read '%x,%x:'.  */
 655
 656                        ptr = &remcomInBuffer[1];
 657
 658                        if (hexToInt(&ptr, &addr)
 659                            && *ptr++ == ','
 660                            && hexToInt(&ptr, &length)
 661                            && *ptr++ == ':') {
 662                                if (hex2mem(ptr, (char *)addr, length)) {
 663                                        strcpy(remcomOutBuffer, "OK");
 664                                } else {
 665                                        strcpy(remcomOutBuffer, "E03");
 666                                }
 667                        } else {
 668                                strcpy(remcomOutBuffer, "E02");
 669                        }
 670                        break;
 671
 672                case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
 673                        /* try to read optional parameter, pc unchanged if no parm */
 674
 675                        ptr = &remcomInBuffer[1];
 676                        if (hexToInt(&ptr, &addr)) {
 677                                registers[PC] = addr;
 678                                registers[NPC] = addr + 4;
 679                        }
 680
 681/* Need to flush the instruction cache here, as we may have deposited a
 682 * breakpoint, and the icache probably has no way of knowing that a data ref to
 683 * some location may have changed something that is in the instruction cache.
 684 */
 685                        flush_cache_all();
 686                        unlock_kernel();
 687                        return;
 688
 689                        /* kill the program */
 690                case 'k' :              /* do nothing */
 691                        break;
 692                case 'r':               /* Reset */
 693                        asm ("call 0\n\t"
 694                             "nop\n\t");
 695                        break;
 696                }                       /* switch */
 697
 698                /* reply to the request */
 699                putpacket(remcomOutBuffer);
 700        } /* while(1) */
 701}
 702
 703/* This function will generate a breakpoint exception.  It is used at the
 704   beginning of a program to sync up with a debugger and can be used
 705   otherwise as a quick means to stop program execution and "break" into
 706   the debugger. */
 707
 708void
 709breakpoint(void)
 710{
 711        if (!initialized)
 712                return;
 713
 714        /* Again, watch those c-prefixes for ELF kernels */
 715#if defined(__svr4__) || defined(__ELF__)
 716        asm(".globl breakinst\n"
 717            "breakinst:\n\t"
 718            "ta 1\n");
 719#else
 720        asm(".globl _breakinst\n"
 721            "_breakinst:\n\t"
 722            "ta 1\n");
 723#endif
 724}
 725