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