PageRenderTime 54ms CodeModel.GetById 14ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/sparc/kernel/sparc-stub.c

https://bitbucket.org/evzijst/gittest
C | 724 lines | 423 code | 112 blank | 189 comment | 68 complexity | a09a6c86b466720ff16168d941b29fbe MD5 | raw file
  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}