source: trunk/libs/newlib/src/libgloss/sparc/sparclet-stub.c @ 684

Last change on this file since 684 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 30.0 KB
RevLine 
[444]1/****************************************************************************
2
3                THIS SOFTWARE IS NOT COPYRIGHTED
4
5   HP offers the following for use in the public domain.  HP makes no
6   warranty with regard to the software or it's performance and the
7   user accepts the software "AS IS" with all faults.
8
9   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13****************************************************************************/
14
15/****************************************************************************
16 *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 *  Module name: remcom.c $
19 *  Revision: 1.34 $
20 *  Date: 91/03/09 12:29:49 $
21 *  Contributor:     Lake Stevens Instrument Division$
22 *
23 *  Description:     low level support for gdb debugger. $
24 *
25 *  Considerations:  only works on target hardware $
26 *
27 *  Written by:      Glenn Engel $
28 *  ModuleState:     Experimental $
29 *
30 *  NOTES:           See Below $
31 *
32 *  Modified for SPARC by Stu Grossman, Cygnus Support.
33 *  Based on sparc-stub.c, it's modified for SPARClite Debug Unit hardware
34 *  breakpoint support to create sparclite-stub.c, by Kung Hsu, Cygnus Support.
35 *
36 *  This code has been extensively tested on the Fujitsu SPARClite demo board.
37 *
38 *  To enable debugger support, two things need to happen.  One, a
39 *  call to set_debug_traps() is necessary in order to allow any breakpoints
40 *  or error conditions to be properly intercepted and reported to gdb.
41 *  Two, a breakpoint needs to be generated to begin communication.  This
42 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
43 *  simulates a breakpoint by executing a trap #1.
44 *
45 *************
46 *
47 *    The following gdb commands are supported:
48 *
49 * command          function                               Return value
50 *
51 *    g             return the value of the CPU registers  hex data or ENN
52 *    G             set the value of the CPU registers     OK or ENN
53 *    P             set the value of a single CPU register OK or P01 (???)
54 *
55 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
56 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
57 *
58 *    c             Resume at current address              SNN   ( signal NN)
59 *    cAA..AA       Continue at address AA..AA             SNN
60 *
61 *    s             Step one instruction                   SNN
62 *    sAA..AA       Step one instruction from AA..AA       SNN
63 *
64 *    k             kill
65 *
66 *    ?             What was the last sigval ?             SNN   (signal NN)
67 *
68 *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
69 *                                                         baud rate
70 *
71 * All commands and responses are sent with a packet which includes a
72 * checksum.  A packet consists of
73 *
74 * $<packet info>#<checksum>.
75 *
76 * where
77 * <packet info> :: <characters representing the command or response>
78 * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
79 *
80 * When a packet is received, it is first acknowledged with either '+' or '-'.
81 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
82 *
83 * Example:
84 *
85 * Host:                  Reply:
86 * $m0,10#2a               +$00010203040506070809101112131415#42
87 *
88 ****************************************************************************/
89
90#include <string.h>
91#include <signal.h>
92
93/************************************************************************
94 *
95 * external low-level support routines
96 */
97
98extern putDebugChar();   /* write a single character      */
99extern getDebugChar();   /* read and return a single char */
100
101/************************************************************************/
102/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
103/* at least NUMREGBYTES*2 are needed for register packets */
104#define BUFMAX 2048
105
106static int initialized = 0;     /* !0 means we've been initialized */
107static int remote_debug = 0;    /* turn on verbose debugging */
108
109extern void breakinst();
110void _cprint();
111static void hw_breakpoint();
112static void set_mem_fault_trap();
113static void get_in_break_mode();
114static unsigned char *mem2hex();
115
116static const char hexchars[]="0123456789abcdef";
117
118#define NUMREGS 121
119
120static unsigned long saved_stack_pointer;
121
122/* Number of bytes of registers.  */
123#define NUMREGBYTES (NUMREGS * 4)
124enum regnames { G0, G1, G2, G3, G4, G5, G6, G7,
125                O0, O1, O2, O3, O4, O5, SP, O7,
126                L0, L1, L2, L3, L4, L5, L6, L7,
127                I0, I1, I2, I3, I4, I5, FP, I7,
128
129                F0, F1, F2, F3, F4, F5, F6, F7,
130                F8, F9, F10, F11, F12, F13, F14, F15,
131                F16, F17, F18, F19, F20, F21, F22, F23,
132                F24, F25, F26, F27, F28, F29, F30, F31,
133
134                Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
135                CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR, UNUSED1,
136
137                ASR1, ASR15, ASR17, ASR18, ASR19, ASR20, ASR21, ASR22, 
138                /* the following not actually implemented */
139                AWR0,  AWR1,  AWR2,  AWR3,  AWR4,  AWR5,  AWR6,  AWR7, 
140                AWR8,  AWR9,  AWR10, AWR11, AWR12, AWR13, AWR14, AWR15, 
141                AWR16, AWR17, AWR18, AWR19, AWR20, AWR21, AWR22, AWR23, 
142                AWR24, AWR25, AWR26, AWR27, AWR28, AWR29, AWR30, AWR31, 
143                APSR
144};
145
146/***************************  ASSEMBLY CODE MACROS *************************/
147/*                                                                         */
148
149extern void trap_low();
150
151asm("
152        .reserve trapstack, 1000 * 4, \"bss\", 8
153
154        .data
155        .align  4
156
157in_trap_handler:
158        .word   0
159
160        .text
161        .align 4
162
163! This function is called when any SPARC trap (except window overflow or
164! underflow) occurs.  It makes sure that the invalid register window is still
165! available before jumping into C code.  It will also restore the world if you
166! return from handle_exception.
167!
168! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
169
170        .globl _trap_low
171_trap_low:
172        mov     %psr, %l0
173        mov     %wim, %l3
174
175        srl     %l3, %l0, %l4           ! wim >> cwp
176        and     %l4, 0xff, %l4          ! Mask off windows 28, 29
177        cmp     %l4, 1
178        bne     window_fine             ! Branch if not in the invalid window
179        nop
180
181! Handle window overflow
182
183        mov     %g1, %l4                ! Save g1, we use it to hold the wim
184        srl     %l3, 1, %g1             ! Rotate wim right
185        and     %g1, 0xff, %g1          ! Mask off windows 28, 29
186        tst     %g1
187        bg      good_wim                ! Branch if new wim is non-zero
188        nop
189
190! At this point, we need to bring a 1 into the high order bit of the wim.
191! Since we don't want to make any assumptions about the number of register
192! windows, we figure it out dynamically so as to setup the wim correctly.
193
194        ! The normal way doesn't work on the sparclet as register windows
195        ! 28 and 29 are special purpose windows.
196        !not    %g1                     ! Fill g1 with ones
197        !mov    %g1, %wim               ! Fill the wim with ones
198        !nop
199        !nop
200        !nop
201        !mov    %wim, %g1               ! Read back the wim
202        !inc    %g1                     ! Now g1 has 1 just to left of wim
203        !srl    %g1, 1, %g1             ! Now put 1 at top of wim
204
205        mov     0x80, %g1               ! Hack for sparclet
206
207        ! This doesn't work on the sparclet.
208        !mov    %g0, %wim               ! Clear wim so that subsequent save
209                                        !  won't trap
210        andn    %l3, 0xff, %l5          ! Clear wim but not windows 28, 29
211        mov     %l5, %wim
212        nop
213        nop
214        nop
215
216good_wim:
217        save    %g0, %g0, %g0           ! Slip into next window
218        mov     %g1, %wim               ! Install the new wim
219
220        std     %l0, [%sp + 0 * 4]      ! save L & I registers
221        std     %l2, [%sp + 2 * 4]
222        std     %l4, [%sp + 4 * 4]
223        std     %l6, [%sp + 6 * 4]
224
225        std     %i0, [%sp + 8 * 4]
226        std     %i2, [%sp + 10 * 4]
227        std     %i4, [%sp + 12 * 4]
228        std     %i6, [%sp + 14 * 4]
229
230        restore                         ! Go back to trap window.
231        mov     %l4, %g1                ! Restore %g1
232
233window_fine:
234        sethi   %hi(in_trap_handler), %l4
235        ld      [%lo(in_trap_handler) + %l4], %l5
236        tst     %l5
237        bg      recursive_trap
238        inc     %l5
239
240        set     trapstack+1000*4, %sp   ! Switch to trap stack
241
242recursive_trap:
243        st      %l5, [%lo(in_trap_handler) + %l4]
244        sub     %sp,(16+1+6+1+88)*4,%sp ! Make room for input & locals
245                                        ! + hidden arg + arg spill
246                                        ! + doubleword alignment
247                                        ! + registers[121]
248
249        std     %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
250        std     %g2, [%sp + (24 + 2) * 4]
251        std     %g4, [%sp + (24 + 4) * 4]
252        std     %g6, [%sp + (24 + 6) * 4]
253
254        std     %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
255        std     %i2, [%sp + (24 + 10) * 4]
256        std     %i4, [%sp + (24 + 12) * 4]
257        std     %i6, [%sp + (24 + 14) * 4]
258
259        ! FP regs (sparclet doesn't have fpu)
260
261        mov     %y, %l4
262        mov     %tbr, %l5
263        st      %l4, [%sp + (24 + 64) * 4] ! Y
264        st      %l0, [%sp + (24 + 65) * 4] ! PSR
265        st      %l3, [%sp + (24 + 66) * 4] ! WIM
266        st      %l5, [%sp + (24 + 67) * 4] ! TBR
267        st      %l1, [%sp + (24 + 68) * 4] ! PC
268        st      %l2, [%sp + (24 + 69) * 4] ! NPC
269                                        ! CPSR and FPSR not impl
270        or      %l0, 0xf20, %l4
271        mov     %l4, %psr               ! Turn on traps, disable interrupts
272        nop
273        nop
274        nop
275
276! Save coprocessor state.
277! See SK/demo/hdlc_demo/ldc_swap_context.S.
278
279        mov     %psr, %l0
280        sethi   %hi(0x2000), %l5                ! EC bit in PSR
281        or      %l5, %l0, %l5
282        mov     %l5, %psr                       ! enable coprocessor
283        nop                     ! 3 nops after write to %psr (needed?)
284        nop
285        nop
286        crdcxt  %ccsr, %l1                      ! capture CCSR
287        mov     0x6, %l2
288        cwrcxt  %l2, %ccsr      ! set CCP state machine for CCFR
289        crdcxt  %ccfr, %l2                      ! capture CCOR
290        cwrcxt  %l2, %ccfr                      ! tickle  CCFR
291        crdcxt  %ccfr, %l3                      ! capture CCOBR
292        cwrcxt  %l3, %ccfr                      ! tickle  CCFR
293        crdcxt  %ccfr, %l4                      ! capture CCIBR
294        cwrcxt  %l4, %ccfr                      ! tickle  CCFR
295        crdcxt  %ccfr, %l5                      ! capture CCIR
296        cwrcxt  %l5, %ccfr                      ! tickle  CCFR
297        crdcxt  %ccpr, %l6                      ! capture CCPR
298        crdcxt  %cccrcr, %l7                    ! capture CCCRCR
299        st      %l1, [%sp + (24 + 72) * 4]      ! save CCSR
300        st      %l2, [%sp + (24 + 75) * 4]      ! save CCOR
301        st      %l3, [%sp + (24 + 76) * 4]      ! save CCOBR
302        st      %l4, [%sp + (24 + 77) * 4]      ! save CCIBR
303        st      %l5, [%sp + (24 + 78) * 4]      ! save CCIR
304        st      %l6, [%sp + (24 + 73) * 4]      ! save CCPR
305        st      %l7, [%sp + (24 + 74) * 4]      ! save CCCRCR
306        mov     %l0, %psr                       ! restore original PSR
307        nop                     ! 3 nops after write to %psr (needed?)
308        nop
309        nop
310
311! End of saving coprocessor state.
312! Save asr regs
313
314! Part of this is silly -- we should not display ASR15 or ASR19 at all.
315
316        sethi   %hi(0x01000000), %l6
317        st      %l6, [%sp + (24 + 81) * 4]      ! ASR15 == NOP
318        sethi   %hi(0xdeadc0de), %l6
319        or      %l6, %lo(0xdeadc0de), %l6
320        st      %l6, [%sp + (24 + 84) * 4]      ! ASR19 == DEADC0DE
321
322        rd      %asr1, %l4
323        st      %l4, [%sp + (24 + 80) * 4]
324!       rd      %asr15, %l4                     ! must not read ASR15
325!       st      %l4, [%sp + (24 + 81) * 4]      ! (illegal instr trap)
326        rd      %asr17, %l4
327        st      %l4, [%sp + (24 + 82) * 4]
328        rd      %asr18, %l4
329        st      %l4, [%sp + (24 + 83) * 4]
330!       rd      %asr19, %l4                     ! must not read asr19
331!       st      %l4, [%sp + (24 + 84) * 4]      ! (halts the CPU)
332        rd      %asr20, %l4
333        st      %l4, [%sp + (24 + 85) * 4]
334        rd      %asr21, %l4
335        st      %l4, [%sp + (24 + 86) * 4]
336        rd      %asr22, %l4
337        st      %l4, [%sp + (24 + 87) * 4]
338
339! End of saving asr regs
340
341        call    _handle_exception
342        add     %sp, 24 * 4, %o0        ! Pass address of registers
343
344! Reload all of the registers that aren't on the stack
345
346        ld      [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
347        ldd     [%sp + (24 + 2) * 4], %g2
348        ldd     [%sp + (24 + 4) * 4], %g4
349        ldd     [%sp + (24 + 6) * 4], %g6
350
351        ldd     [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
352        ldd     [%sp + (24 + 10) * 4], %i2
353        ldd     [%sp + (24 + 12) * 4], %i4
354        ldd     [%sp + (24 + 14) * 4], %i6
355
356        ! FP regs (sparclet doesn't have fpu)
357
358! Update the coprocessor registers.
359! See SK/demo/hdlc_demo/ldc_swap_context.S.
360
361        mov     %psr, %l0
362        sethi   %hi(0x2000), %l5                ! EC bit in PSR
363        or      %l5, %l0, %l5
364        mov     %l5, %psr                       ! enable coprocessor
365        nop                     ! 3 nops after write to %psr (needed?)
366        nop
367        nop
368
369        mov 0x6, %l2
370        cwrcxt  %l2, %ccsr      ! set CCP state machine for CCFR
371
372        ld      [%sp + (24 + 72) * 4], %l1      ! saved CCSR
373        ld      [%sp + (24 + 75) * 4], %l2      ! saved CCOR
374        ld      [%sp + (24 + 76) * 4], %l3      ! saved CCOBR
375        ld      [%sp + (24 + 77) * 4], %l4      ! saved CCIBR
376        ld      [%sp + (24 + 78) * 4], %l5      ! saved CCIR
377        ld      [%sp + (24 + 73) * 4], %l6      ! saved CCPR
378        ld      [%sp + (24 + 74) * 4], %l7      ! saved CCCRCR
379
380        cwrcxt  %l2, %ccfr                      ! restore CCOR
381        cwrcxt  %l3, %ccfr                      ! restore CCOBR
382        cwrcxt  %l4, %ccfr                      ! restore CCIBR
383        cwrcxt  %l5, %ccfr                      ! restore CCIR
384        cwrcxt  %l6, %ccpr                      ! restore CCPR
385        cwrcxt  %l7, %cccrcr                    ! restore CCCRCR
386        cwrcxt  %l1, %ccsr                      ! restore CCSR
387
388        mov %l0, %psr                           ! restore PSR
389        nop             ! 3 nops after write to %psr (needed?)
390        nop
391        nop
392
393! End of coprocessor handling stuff.
394! Update asr regs
395
396        ld      [%sp + (24 + 80) * 4], %l4
397        wr      %l4, %asr1
398!       ld      [%sp + (24 + 81) * 4], %l4      ! can't write asr15
399!       wr      %l4, %asr15
400        ld      [%sp + (24 + 82) * 4], %l4
401        wr      %l4, %asr17
402        ld      [%sp + (24 + 83) * 4], %l4
403        wr      %l4, %asr18
404!       ld      [%sp + (24 + 84) * 4], %l4      ! can't write asr19
405!       wr      %l4, %asr19
406!       ld      [%sp + (24 + 85) * 4], %l4      ! can't write asr20
407!       wr      %l4, %asr20
408!       ld      [%sp + (24 + 86) * 4], %l4      ! can't write asr21
409!       wr      %l4, %asr21
410        ld      [%sp + (24 + 87) * 4], %l4
411        wr      %l4, %asr22
412
413! End of restoring asr regs
414
415
416        ldd     [%sp + (24 + 64) * 4], %l0 ! Y & PSR
417        ldd     [%sp + (24 + 68) * 4], %l2 ! PC & NPC
418
419        restore                         ! Ensure that previous window is valid
420        save    %g0, %g0, %g0           !  by causing a window_underflow trap
421
422        mov     %l0, %y
423        mov     %l1, %psr               ! Make sure that traps are disabled
424                                        ! for rett
425        nop     ! 3 nops after write to %psr (needed?)
426        nop
427        nop
428
429        sethi   %hi(in_trap_handler), %l4
430        ld      [%lo(in_trap_handler) + %l4], %l5
431        dec     %l5
432        st      %l5, [%lo(in_trap_handler) + %l4]
433
434        jmpl    %l2, %g0                ! Restore old PC
435        rett    %l3                     ! Restore old nPC
436");
437
438/* Convert ch from a hex digit to an int */
439
440static int
441hex(ch)
442     unsigned char ch;
443{
444  if (ch >= 'a' && ch <= 'f')
445    return ch-'a'+10;
446  if (ch >= '0' && ch <= '9')
447    return ch-'0';
448  if (ch >= 'A' && ch <= 'F')
449    return ch-'A'+10;
450  return -1;
451}
452
453/* scan for the sequence $<data>#<checksum>     */
454
455static void
456getpacket(buffer)
457     char *buffer;
458{
459  unsigned char checksum;
460  unsigned char xmitcsum;
461  int i;
462  int count;
463  unsigned char ch;
464
465  do
466    {
467      /* wait around for the start character, ignore all other characters */
468      while ((ch = (getDebugChar() & 0x7f)) != '$') 
469        ;
470
471      checksum = 0;
472      xmitcsum = -1;
473
474      count = 0;
475
476      /* now, read until a # or end of buffer is found */
477      while (count < BUFMAX)
478        {
479          ch = getDebugChar() & 0x7f;
480          if (ch == '#')
481            break;
482          checksum = checksum + ch;
483          buffer[count] = ch;
484          count = count + 1;
485        }
486
487      if (count >= BUFMAX)
488        continue;
489
490      buffer[count] = 0;
491
492      if (ch == '#')
493        {
494          xmitcsum = hex(ch = getDebugChar() & 0x7f) << 4;
495          xmitcsum |= hex(ch = getDebugChar() & 0x7f);
496
497          if (checksum != xmitcsum)
498            putDebugChar('-');  /* failed checksum */
499          else
500            {
501              putDebugChar('+'); /* successful transfer */
502              /* if a sequence char is present, reply the sequence ID */
503              if (buffer[2] == ':')
504                {
505                  putDebugChar(buffer[0]);
506                  putDebugChar(buffer[1]);
507                  /* remove sequence chars from buffer */
508                  count = strlen(buffer);
509                  for (i=3; i <= count; i++)
510                    buffer[i-3] = buffer[i];
511                }
512            }
513        }
514    }
515  while (checksum != xmitcsum);
516}
517
518/* send the packet in buffer.  */
519
520static void
521putpacket(buffer)
522     unsigned char *buffer;
523{
524  unsigned char checksum;
525  int count;
526  unsigned char ch;
527
528  /*  $<packet info>#<checksum>. */
529  do
530    {
531      putDebugChar('$');
532      checksum = 0;
533      count = 0;
534
535      while (ch = buffer[count])
536        {
537          if (! putDebugChar(ch))
538            return;
539          checksum += ch;
540          count += 1;
541        }
542
543      putDebugChar('#');
544      putDebugChar(hexchars[checksum >> 4]);
545      putDebugChar(hexchars[checksum & 0xf]);
546
547    }
548  while ((getDebugChar() & 0x7f) != '+');
549}
550
551static char remcomInBuffer[BUFMAX];
552static char remcomOutBuffer[BUFMAX];
553
554/* Indicate to caller of mem2hex or hex2mem that there has been an
555   error.  */
556static volatile int mem_err = 0;
557
558/* Convert the memory pointed to by mem into hex, placing result in buf.
559 * Return a pointer to the last char put in buf (null), in case of mem fault,
560 * return 0.
561 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
562 * a 0, else treat a fault like any other fault in the stub.
563 */
564
565static unsigned char *
566mem2hex(mem, buf, count, may_fault)
567     unsigned char *mem;
568     unsigned char *buf;
569     int count;
570     int may_fault;
571{
572  unsigned char ch;
573
574  set_mem_fault_trap(may_fault);
575
576  while (count-- > 0)
577    {
578      ch = *mem++;
579      if (mem_err)
580        return 0;
581      *buf++ = hexchars[ch >> 4];
582      *buf++ = hexchars[ch & 0xf];
583    }
584
585  *buf = 0;
586
587  set_mem_fault_trap(0);
588
589  return buf;
590}
591
592/* convert the hex array pointed to by buf into binary to be placed in mem
593 * return a pointer to the character AFTER the last byte written */
594
595static char *
596hex2mem(buf, mem, count, may_fault)
597     unsigned char *buf;
598     unsigned char *mem;
599     int count;
600     int may_fault;
601{
602  int i;
603  unsigned char ch;
604
605  set_mem_fault_trap(may_fault);
606
607  for (i=0; i<count; i++)
608    {
609      ch = hex(*buf++) << 4;
610      ch |= hex(*buf++);
611      *mem++ = ch;
612      if (mem_err)
613        return 0;
614    }
615
616  set_mem_fault_trap(0);
617
618  return mem;
619}
620
621/* This table contains the mapping between SPARC hardware trap types, and
622   signals, which are primarily what GDB understands.  It also indicates
623   which hardware traps we need to commandeer when initializing the stub. */
624
625static struct hard_trap_info
626{
627  unsigned char tt;             /* Trap type code for SPARClite */
628  unsigned char signo;          /* Signal that we map this trap into */
629} hard_trap_info[] = {
630  {1, SIGSEGV},                 /* instruction access exception */
631  {0x3b, SIGSEGV},              /* instruction access error */
632  {2, SIGILL},                  /* illegal    instruction */
633  {3, SIGILL},                  /* privileged instruction */
634  {4, SIGEMT},                  /* fp disabled */
635  {0x24, SIGEMT},               /* cp disabled */
636  {7, SIGBUS},                  /* mem address not aligned */
637  {0x29, SIGSEGV},              /* data access exception */
638  {10, SIGEMT},                 /* tag overflow */
639  {128+1, SIGTRAP},             /* ta 1 - normal breakpoint instruction */
640  {0, 0}                        /* Must be last */
641};
642
643/* Set up exception handlers for tracing and breakpoints */
644
645void
646set_debug_traps()
647{
648  struct hard_trap_info *ht;
649
650  for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
651    exceptionHandler(ht->tt, trap_low);
652
653  /* In case GDB is started before us, ack any packets (presumably
654     "$?#xx") sitting there.  */
655  putDebugChar ('+');
656
657  initialized = 1;
658}
659
660asm ("
661! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
662! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
663! 0 would ever contain code that could mem fault.  This routine will skip
664! past the faulting instruction after setting mem_err.
665
666        .text
667        .align 4
668
669_fltr_set_mem_err:
670        sethi %hi(_mem_err), %l0
671        st %l1, [%l0 + %lo(_mem_err)]
672        jmpl %l2, %g0
673        rett %l2+4
674");
675
676static void
677set_mem_fault_trap(enable)
678     int enable;
679{
680  extern void fltr_set_mem_err();
681  mem_err = 0;
682
683  if (enable)
684    exceptionHandler(0x29, fltr_set_mem_err);
685  else
686    exceptionHandler(0x29, trap_low);
687}
688
689asm ("
690        .text
691        .align 4
692
693_dummy_hw_breakpoint:
694        jmpl %l2, %g0
695        rett %l2+4
696        nop
697        nop
698");
699
700static void
701set_hw_breakpoint_trap(enable)
702     int enable;
703{
704  extern void dummy_hw_breakpoint();
705
706  if (enable)
707    exceptionHandler(255, dummy_hw_breakpoint);
708  else
709    exceptionHandler(255, trap_low);
710}
711
712static void
713get_in_break_mode()
714{
715#if 0
716  int x;
717  mesg("get_in_break_mode, sp = ");
718  phex(&x);
719#endif
720  set_hw_breakpoint_trap(1);
721
722  asm("
723        sethi   %hi(0xff10), %l4
724        or      %l4, %lo(0xff10), %l4
725        sta     %g0, [%l4]0x1   
726        nop
727        nop
728        nop
729      ");
730
731  set_hw_breakpoint_trap(0);
732}
733
734/* Convert the SPARC hardware trap type code to a unix signal number. */
735
736static int
737computeSignal(tt)
738     int tt;
739{
740  struct hard_trap_info *ht;
741
742  for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
743    if (ht->tt == tt)
744      return ht->signo;
745
746  return SIGHUP;                /* default for things we don't know about */
747}
748
749/*
750 * While we find nice hex chars, build an int.
751 * Return number of chars processed.
752 */
753
754static int
755hexToInt(char **ptr, int *intValue)
756{
757  int numChars = 0;
758  int hexValue;
759
760  *intValue = 0;
761
762  while (**ptr)
763    {
764      hexValue = hex(**ptr);
765      if (hexValue < 0)
766        break;
767
768      *intValue = (*intValue << 4) | hexValue;
769      numChars ++;
770
771      (*ptr)++;
772    }
773
774  return (numChars);
775}
776
777/*
778 * This function does all command procesing for interfacing to gdb.  It
779 * returns 1 if you should skip the instruction at the trap address, 0
780 * otherwise.
781 */
782
783static void
784handle_exception (registers)
785     unsigned long *registers;
786{
787  int tt;                       /* Trap type */
788  int sigval;
789  int addr;
790  int length;
791  char *ptr;
792  unsigned long *sp;
793  unsigned long dsr;
794
795/* First, we must force all of the windows to be spilled out */
796
797  asm("
798        ! Ugh.  sparclet has broken save
799        !save %sp, -64, %sp
800        save
801        add %fp,-64,%sp
802        !save %sp, -64, %sp
803        save
804        add %fp,-64,%sp
805        !save %sp, -64, %sp
806        save
807        add %fp,-64,%sp
808        !save %sp, -64, %sp
809        save
810        add %fp,-64,%sp
811        !save %sp, -64, %sp
812        save
813        add %fp,-64,%sp
814        !save %sp, -64, %sp
815        save
816        add %fp,-64,%sp
817        !save %sp, -64, %sp
818        save
819        add %fp,-64,%sp
820        !save %sp, -64, %sp
821        save
822        add %fp,-64,%sp
823        restore
824        restore
825        restore
826        restore
827        restore
828        restore
829        restore
830        restore
831");
832
833  if (registers[PC] == (unsigned long)breakinst)
834    {
835      registers[PC] = registers[NPC];
836      registers[NPC] += 4;
837    }
838  sp = (unsigned long *)registers[SP];
839
840  tt = (registers[TBR] >> 4) & 0xff;
841
842  /* reply to host that an exception has occurred */
843  sigval = computeSignal(tt);
844  ptr = remcomOutBuffer;
845
846  *ptr++ = 'T';
847  *ptr++ = hexchars[sigval >> 4];
848  *ptr++ = hexchars[sigval & 0xf];
849
850  *ptr++ = hexchars[PC >> 4];
851  *ptr++ = hexchars[PC & 0xf];
852  *ptr++ = ':';
853  ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
854  *ptr++ = ';';
855
856  *ptr++ = hexchars[FP >> 4];
857  *ptr++ = hexchars[FP & 0xf];
858  *ptr++ = ':';
859  ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
860  *ptr++ = ';';
861
862  *ptr++ = hexchars[SP >> 4];
863  *ptr++ = hexchars[SP & 0xf];
864  *ptr++ = ':';
865  ptr = mem2hex((char *)&sp, ptr, 4, 0);
866  *ptr++ = ';';
867
868  *ptr++ = hexchars[NPC >> 4];
869  *ptr++ = hexchars[NPC & 0xf];
870  *ptr++ = ':';
871  ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
872  *ptr++ = ';';
873
874  *ptr++ = hexchars[O7 >> 4];
875  *ptr++ = hexchars[O7 & 0xf];
876  *ptr++ = ':';
877  ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
878  *ptr++ = ';';
879
880  *ptr++ = 0;
881
882  putpacket(remcomOutBuffer);
883
884  while (1)
885    {
886      remcomOutBuffer[0] = 0;
887
888      getpacket(remcomInBuffer);
889      switch (remcomInBuffer[0])
890        {
891        case '?':
892          remcomOutBuffer[0] = 'S';
893          remcomOutBuffer[1] = hexchars[sigval >> 4];
894          remcomOutBuffer[2] = hexchars[sigval & 0xf];
895          remcomOutBuffer[3] = 0;
896          break;
897
898        case 'd':
899          remote_debug = !(remote_debug);       /* toggle debug flag */
900          break;
901
902        case 'g':               /* return the value of the CPU registers */
903          {
904            ptr = remcomOutBuffer;
905            ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
906            ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
907            memset(ptr, '0', 32 * 8); /* Floating point */
908            ptr = mem2hex((char *)&registers[Y],
909                    ptr + 32 * 4 * 2,
910                    8 * 4,
911                    0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
912            ptr = mem2hex((char *)&registers[CCSR],
913                    ptr,
914                    8 * 4,
915                    0); /* CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR */
916            ptr = mem2hex((char *)&registers[ASR1],
917                    ptr,
918                    8 * 4,
919                    0); /* ASR1,ASR15,ASR17,ASR18,ASR19,ASR20,ASR21,ASR22 */
920#if 0 /* not implemented */
921            ptr = mem2hex((char *) &registers[AWR0],
922                    ptr,
923                    32 * 4,
924                    0); /* Alternate Window Registers */
925#endif
926          }
927          break;
928
929        case 'G':       /* set value of all the CPU registers - return OK */
930        case 'P':       /* set value of one CPU register      - return OK */
931          {
932            unsigned long *newsp, psr;
933
934            psr = registers[PSR];
935
936            ptr = &remcomInBuffer[1];
937
938            if (remcomInBuffer[0] == 'P')       /* do a single register */
939              {
940                int regno;
941 
942                if (hexToInt (&ptr, &regno)
943                    && *ptr++ == '=')
944                  if (regno >= L0 && regno <= I7)
945                    hex2mem (ptr, sp + regno - L0, 4, 0);
946                  else
947                    hex2mem (ptr, (char *)&registers[regno], 4, 0);
948                else
949                  {
950                    strcpy (remcomOutBuffer, "P01");
951                    break;
952                  }
953              }
954            else
955              {
956                hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
957                hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
958                hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
959                        8 * 4, 0); /* Y,PSR,WIM,TBR,PC,NPC,FPSR,CPSR */
960                hex2mem(ptr + 72 * 4 * 2, (char *)&registers[CCSR],
961                        8 * 4, 0); /* CCSR,CCPR,CCCRCR,CCOR,CCOBR,CCIBR,CCIR */
962                hex2mem(ptr + 80 * 4 * 2, (char *)&registers[ASR1],
963                        8 * 4, 0); /* ASR1 ... ASR22 */
964#if 0 /* not implemented */
965                hex2mem(ptr + 88 * 4 * 2, (char *)&registers[AWR0],
966                        8 * 4, 0); /* Alternate Window Registers */
967#endif
968              }
969            /* See if the stack pointer has moved.  If so, then copy the saved
970               locals and ins to the new location.  This keeps the window
971               overflow and underflow routines happy.  */
972
973            newsp = (unsigned long *)registers[SP];
974            if (sp != newsp)
975              sp = memcpy(newsp, sp, 16 * 4);
976
977            /* Don't allow CWP to be modified. */
978
979            if (psr != registers[PSR])
980              registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
981
982            strcpy(remcomOutBuffer,"OK");
983          }
984          break;
985
986        case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
987          /* Try to read %x,%x.  */
988
989          ptr = &remcomInBuffer[1];
990
991          if (hexToInt(&ptr, &addr)
992              && *ptr++ == ','
993              && hexToInt(&ptr, &length))
994            {
995              if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
996                break;
997
998              strcpy (remcomOutBuffer, "E03");
999            }
1000          else
1001            strcpy(remcomOutBuffer,"E01");
1002          break;
1003
1004        case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1005          /* Try to read '%x,%x:'.  */
1006
1007          ptr = &remcomInBuffer[1];
1008
1009          if (hexToInt(&ptr, &addr)
1010              && *ptr++ == ','
1011              && hexToInt(&ptr, &length)
1012              && *ptr++ == ':')
1013            {
1014              if (hex2mem(ptr, (char *)addr, length, 1))
1015                strcpy(remcomOutBuffer, "OK");
1016              else
1017                strcpy(remcomOutBuffer, "E03");
1018            }
1019          else
1020            strcpy(remcomOutBuffer, "E02");
1021          break;
1022
1023        case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
1024          /* try to read optional parameter, pc unchanged if no parm */
1025
1026          ptr = &remcomInBuffer[1];
1027          if (hexToInt(&ptr, &addr))
1028            {
1029              registers[PC] = addr;
1030              registers[NPC] = addr + 4;
1031            }
1032
1033/* Need to flush the instruction cache here, as we may have deposited a
1034   breakpoint, and the icache probably has no way of knowing that a data ref to
1035   some location may have changed something that is in the instruction cache.
1036 */
1037
1038          flush_i_cache();
1039          return;
1040
1041          /* kill the program */
1042        case 'k' :              /* do nothing */
1043          break;
1044#if 0
1045        case 't':               /* Test feature */
1046          asm (" std %f30,[%sp]");
1047          break;
1048#endif
1049        case 'r':               /* Reset */
1050          asm ("call 0
1051                nop ");
1052          break;
1053
1054#if 0
1055Disabled until we can unscrew this properly
1056
1057        case 'b':         /* bBB...  Set baud rate to BB... */
1058          {
1059            int baudrate;
1060            extern void set_timer_3();
1061
1062            ptr = &remcomInBuffer[1];
1063            if (!hexToInt(&ptr, &baudrate))
1064              {
1065                strcpy(remcomOutBuffer,"B01");
1066                break;
1067              }
1068
1069            /* Convert baud rate to uart clock divider */
1070            switch (baudrate)
1071              {
1072              case 38400:
1073                baudrate = 16;
1074                break;
1075              case 19200:
1076                baudrate = 33;
1077                break;
1078              case 9600:
1079                baudrate = 65;
1080                break;
1081              default:
1082                strcpy(remcomOutBuffer,"B02");
1083                goto x1;
1084              }
1085
1086            putpacket("OK");    /* Ack before changing speed */
1087            set_timer_3(baudrate); /* Set it */
1088          }
1089x1:       break;
1090#endif
1091        }                       /* switch */
1092
1093      /* reply to the request */
1094      putpacket(remcomOutBuffer);
1095    }
1096}
1097
1098/* This function will generate a breakpoint exception.  It is used at the
1099   beginning of a program to sync up with a debugger and can be used
1100   otherwise as a quick means to stop program execution and "break" into
1101   the debugger. */
1102
1103void
1104breakpoint()
1105{
1106  if (!initialized)
1107    return;
1108
1109  asm(" .globl _breakinst
1110
1111        _breakinst: ta 1
1112      ");
1113}
1114
1115static void
1116hw_breakpoint()
1117{
1118  asm("
1119      ta 127
1120      ");
1121}
1122
1123#if 0 /* experimental and never finished, left here for reference */
1124static void
1125splet_temp(void)
1126{
1127  asm(" sub     %sp,(16+1+6+1+121)*4,%sp ! Make room for input & locals
1128                                        ! + hidden arg + arg spill
1129                                        ! + doubleword alignment
1130                                        ! + registers[121]
1131
1132! Leave a trail of breadcrumbs! (save register save area for debugging)
1133        mov     %sp, %l0
1134        add     %l0, 24*4, %l0
1135        sethi   %hi(_debug_registers), %l1
1136        st      %l0, [%lo(_debug_registers) + %l1]
1137
1138! Save the Alternate Register Set: (not implemented yet)
1139!    To save the Alternate Register set, we must:
1140!    1) Save the current SP in some global location.
1141!    2) Swap the register sets.
1142!    3) Save the Alternate SP in the Y register
1143!    4) Fetch the SP that we saved in step 1.
1144!    5) Use that to save the rest of the regs (not forgetting ASP in Y)
1145!    6) Restore the Alternate SP from Y
1146!    7) Swap the registers back.
1147
1148! 1) Copy the current stack pointer to global _SAVED_STACK_POINTER:
1149        sethi   %hi(_saved_stack_pointer), %l0
1150        st      %sp, [%lo(_saved_stack_pointer) + %l0]
1151
1152! 2) Swap the register sets:
1153        mov     %psr, %l1
1154        sethi   %hi(0x10000), %l2
1155        xor     %l1, %l2, %l1
1156        mov     %l1, %psr
1157        nop                     ! 3 nops after write to %psr (needed?)
1158        nop
1159        nop
1160
1161! 3) Save Alternate L0 in Y
1162        wr      %l0, 0, %y
1163
1164! 4) Load former SP into alternate SP, using L0
1165        sethi   %hi(_saved_stack_pointer), %l0
1166        or      %lo(_saved_stack_pointer), %l0, %l0
1167        swap    [%l0], %sp
1168
1169! 4.5) Restore alternate L0
1170        rd      %y, %l0
1171
1172! 5) Save the Alternate Window Registers
1173        st      %r0, [%sp + (24 + 88) * 4]      ! AWR0
1174        st      %r1, [%sp + (24 + 89) * 4]      ! AWR1
1175        st      %r2, [%sp + (24 + 90) * 4]      ! AWR2
1176        st      %r3, [%sp + (24 + 91) * 4]      ! AWR3
1177        st      %r4, [%sp + (24 + 92) * 4]      ! AWR4
1178        st      %r5, [%sp + (24 + 93) * 4]      ! AWR5
1179        st      %r6, [%sp + (24 + 94) * 4]      ! AWR6
1180        st      %r7, [%sp + (24 + 95) * 4]      ! AWR7
1181        st      %r8, [%sp + (24 + 96) * 4]      ! AWR8
1182        st      %r9, [%sp + (24 + 97) * 4]      ! AWR9
1183        st      %r10, [%sp + (24 + 98) * 4]     ! AWR10
1184        st      %r11, [%sp + (24 + 99) * 4]     ! AWR11
1185        st      %r12, [%sp + (24 + 100) * 4]    ! AWR12
1186        st      %r13, [%sp + (24 + 101) * 4]    ! AWR13
1187!       st      %r14, [%sp + (24 + 102) * 4]    ! AWR14 (SP)
1188        st      %r15, [%sp + (24 + 103) * 4]    ! AWR15
1189        st      %r16, [%sp + (24 + 104) * 4]    ! AWR16
1190        st      %r17, [%sp + (24 + 105) * 4]    ! AWR17
1191        st      %r18, [%sp + (24 + 106) * 4]    ! AWR18
1192        st      %r19, [%sp + (24 + 107) * 4]    ! AWR19
1193        st      %r20, [%sp + (24 + 108) * 4]    ! AWR20
1194        st      %r21, [%sp + (24 + 109) * 4]    ! AWR21
1195        st      %r22, [%sp + (24 + 110) * 4]    ! AWR22
1196        st      %r23, [%sp + (24 + 111) * 4]    ! AWR23
1197        st      %r24, [%sp + (24 + 112) * 4]    ! AWR24
1198        st      %r25, [%sp + (24 + 113) * 4]    ! AWR25
1199        st      %r26, [%sp + (24 + 114) * 4]    ! AWR26
1200        st      %r27, [%sp + (24 + 115) * 4]    ! AWR27
1201        st      %r28, [%sp + (24 + 116) * 4]    ! AWR28
1202        st      %r29, [%sp + (24 + 117) * 4]    ! AWR29
1203        st      %r30, [%sp + (24 + 118) * 4]    ! AWR30
1204        st      %r31, [%sp + (24 + 119) * 4]    ! AWR21
1205
1206! Get the Alternate PSR (I hope...)
1207
1208        rd      %psr, %l2
1209        st      %l2, [%sp + (24 + 120) * 4]     ! APSR
1210
1211! Don't forget the alternate stack pointer
1212
1213        rd      %y, %l3
1214        st      %l3, [%sp + (24 + 102) * 4]     ! AWR14 (SP)
1215
1216! 6) Restore the Alternate SP (saved in Y)
1217
1218        rd      %y, %o6
1219
1220
1221! 7) Swap the registers back:
1222
1223        mov     %psr, %l1
1224        sethi   %hi(0x10000), %l2
1225        xor     %l1, %l2, %l1
1226        mov     %l1, %psr
1227        nop                     ! 3 nops after write to %psr (needed?)
1228        nop
1229        nop
1230");
1231}
1232
1233#endif
Note: See TracBrowser for help on using the repository browser.