1 /*
2 * Copyright (c) 1996 Cygnus Support
3 *
4 * The authors hereby grant permission to use, copy, modify, distribute,
5 * and license this software and its documentation for any purpose, provided
6 * that existing copyright notices are retained in all copies and that this
7 * notice is included verbatim in any distributions. No written agreement,
8 * license, or royalty fee is required for any of the authorized uses.
9 * Modifications to this software may be copyrighted by their authors
10 * and need not follow the licensing terms described here, provided that
11 * the new terms are clearly indicated on the first page of each file where
12 * they apply.
13 */
14
15 #include <string.h>
16 #include <signal.h>
17 #include "debug.h"
18 #include "asm.h"
19 #include "slite.h"
20
21 extern unsigned long rdtbr();
22 extern struct trap_entry fltr_proto;
23 extern void trap_low();
24 exception_t default_trap_hook = trap_low;
25 void target_reset();
26 void flush_i_cache();
27 char *target_read_registers(unsigned long *);
28 char *target_write_registers(unsigned long *);
29 char *target_dump_state(unsigned long *);
30
31 #define NUMREGS 72
32
33 /* Number of bytes of registers. */
34 #define NUMREGBYTES (NUMREGS * 4)
35
36 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
37 O0, O1, O2, O3, O4, O5, SP, O7,
38 L0, L1, L2, L3, L4, L5, L6, L7,
39 I0, I1, I2, I3, I4, I5, FP, I7,
40
41 F0, F1, F2, F3, F4, F5, F6, F7,
42 F8, F9, F10, F11, F12, F13, F14, F15,
43 F16, F17, F18, F19, F20, F21, F22, F23,
44 F24, F25, F26, F27, F28, F29, F30, F31,
45 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
46
47 /*
48 * Each entry in the trap vector occupies four words, typically a jump
49 * to the processing routine.
50 */
51 struct trap_entry {
52 unsigned sethi_filler:10;
53 unsigned sethi_imm22:22;
54 unsigned jmpl_filler:19;
55 unsigned jmpl_simm13:13;
56 unsigned long filler[2];
57 };
58
59 /*
60 * This table contains the mapping between SPARC hardware trap types, and
61 * signals, which are primarily what GDB understands. It also indicates
62 * which hardware traps we need to commandeer when initializing the stub.
63 */
64 struct trap_info hard_trap_info[] = {
65 {1, SIGSEGV}, /* instruction access error */
66 {2, SIGILL}, /* privileged instruction */
67 {3, SIGILL}, /* illegal instruction */
68 {4, SIGEMT}, /* fp disabled */
69 {36, SIGEMT}, /* cp disabled */
70 {7, SIGBUS}, /* mem address not aligned */
71 {9, SIGSEGV}, /* data access exception */
72 {10, SIGEMT}, /* tag overflow */
73 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
74 {0, 0} /* Must be last */
75 };
76
77 extern struct trap_entry fltr_proto;
78 void
exception_handler(int tt,unsigned long routine)79 exception_handler (int tt, unsigned long routine)
80 {
81 struct trap_entry *tb; /* Trap vector base address */
82
83 DEBUG (1, "Entering exception_handler()");
84 if (tt != 256) {
85 tb = (struct trap_entry *) (rdtbr() & ~0xfff);
86 } else {
87 tt = 255;
88 tb = (struct trap_entry *) 0;
89 }
90
91 tb[tt] = fltr_proto;
92
93 tb[tt].sethi_imm22 = routine >> 10;
94 tb[tt].jmpl_simm13 = routine & 0x3ff;
95
96 DEBUG (1, "Leaving exception_handler()");
97 }
98
99 /*
100 * This is so we can trap a memory fault when reading or writing
101 * directly to memory.
102 */
103 void
set_mem_fault_trap(enable)104 set_mem_fault_trap(enable)
105 int enable;
106 {
107 extern void fltr_set_mem_err();
108
109 DEBUG (1, "Entering set_mem_fault_trap()");
110
111 mem_err = 0;
112
113 if (enable)
114 exception_handler(9, (unsigned long)fltr_set_mem_err);
115 else
116 exception_handler(9, (unsigned long)trap_low);
117
118 DEBUG (1, "Leaving set_mem_fault_trap()");
119 }
120
121 /*
122 * This function does all command procesing for interfacing to gdb. It
123 * returns 1 if you should skip the instruction at the trap address, 0
124 * otherwise.
125 */
126 extern void breakinst();
127
128 void
handle_exception(registers)129 handle_exception (registers)
130 unsigned long *registers;
131 {
132 int sigval;
133
134 /* First, we must force all of the windows to be spilled out */
135
136 DEBUG (1, "Entering handle_exception()");
137
138 /* asm("mov %g0, %wim ; nop; nop; nop"); */
139 asm(" save %sp, -64, %sp \n\
140 save %sp, -64, %sp \n\
141 save %sp, -64, %sp \n\
142 save %sp, -64, %sp \n\
143 save %sp, -64, %sp \n\
144 save %sp, -64, %sp \n\
145 save %sp, -64, %sp \n\
146 save %sp, -64, %sp \n\
147 restore \n\
148 restore \n\
149 restore \n\
150 restore \n\
151 restore \n\
152 restore \n\
153 restore \n\
154 restore \n\
155 ");
156
157 if (registers[PC] == (unsigned long)breakinst) {
158 registers[PC] = registers[NPC];
159 registers[NPC] += 4;
160 }
161
162 /* get the last know signal number from the trap register */
163 sigval = computeSignal((registers[TBR] >> 4) & 0xff);
164
165 /* call the main command processing loop for gdb */
166 gdb_event_loop (sigval, registers);
167 }
168
169 /*
170 * This function will generate a breakpoint exception. It is used at the
171 * beginning of a program to sync up with a debugger and can be used
172 * otherwise as a quick means to stop program execution and "break" into
173 * the debugger.
174 */
175 void
breakpoint()176 breakpoint()
177 {
178 DEBUG (1, "Entering breakpoint()");
179
180 if (!initialized)
181 return;
182
183 asm(" .globl " STRINGSYM(breakinst) " \n\
184 " STRINGSYM(breakinst) ": ta 128+1 \n\
185 nop \n\
186 nop \n\
187 ");
188 }
189
190 /*
191 * This is just a test vector for debugging excpetions.
192 */
193 void
bad_trap(tt)194 bad_trap(tt)
195 int tt;
196 {
197 print ("Got a bad trap #");
198 outbyte (tt);
199 outbyte ('\n');
200 asm("ta 0 \n\
201 nop \n\
202 nop \n\
203 ");
204 }
205
206 /*
207 * This is just a test vector for debugging excpetions.
208 */
209 void
soft_trap(tt)210 soft_trap(tt)
211 int tt;
212 {
213 print ("Got a soft trap #");
214 outbyte (tt);
215 outbyte ('\n');
216 asm("ta 0 \n\
217 nop \n\
218 nop \n\
219 ");
220 }
221
222 /*
223 * Flush the instruction cache. We need to do this for the debugger stub so
224 * that breakpoints, et. al. become visible to the instruction stream after
225 * storing them in memory.
226 *
227 * For the sparclite, we need to do something here, but for a standard
228 * sparc (which SIS simulates), we don't.
229 */
230
231 void
flush_i_cache()232 flush_i_cache ()
233 {
234 }
235
236 /*
237 * This will reset the processor, so we never return from here.
238 */
239 void
target_reset()240 target_reset()
241 {
242 asm ("call 0 \n\
243 nop ");
244 }
245
246 /*
247 * g - read registers.
248 * no params.
249 * returns a vector of words, size is NUM_REGS.
250 */
251 char *
target_read_registers(unsigned long * registers)252 target_read_registers(unsigned long *registers)
253 {
254 char *ptr;
255 unsigned long *sp;
256
257 DEBUG (1, "In target_read_registers()");
258
259 ptr = packet_out_buf;
260 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
261 ptr = mem2hex((unsigned char *)(sp + 0), ptr, 16 * 4, 0); /* L & I regs */
262 memset(ptr, '0', 32 * 8); /* Floating point */
263 mem2hex((char *)®isters[Y],
264 ptr + 32 * 4 * 2,
265 8 * 4,
266 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
267 return (ptr);
268 }
269
270 /*
271 * G - write registers.
272 * param is a vector of words, size is NUM_REGS.
273 * returns an OK or an error number.
274 */
275 char *
target_write_registers(unsigned long * registers)276 target_write_registers(unsigned long *registers)
277 {
278 unsigned char *ptr;
279 unsigned long *sp;
280 unsigned long *newsp, psr;
281
282 DEBUG (1, "In target_write_registers()");
283
284 psr = registers[PSR];
285
286 ptr = &packet_in_buf[1];
287
288 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
289 hex2mem(ptr + 16 * 4 * 2, (unsigned char *)(sp + 0), 16 * 4, 0); /* L & I regs */
290 hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
291 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
292
293 /*
294 * see if the stack pointer has moved. If so, then copy the saved
295 * locals and ins to the new location. This keeps the window
296 * overflow and underflow routines happy.
297 */
298
299 newsp = (unsigned long *)registers[SP];
300 if (sp != newsp)
301 sp = memcpy(newsp, sp, 16 * 4);
302
303 /* Don't allow CWP to be modified. */
304
305 if (psr != registers[PSR])
306 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
307
308 return (ptr);
309 }
310
311 char *
target_dump_state(unsigned long * registers)312 target_dump_state(unsigned long *registers)
313 {
314 int tt; /* Trap type */
315 int sigval;
316 char *ptr;
317 unsigned long *sp;
318
319 DEBUG (1, "In target_dump_state()");
320
321 sp = (unsigned long *)registers[SP];
322
323 tt = (registers[TBR] >> 4) & 0xff;
324
325 /* reply to host that an exception has occurred */
326 sigval = computeSignal(tt);
327 ptr = packet_out_buf;
328
329 *ptr++ = 'T';
330 *ptr++ = hexchars[sigval >> 4];
331 *ptr++ = hexchars[sigval & 0xf];
332
333 *ptr++ = hexchars[PC >> 4];
334 *ptr++ = hexchars[PC & 0xf];
335 *ptr++ = ':';
336 ptr = mem2hex((unsigned char *)®isters[PC], ptr, 4, 0);
337 *ptr++ = ';';
338
339 *ptr++ = hexchars[FP >> 4];
340 *ptr++ = hexchars[FP & 0xf];
341 *ptr++ = ':';
342 ptr = mem2hex((unsigned char *)(sp + 8 + 6), ptr, 4, 0); /* FP */
343 *ptr++ = ';';
344
345 *ptr++ = hexchars[SP >> 4];
346 *ptr++ = hexchars[SP & 0xf];
347 *ptr++ = ':';
348 ptr = mem2hex((unsigned char *)&sp, ptr, 4, 0);
349 *ptr++ = ';';
350
351 *ptr++ = hexchars[NPC >> 4];
352
353 return (packet_out_buf);
354 }
355
356 void
write_pc(unsigned long * registers,unsigned long addr)357 write_pc(unsigned long *registers, unsigned long addr)
358 {
359 DEBUG (1, "In write_pc");
360
361 registers[PC] = addr;
362 registers[NPC] = addr + 4;
363 }
364