]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/alpha/alpha/db_interface.c
Modify the critical section API as follows:
[FreeBSD/FreeBSD.git] / sys / alpha / alpha / db_interface.c
1 /* $NetBSD: db_interface.c,v 1.2 1997/09/16 19:07:19 thorpej Exp $ */
2 /* $FreeBSD$ */
3
4 /* 
5  * Mach Operating System
6  * Copyright (c) 1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  * 
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  * 
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  * 
19  * Carnegie Mellon requests users of this software to return to
20  * 
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  * 
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  *
29  *      db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
30  */
31
32 /*
33  * Parts of this file are derived from Mach 3:
34  *
35  *      File: alpha_instruction.c
36  *      Author: Alessandro Forin, Carnegie Mellon University
37  *      Date:   6/92
38  */
39
40 /*
41  * Interface to DDB.
42  *
43  * Modified for NetBSD/alpha by:
44  *
45  *      Christopher G. Demetriou, Carnegie Mellon University
46  *
47  *      Jason R. Thorpe, Numerical Aerospace Simulation Facility,
48  *      NASA Ames Research Center
49  */
50
51 #include <sys/cdefs.h>                  /* RCS ID & Copyright macro defns */
52
53 /* __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.2 1997/09/16 19:07:19 thorpej Exp $"); */
54
55 #include <sys/param.h>
56 #include <sys/proc.h>
57 #include <sys/reboot.h>
58 #include <sys/systm.h>
59 #include <sys/kernel.h>
60 #include <sys/cons.h>
61 #include <sys/ktr.h>
62 #include <sys/lock.h>
63 #include <sys/pcpu.h>
64 #include <sys/smp.h>
65
66 #include <vm/vm.h>
67
68 #include <machine/db_machdep.h>
69 #include <machine/pal.h>
70 #include <machine/prom.h>
71
72 #include <alpha/alpha/db_instruction.h>
73
74 #include <ddb/ddb.h>
75
76 #include <ddb/db_access.h>
77 #include <ddb/db_sym.h>
78 #include <ddb/db_variables.h>
79 #include <machine/setjmp.h>
80
81 static jmp_buf *db_nofault = 0;
82 extern jmp_buf  db_jmpbuf;
83
84 extern void     gdb_handle_exception __P((db_regs_t *, int, int));
85
86 #if 0
87 extern char *trap_type[];
88 extern int trap_types;
89 #endif
90
91 int     db_active;
92
93 void    ddbprinttrap __P((unsigned long, unsigned long, unsigned long,
94             unsigned long));
95
96 struct db_variable db_regs[] = {
97         {       "v0",   &ddb_regs.tf_regs[FRAME_V0],    FCN_NULL        },
98         {       "t0",   &ddb_regs.tf_regs[FRAME_T0],    FCN_NULL        },
99         {       "t1",   &ddb_regs.tf_regs[FRAME_T1],    FCN_NULL        },
100         {       "t2",   &ddb_regs.tf_regs[FRAME_T2],    FCN_NULL        },
101         {       "t3",   &ddb_regs.tf_regs[FRAME_T3],    FCN_NULL        },
102         {       "t4",   &ddb_regs.tf_regs[FRAME_T4],    FCN_NULL        },
103         {       "t5",   &ddb_regs.tf_regs[FRAME_T5],    FCN_NULL        },
104         {       "t6",   &ddb_regs.tf_regs[FRAME_T6],    FCN_NULL        },
105         {       "t7",   &ddb_regs.tf_regs[FRAME_T7],    FCN_NULL        },
106         {       "s0",   &ddb_regs.tf_regs[FRAME_S0],    FCN_NULL        },
107         {       "s1",   &ddb_regs.tf_regs[FRAME_S1],    FCN_NULL        },
108         {       "s2",   &ddb_regs.tf_regs[FRAME_S2],    FCN_NULL        },
109         {       "s3",   &ddb_regs.tf_regs[FRAME_S3],    FCN_NULL        },
110         {       "s4",   &ddb_regs.tf_regs[FRAME_S4],    FCN_NULL        },
111         {       "s5",   &ddb_regs.tf_regs[FRAME_S5],    FCN_NULL        },
112         {       "s6",   &ddb_regs.tf_regs[FRAME_S6],    FCN_NULL        },
113         {       "a0",   &ddb_regs.tf_regs[FRAME_A0],    FCN_NULL        },
114         {       "a1",   &ddb_regs.tf_regs[FRAME_A1],    FCN_NULL        },
115         {       "a2",   &ddb_regs.tf_regs[FRAME_A2],    FCN_NULL        },
116         {       "a3",   &ddb_regs.tf_regs[FRAME_A3],    FCN_NULL        },
117         {       "a4",   &ddb_regs.tf_regs[FRAME_A4],    FCN_NULL        },
118         {       "a5",   &ddb_regs.tf_regs[FRAME_A5],    FCN_NULL        },
119         {       "t8",   &ddb_regs.tf_regs[FRAME_T8],    FCN_NULL        },
120         {       "t9",   &ddb_regs.tf_regs[FRAME_T9],    FCN_NULL        },
121         {       "t10",  &ddb_regs.tf_regs[FRAME_T10],   FCN_NULL        },
122         {       "t11",  &ddb_regs.tf_regs[FRAME_T11],   FCN_NULL        },
123         {       "ra",   &ddb_regs.tf_regs[FRAME_RA],    FCN_NULL        },
124         {       "t12",  &ddb_regs.tf_regs[FRAME_T12],   FCN_NULL        },
125         {       "at",   &ddb_regs.tf_regs[FRAME_AT],    FCN_NULL        },
126         {       "gp",   &ddb_regs.tf_regs[FRAME_GP],    FCN_NULL        },
127         {       "sp",   &ddb_regs.tf_regs[FRAME_SP],    FCN_NULL        },
128         {       "pc",   &ddb_regs.tf_regs[FRAME_PC],    FCN_NULL        },
129         {       "ps",   &ddb_regs.tf_regs[FRAME_PS],    FCN_NULL        },
130         {       "ai",   &ddb_regs.tf_regs[FRAME_T11],   FCN_NULL        },
131         {       "pv",   &ddb_regs.tf_regs[FRAME_T12],   FCN_NULL        },
132 };
133 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
134
135 /*
136  * Print trap reason.
137  */
138 void
139 ddbprinttrap(a0, a1, a2, entry)
140         unsigned long a0, a1, a2, entry;
141 {
142
143         /* XXX Implement. */
144
145         printf("ddbprinttrap(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", a0, a1, a2,
146             entry);
147 }
148
149 /*
150  *  ddb_trap - field a kernel trap
151  */
152 int
153 kdb_trap(a0, a1, a2, entry, regs)
154         unsigned long a0, a1, a2, entry;
155         db_regs_t *regs;
156 {
157         int ddb_mode = !(boothowto & RB_GDB);
158         critical_t s;
159
160         /*
161          * Don't bother checking for usermode, since a benign entry
162          * by the kernel (call to Debugger() or a breakpoint) has
163          * already checked for usermode.  If neither of those
164          * conditions exist, something Bad has happened.
165          */
166
167         if (entry != ALPHA_KENTRY_IF ||
168             (a0 != ALPHA_IF_CODE_BUGCHK && a0 != ALPHA_IF_CODE_BPT
169                 && a0 != ALPHA_IF_CODE_GENTRAP)) {
170 #if 0
171                 if (ddb_mode) {
172                         db_printf("ddbprinttrap from 0x%lx\n",  /* XXX */
173                                   regs->tf_regs[FRAME_PC]);
174                         ddbprinttrap(a0, a1, a2, entry);
175                         /*
176                          * Tell caller "We did NOT handle the trap."
177                          * Caller should panic, or whatever.
178                          */
179                         return (0);
180                 }
181 #endif
182                 if (db_nofault) {
183                         jmp_buf *no_fault = db_nofault;
184                         db_nofault = 0;
185                         longjmp(*no_fault, 1);
186                 }
187         }
188
189         /*
190          * XXX Should switch to DDB's own stack, here.
191          */
192
193         ddb_regs = *regs;
194
195         s = cpu_critical_enter();
196
197 #ifdef SMP
198 #ifdef DIAGNOSTIC
199         db_printf("stopping %x\n", PCPU_GET(other_cpus));
200 #endif
201         stop_cpus(PCPU_GET(other_cpus));
202 #ifdef DIAGNOSTIC
203         db_printf("stopped_cpus=%x\n", stopped_cpus);
204 #endif
205 #endif
206
207         db_active++;
208
209         if (ddb_mode) {
210             cndbctl(TRUE);      /* DDB active, unblank video */
211             db_trap(entry, a0); /* Where the work happens */
212             cndbctl(FALSE);     /* DDB inactive */
213         } else
214             gdb_handle_exception(&ddb_regs, entry, a0);
215
216         db_active--;
217
218 #ifdef SMP 
219         restart_cpus(stopped_cpus);
220 #endif
221
222         cpu_critical_exit(s);
223
224         *regs = ddb_regs;
225
226         /*
227          * Tell caller "We HAVE handled the trap."
228          */
229         return (1);
230 }
231
232 /*
233  * Read bytes from kernel address space for debugger.
234  */
235 void
236 db_read_bytes(addr, size, data)
237         vm_offset_t     addr;
238         register size_t size;
239         register char   *data;
240 {
241         register char   *src;
242
243         db_nofault = &db_jmpbuf;
244
245         src = (char *)addr;
246         while (size-- > 0)
247                 *data++ = *src++;
248
249         db_nofault = 0;
250 }
251
252 /*
253  * Write bytes to kernel address space for debugger.
254  */
255 void
256 db_write_bytes(addr, size, data)
257         vm_offset_t     addr;
258         register size_t size;
259         register char   *data;
260 {
261         register char   *dst;
262
263         db_nofault = &db_jmpbuf;
264
265         dst = (char *)addr;
266         while (size-- > 0)
267                 *dst++ = *data++;
268         alpha_pal_imb();
269
270         db_nofault = 0;
271 }
272
273 void
274 Debugger(const char* msg)
275 {
276         u_int   saveintr;
277
278         printf("%s\n", msg);
279         saveintr = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
280         __asm("call_pal 0x81");         /* XXX bugchk */
281         alpha_pal_swpipl(saveintr);
282 }
283
284 /*
285  * Alpha-specific ddb commands:
286  *
287  *      halt            set halt bit in rpb and halt
288  *      reboot          set reboot bit in rpb and halt
289  */
290
291 DB_COMMAND(halt, db_mach_halt)
292 {
293
294         prom_halt(1);
295 }
296
297 DB_COMMAND(reboot, db_mach_reboot)
298 {
299         prom_halt(0);
300 }
301
302 /*
303  * Map Alpha register numbers to trapframe/db_regs_t offsets.
304  */
305 static int reg_to_frame[32] = {
306         FRAME_V0,
307         FRAME_T0,
308         FRAME_T1,
309         FRAME_T2,
310         FRAME_T3,
311         FRAME_T4,
312         FRAME_T5,
313         FRAME_T6,
314         FRAME_T7,
315
316         FRAME_S0,
317         FRAME_S1,
318         FRAME_S2,
319         FRAME_S3,
320         FRAME_S4,
321         FRAME_S5,
322         FRAME_S6,
323
324         FRAME_A0,
325         FRAME_A1,
326         FRAME_A2,
327         FRAME_A3,
328         FRAME_A4,
329         FRAME_A5,
330
331         FRAME_T8,
332         FRAME_T9,
333         FRAME_T10,
334         FRAME_T11,
335         FRAME_RA,
336         FRAME_T12,
337         FRAME_AT,
338         FRAME_GP,
339         FRAME_SP,
340         -1,             /* zero */
341 };
342
343 u_long
344 db_register_value(regs, regno)
345         db_regs_t *regs;
346         int regno;
347 {
348
349         if (regno > 31 || regno < 0) {
350                 db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno);
351                 return (0);
352         }
353
354         if (regno == 31)
355                 return (0);
356
357         return (regs->tf_regs[reg_to_frame[regno]]);
358 }
359
360 /*
361  * Support functions for software single-step.
362  */
363
364 boolean_t
365 db_inst_call(ins)
366         int ins;
367 {
368         alpha_instruction insn;
369
370         insn.bits = ins;
371         return ((insn.branch_format.opcode == op_bsr) ||
372             ((insn.jump_format.opcode == op_j) &&
373              (insn.jump_format.action & 1)));
374 }
375
376 boolean_t
377 db_inst_return(ins)
378         int ins;
379 {
380         alpha_instruction insn;
381
382         insn.bits = ins;
383         return ((insn.jump_format.opcode == op_j) &&
384             (insn.jump_format.action == op_ret));
385 }
386
387 boolean_t
388 db_inst_trap_return(ins)
389         int ins;
390 {
391         alpha_instruction insn;
392
393         insn.bits = ins;
394         return ((insn.pal_format.opcode == op_pal) &&
395             (insn.pal_format.function == PAL_OSF1_rti));
396 }
397
398 boolean_t
399 db_inst_branch(ins)
400         int ins;
401 {
402         alpha_instruction insn;
403
404         insn.bits = ins;
405         switch (insn.branch_format.opcode) {
406         case op_j:
407         case op_br:
408         case op_fbeq:
409         case op_fblt:
410         case op_fble:
411         case op_fbne:
412         case op_fbge:
413         case op_fbgt:
414         case op_blbc:
415         case op_beq:
416         case op_blt:
417         case op_ble:
418         case op_blbs:
419         case op_bne:
420         case op_bge:
421         case op_bgt:
422                 return (TRUE);
423         }
424
425         return (FALSE);
426 }
427
428 boolean_t
429 db_inst_unconditional_flow_transfer(ins)
430         int ins;
431 {
432         alpha_instruction insn;
433
434         insn.bits = ins;
435         switch (insn.branch_format.opcode) {
436         case op_j:
437         case op_br:
438                 return (TRUE);
439
440         case op_pal:
441                 switch (insn.pal_format.function) {
442                 case PAL_OSF1_retsys:
443                 case PAL_OSF1_rti:
444                 case PAL_OSF1_callsys:
445                         return (TRUE);
446                 }
447         }
448
449         return (FALSE);
450 }
451
452 #if 0
453 boolean_t
454 db_inst_spill(ins, regn)
455         int ins, regn;
456 {
457         alpha_instruction insn;
458
459         insn.bits = ins;
460         return ((insn.mem_format.opcode == op_stq) &&
461             (insn.mem_format.rd == regn));
462 }
463 #endif
464
465 boolean_t
466 db_inst_load(ins)
467         int ins;
468 {
469         alpha_instruction insn;
470
471         insn.bits = ins;
472         
473         /* Loads. */
474         if (insn.mem_format.opcode == op_ldbu ||
475             insn.mem_format.opcode == op_ldq_u ||
476             insn.mem_format.opcode == op_ldwu)
477                 return (TRUE);
478         if ((insn.mem_format.opcode >= op_ldf) &&
479             (insn.mem_format.opcode <= op_ldt))
480                 return (TRUE);
481         if ((insn.mem_format.opcode >= op_ldl) &&
482             (insn.mem_format.opcode <= op_ldq_l))
483                 return (TRUE);
484
485         /* Prefetches. */
486         if (insn.mem_format.opcode == op_special) {
487                 /* Note: MB is treated as a store. */
488                 if ((insn.mem_format.displacement == (short)op_fetch) ||
489                     (insn.mem_format.displacement == (short)op_fetch_m))
490                         return (TRUE);
491         }
492
493         return (FALSE);
494 }
495
496 boolean_t
497 db_inst_store(ins)
498         int ins;
499 {
500         alpha_instruction insn;
501
502         insn.bits = ins;
503
504         /* Stores. */
505         if (insn.mem_format.opcode == op_stw ||
506             insn.mem_format.opcode == op_stb ||
507             insn.mem_format.opcode == op_stq_u)
508                 return (TRUE);
509         if ((insn.mem_format.opcode >= op_stf) &&
510             (insn.mem_format.opcode <= op_stt))
511                 return (TRUE);
512         if ((insn.mem_format.opcode >= op_stl) &&
513             (insn.mem_format.opcode <= op_stq_c))
514                 return (TRUE);
515
516         /* Barriers. */
517         if (insn.mem_format.opcode == op_special) {
518                 if (insn.mem_format.displacement == op_mb)
519                         return (TRUE);
520         }
521
522         return (FALSE);
523 }
524
525 db_addr_t
526 db_branch_taken(ins, pc, regs)
527         int ins;
528         db_addr_t pc;
529         db_regs_t *regs;
530 {
531         alpha_instruction insn;
532         db_addr_t newpc;
533
534         insn.bits = ins;
535         switch (insn.branch_format.opcode) {
536         /*
537          * Jump format: target PC is (contents of instruction's "RB") & ~3.
538          */
539         case op_j:
540                 newpc = db_register_value(regs, insn.jump_format.rs) & ~3;
541                 break;
542
543         /*
544          * Branch format: target PC is
545          *      (new PC) + (4 * sign-ext(displacement)).
546          */
547         case op_br:
548         case op_fbeq:
549         case op_fblt:
550         case op_fble:
551         case op_bsr:
552         case op_fbne:
553         case op_fbge:
554         case op_fbgt:
555         case op_blbc:
556         case op_beq:
557         case op_blt:
558         case op_ble:
559         case op_blbs:
560         case op_bne:
561         case op_bge:
562         case op_bgt:
563                 newpc = (insn.branch_format.displacement << 2) + (pc + 4);
564                 break;
565
566         default:
567                 printf("DDB: db_inst_branch_taken on non-branch!\n");
568                 newpc = pc;     /* XXX */
569         }
570
571         return (newpc);
572 }
573
574 void
575 db_show_mdpcpu(struct pcpu *pc)
576 {
577
578         db_printf("ipis         = 0x%lx\n", pc->pc_pending_ipis);
579         db_printf("next ASN     = %d\n", pc->pc_next_asn);
580 }