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