update atp870u driver to 0.78 from D-Link source
[linux-2.4.git] / arch / s390x / kernel / gdb-stub.c
1 /*
2  *  arch/s390/kernel/gdb-stub.c
3  *
4  *  S390 version
5  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
7  *
8  *  Originally written by Glenn Engel, Lake Stevens Instrument Division
9  *
10  *  Contributed by HP Systems
11  *
12  *  Modified for SPARC by Stu Grossman, Cygnus Support.
13  *
14  *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
15  *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
16  *
17  *  Copyright (C) 1995 Andreas Busse
18  */
19
20 /*
21  *  To enable debugger support, two things need to happen.  One, a
22  *  call to set_debug_traps() is necessary in order to allow any breakpoints
23  *  or error conditions to be properly intercepted and reported to gdb.
24  *  Two, a breakpoint needs to be generated to begin communication.  This
25  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
26  *  simulates a breakpoint by executing a BREAK instruction.
27  *
28  *
29  *    The following gdb commands are supported:
30  *
31  * command          function                               Return value
32  *
33  *    g             return the value of the CPU registers  hex data or ENN
34  *    G             set the value of the CPU registers     OK or ENN
35  *
36  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
37  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
38  *
39  *    c             Resume at current address              SNN   ( signal NN)
40  *    cAA..AA       Continue at address AA..AA             SNN
41  *
42  *    s             Step one instruction                   SNN
43  *    sAA..AA       Step one instruction from AA..AA       SNN
44  *
45  *    k             kill
46  *
47  *    ?             What was the last sigval ?             SNN   (signal NN)
48  *
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 #include <asm/gdb-stub.h>
70 #include <linux/string.h>
71 #include <linux/kernel.h>
72 #include <linux/signal.h>
73 #include <linux/sched.h>
74 #include <linux/mm.h>
75 #include <asm/pgtable.h>
76 #include <asm/system.h>
77
78
79 /*
80  * external low-level support routines
81  */
82
83 extern int putDebugChar(char c);    /* write a single character      */
84 extern char getDebugChar(void);     /* read and return a single char */
85 extern void fltr_set_mem_err(void);
86 extern void trap_low(void);
87
88 /*
89  * breakpoint and test functions
90  */
91 extern void breakpoint(void);
92 extern void breakinst(void);
93
94 /*
95  * local prototypes
96  */
97
98 static void getpacket(char *buffer);
99 static void putpacket(char *buffer);
100 static int hex(unsigned char ch);
101 static int hexToInt(char **ptr, int *intValue);
102 static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
103
104
105 /*
106  * BUFMAX defines the maximum number of characters in inbound/outbound buffers
107  * at least NUMREGBYTES*2 are needed for register packets
108  */
109 #define BUFMAX 2048
110
111 static char input_buffer[BUFMAX];
112 static char output_buffer[BUFMAX];
113 int gdb_stub_initialised = FALSE;       
114 static const char hexchars[]="0123456789abcdef";
115
116
117 /*
118  * Convert ch from a hex digit to an int
119  */
120 static int hex(unsigned char ch)
121 {
122         if (ch >= 'a' && ch <= 'f')
123                 return ch-'a'+10;
124         if (ch >= '0' && ch <= '9')
125                 return ch-'0';
126         if (ch >= 'A' && ch <= 'F')
127                 return ch-'A'+10;
128         return -1;
129 }
130
131 /*
132  * scan for the sequence $<data>#<checksum>
133  */
134 static void getpacket(char *buffer)
135 {
136         unsigned char checksum;
137         unsigned char xmitcsum;
138         int i;
139         int count;
140         unsigned char ch;
141
142         do {
143                 /*
144                  * wait around for the start character,
145                  * ignore all other characters
146                  */
147                 while ((ch = (getDebugChar() & 0x7f)) != '$') ;
148
149                 checksum = 0;
150                 xmitcsum = -1;
151                 count = 0;
152         
153                 /*
154                  * now, read until a # or end of buffer is found
155                  */
156                 while (count < BUFMAX) {
157                         ch = getDebugChar() & 0x7f;
158                         if (ch == '#')
159                                 break;
160                         checksum = checksum + ch;
161                         buffer[count] = ch;
162                         count = count + 1;
163                 }
164
165                 if (count >= BUFMAX)
166                         continue;
167
168                 buffer[count] = 0;
169
170                 if (ch == '#') {
171                         xmitcsum = hex(getDebugChar() & 0x7f) << 4;
172                         xmitcsum |= hex(getDebugChar() & 0x7f);
173
174                         if (checksum != xmitcsum)
175                                 putDebugChar('-');      /* failed checksum */
176                         else {
177                                 putDebugChar('+'); /* successful transfer */
178
179                                 /*
180                                  * if a sequence char is present,
181                                  * reply the sequence ID
182                                  */
183                                 if (buffer[2] == ':') {
184                                         putDebugChar(buffer[0]);
185                                         putDebugChar(buffer[1]);
186
187                                         /*
188                                          * remove sequence chars from buffer
189                                          */
190                                         count = strlen(buffer);
191                                         for (i=3; i <= count; i++)
192                                                 buffer[i-3] = buffer[i];
193                                 }
194                         }
195                 }
196         }
197         while (checksum != xmitcsum);
198 }
199
200 /*
201  * send the packet in buffer.
202  */
203 static void putpacket(char *buffer)
204 {
205         unsigned char checksum;
206         int count;
207         unsigned char ch;
208
209         /*
210          * $<packet info>#<checksum>.
211          */
212
213         do {
214                 putDebugChar('$');
215                 checksum = 0;
216                 count = 0;
217
218                 while ((ch = buffer[count]) != 0) {
219                         if (!(putDebugChar(ch)))
220                                 return;
221                         checksum += ch;
222                         count += 1;
223                 }
224
225                 putDebugChar('#');
226                 putDebugChar(hexchars[checksum >> 4]);
227                 putDebugChar(hexchars[checksum & 0xf]);
228
229         }
230         while ((getDebugChar() & 0x7f) != '+');
231 }
232
233
234
235 /*
236  * Convert the memory pointed to by mem into hex, placing result in buf.
237  * Return a pointer to the last char put in buf (null), in case of mem fault,
238  * return 0.
239  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
240  * a 0, else treat a fault like any other fault in the stub.
241  */
242 static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
243 {
244         unsigned char ch;
245
246 /*      set_mem_fault_trap(may_fault); */
247
248         while (count-- > 0) {
249                 ch = *(mem++);
250                 if (mem_err)
251                         return 0;
252                 *buf++ = hexchars[ch >> 4];
253                 *buf++ = hexchars[ch & 0xf];
254         }
255
256         *buf = 0;
257
258 /*      set_mem_fault_trap(0); */
259
260         return buf;
261 }
262
263 /*
264  * convert the hex array pointed to by buf into binary to be placed in mem
265  * return a pointer to the character AFTER the last byte written
266  */
267 static char *hex2mem(char *buf, char *mem, int count, int may_fault)
268 {
269         int i;
270         unsigned char ch;
271
272 /*      set_mem_fault_trap(may_fault); */
273
274         for (i=0; i<count; i++)
275         {
276                 ch = hex(*buf++) << 4;
277                 ch |= hex(*buf++);
278                 *(mem++) = ch;
279                 if (mem_err)
280                         return 0;
281         }
282
283 /*      set_mem_fault_trap(0); */
284
285         return mem;
286 }
287
288
289
290 /*
291  * Set up exception handlers for tracing and breakpoints
292  */
293 void set_debug_traps(void)
294 {
295 //      unsigned long flags;
296         unsigned char c;
297
298 //      save_and_cli(flags);
299         /*
300          * In case GDB is started before us, ack any packets
301          * (presumably "$?#xx") sitting there.
302          */
303         while((c = getDebugChar()) != '$');
304         while((c = getDebugChar()) != '#');
305         c = getDebugChar(); /* eat first csum byte */
306         c = getDebugChar(); /* eat second csum byte */
307         putDebugChar('+'); /* ack it */
308
309         gdb_stub_initialised = TRUE;
310 //      restore_flags(flags);
311 }
312
313
314 /*
315  * Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
316  * assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
317  * 0 would ever contain code that could mem fault.  This routine will skip
318  * past the faulting instruction after setting mem_err.
319  */
320 extern void fltr_set_mem_err(void)
321 {
322   /* FIXME: Needs to be written... */
323 }
324
325
326 /*
327  * While we find nice hex chars, build an int.
328  * Return number of chars processed.
329  */
330 static int hexToInt(char **ptr, int *intValue)
331 {
332         int numChars = 0;
333         int hexValue;
334
335         *intValue = 0;
336
337         while (**ptr)
338         {
339                 hexValue = hex(**ptr);
340                 if (hexValue < 0)
341                         break;
342
343                 *intValue = (*intValue << 4) | hexValue;
344                 numChars ++;
345
346                 (*ptr)++;
347         }
348
349         return (numChars);
350 }
351
352 void gdb_stub_get_non_pt_regs(gdb_pt_regs *regs)
353 {
354         s390_fp_regs *fpregs=&regs->fp_regs;
355         int has_ieee=save_fp_regs1(fpregs);
356
357         if(!has_ieee)
358         {
359                 fpregs->fpc=0;
360                 fpregs->fprs[1].d=
361                 fpregs->fprs[3].d=
362                 fpregs->fprs[5].d=
363                 fpregs->fprs[7].d=0;
364                 memset(&fpregs->fprs[8].d,0,sizeof(freg_t)*8);
365         }
366 }
367
368 void gdb_stub_set_non_pt_regs(gdb_pt_regs *regs)
369 {
370         restore_fp_regs1(&regs->fp_regs);
371 }
372
373 void gdb_stub_send_signal(int sigval)
374 {
375         char *ptr;
376         ptr = output_buffer;
377
378         /*
379          * Send trap type (converted to signal)
380          */
381         *ptr++ = 'S';
382         *ptr++ = hexchars[sigval >> 4];
383         *ptr++ = hexchars[sigval & 0xf];
384         *ptr++ = 0;
385         putpacket(output_buffer);       /* send it off... */
386 }
387
388 /*
389  * This function does all command processing for interfacing to gdb.  It
390  * returns 1 if you should skip the instruction at the trap address, 0
391  * otherwise.
392  */
393 void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval)
394 {
395         int trap;                       /* Trap type */
396         int addr;
397         int length;
398         char *ptr;
399         unsigned long *stack;
400
401         
402         /*
403          * reply to host that an exception has occurred
404          */
405         send_signal(sigval);
406
407         /*
408          * Wait for input from remote GDB
409          */
410         while (1) {
411                 output_buffer[0] = 0;
412                 getpacket(input_buffer);
413
414                 switch (input_buffer[0])
415                 {
416                 case '?':
417                         send_signal(sigval);
418                         continue;
419
420                 case 'd':
421                         /* toggle debug flag */
422                         break;
423
424                 /*
425                  * Return the value of the CPU registers
426                  */
427                 case 'g':
428                         gdb_stub_get_non_pt_regs(regs);
429                         ptr = output_buffer;
430                         ptr=  mem2hex((char *)regs,ptr,sizeof(s390_regs_common),FALSE);
431                         ptr=  mem2hex((char *)&regs->crs[0],ptr,NUM_CRS*CR_SIZE,FALSE);
432                         ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs));
433                         break;
434           
435                 /*
436                  * set the value of the CPU registers - return OK
437                  * FIXME: Needs to be written
438                  */
439                 case 'G':
440                         ptr=input_buffer;
441                         hex2mem (ptr, (char *)regs,sizeof(s390_regs_common), FALSE);
442                         ptr+=sizeof(s390_regs_common)*2;
443                         hex2mem (ptr, (char *)regs->crs[0],NUM_CRS*CR_SIZE, FALSE);
444                         ptr+=NUM_CRS*CR_SIZE*2;
445                         hex2mem (ptr, (char *)regs->fp_regs,sizeof(s390_fp_regs), FALSE);
446                         gdb_stub_set_non_pt_regs(regs);
447                         strcpy(output_buffer,"OK");
448                 break;
449
450                 /*
451                  * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
452                  */
453                 case 'm':
454                         ptr = &input_buffer[1];
455
456                         if (hexToInt(&ptr, &addr)
457                                 && *ptr++ == ','
458                                 && hexToInt(&ptr, &length)) {
459                                 if (mem2hex((char *)addr, output_buffer, length, 1))
460                                         break;
461                                 strcpy (output_buffer, "E03");
462                         } else
463                                 strcpy(output_buffer,"E01");
464                         break;
465
466                 /*
467                  * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
468                  */
469                 case 'M': 
470                         ptr = &input_buffer[1];
471
472                         if (hexToInt(&ptr, &addr)
473                                 && *ptr++ == ','
474                                 && hexToInt(&ptr, &length)
475                                 && *ptr++ == ':') {
476                                 if (hex2mem(ptr, (char *)addr, length, 1))
477                                         strcpy(output_buffer, "OK");
478                                 else
479                                         strcpy(output_buffer, "E03");
480                         }
481                         else
482                                 strcpy(output_buffer, "E02");
483                         break;
484
485                 /*
486                  * cAA..AA    Continue at address AA..AA(optional)
487                  */
488                 case 'c':    
489                         /* try to read optional parameter, pc unchanged if no parm */
490
491                         ptr = &input_buffer[1];
492                         if (hexToInt(&ptr, &addr))
493                                 regs->cp0_epc = addr;
494           
495                         /*
496                          * Need to flush the instruction cache here, as we may
497                          * have deposited a breakpoint, and the icache probably
498                          * has no way of knowing that a data ref to some location
499                          * may have changed something that is in the instruction
500                          * cache.
501                          * NB: We flush both caches, just to be sure...
502                          */
503
504                         flush_cache_all();
505                         return;
506                         /* NOTREACHED */
507                         break;
508
509
510                 /*
511                  * kill the program
512                  */
513                 case 'k' :
514                         break;          /* do nothing */
515
516
517                 /*
518                  * Reset the whole machine (FIXME: system dependent)
519                  */
520                 case 'r':
521                         break;
522
523
524                 /*
525                  * Step to next instruction
526                  */
527                 case 's':
528                         /*
529                          * There is no single step insn in the MIPS ISA, so we
530                          * use breakpoints and continue, instead.
531                          */
532                         single_step(regs);
533                         flush_cache_all();
534                         return;
535                         /* NOTREACHED */
536
537                 }
538                 break;
539
540                 }                       /* switch */
541
542                 /*
543                  * reply to the request
544                  */
545
546                 putpacket(output_buffer);
547
548         } /* while */
549 }
550
551 /*
552  * This function will generate a breakpoint exception.  It is used at the
553  * beginning of a program to sync up with a debugger and can be used
554  * otherwise as a quick means to stop program execution and "break" into
555  * the debugger.
556  */
557 void breakpoint(void)
558 {
559         if (!gdb_stub_initialised)
560                 return;
561         __asm__ __volatile__(
562                         ".globl breakinst\n"
563                         "breakinst:\t.word   %0\n\t"
564                         :
565                         : "i" (S390_BREAKPOINT_U16)
566                                 :
567                                 );
568 }
569
570
571
572
573
574
575