1 /* $NetBSD: db_interface.c,v 1.37 2022/10/26 23:38:05 riastradh Exp $ */
2
3 /*
4 * Mach Operating System
5 * Copyright (c) 1992,1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS ``AS IS''
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 *
28 * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
29 */
30
31 /*
32 * Parts of this file are derived from Mach 3:
33 *
34 * File: alpha_instruction.c
35 * Author: Alessandro Forin, Carnegie Mellon University
36 * Date: 6/92
37 */
38
39 /*
40 * Interface to DDB.
41 *
42 * Modified for NetBSD/alpha by:
43 *
44 * Christopher G. Demetriou, Carnegie Mellon University
45 *
46 * Jason R. Thorpe, Numerical Aerospace Simulation Facility,
47 * NASA Ames Research Center
48 */
49
50 #include "opt_ddb.h"
51 #include "opt_multiprocessor.h"
52
53 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
54
55 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.37 2022/10/26 23:38:05 riastradh Exp $");
56
57 #include <sys/param.h>
58 #include <sys/proc.h>
59 #include <sys/reboot.h>
60 #include <sys/systm.h>
61
62 #include <dev/cons.h>
63
64 #include <machine/alpha.h>
65 #include <machine/db_machdep.h>
66 #include <machine/pal.h>
67 #include <machine/prom.h>
68
69 #include <alpha/alpha/db_instruction.h>
70
71 #include <ddb/db_active.h>
72 #include <ddb/db_sym.h>
73 #include <ddb/db_command.h>
74 #include <ddb/db_extern.h>
75 #include <ddb/db_access.h>
76 #include <ddb/db_output.h>
77 #include <ddb/db_variables.h>
78 #include <ddb/db_interface.h>
79
80
81 #if 0
82 extern char *trap_type[];
83 extern int trap_types;
84 #endif
85
86 int db_active = 0;
87
88 db_regs_t *ddb_regp;
89
90 #if defined(MULTIPROCESSOR)
91 void db_mach_cpu(db_expr_t, bool, db_expr_t, const char *);
92 #endif
93
94 const struct db_command db_machine_command_table[] = {
95 #if defined(MULTIPROCESSOR)
96 { DDB_ADD_CMD("cpu", db_mach_cpu, 0,
97 "switch to another cpu", "cpu-no", NULL) },
98 #endif
99 { DDB_END_CMD },
100 };
101
102 static int db_alpha_regop(const struct db_variable *, db_expr_t *, int);
103
104 #define dbreg(xx) ((long *)(xx))
105
106 const struct db_variable db_regs[] = {
107 { "v0", dbreg(FRAME_V0), db_alpha_regop },
108 { "t0", dbreg(FRAME_T0), db_alpha_regop },
109 { "t1", dbreg(FRAME_T1), db_alpha_regop },
110 { "t2", dbreg(FRAME_T2), db_alpha_regop },
111 { "t3", dbreg(FRAME_T3), db_alpha_regop },
112 { "t4", dbreg(FRAME_T4), db_alpha_regop },
113 { "t5", dbreg(FRAME_T5), db_alpha_regop },
114 { "t6", dbreg(FRAME_T6), db_alpha_regop },
115 { "t7", dbreg(FRAME_T7), db_alpha_regop },
116 { "s0", dbreg(FRAME_S0), db_alpha_regop },
117 { "s1", dbreg(FRAME_S1), db_alpha_regop },
118 { "s2", dbreg(FRAME_S2), db_alpha_regop },
119 { "s3", dbreg(FRAME_S3), db_alpha_regop },
120 { "s4", dbreg(FRAME_S4), db_alpha_regop },
121 { "s5", dbreg(FRAME_S5), db_alpha_regop },
122 { "s6", dbreg(FRAME_S6), db_alpha_regop },
123 { "a0", dbreg(FRAME_A0), db_alpha_regop },
124 { "a1", dbreg(FRAME_A1), db_alpha_regop },
125 { "a2", dbreg(FRAME_A2), db_alpha_regop },
126 { "a3", dbreg(FRAME_A3), db_alpha_regop },
127 { "a4", dbreg(FRAME_A4), db_alpha_regop },
128 { "a5", dbreg(FRAME_A5), db_alpha_regop },
129 { "t8", dbreg(FRAME_T8), db_alpha_regop },
130 { "t9", dbreg(FRAME_T9), db_alpha_regop },
131 { "t10", dbreg(FRAME_T10), db_alpha_regop },
132 { "t11", dbreg(FRAME_T11), db_alpha_regop },
133 { "ra", dbreg(FRAME_RA), db_alpha_regop },
134 { "t12", dbreg(FRAME_T12), db_alpha_regop },
135 { "at", dbreg(FRAME_AT), db_alpha_regop },
136 { "gp", dbreg(FRAME_GP), db_alpha_regop },
137 { "sp", dbreg(FRAME_SP), db_alpha_regop },
138 { "pc", dbreg(FRAME_PC), db_alpha_regop },
139 { "ps", dbreg(FRAME_PS), db_alpha_regop },
140 { "ai", dbreg(FRAME_T11), db_alpha_regop },
141 { "pv", dbreg(FRAME_T12), db_alpha_regop },
142 };
143 const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
144
145 static int
db_alpha_regop(const struct db_variable * vp,db_expr_t * val,int opcode)146 db_alpha_regop(const struct db_variable *vp, db_expr_t *val, int opcode)
147 {
148 unsigned long *tfaddr;
149 unsigned long zeroval = 0;
150 struct trapframe *f = NULL;
151
152 if (vp->modif != NULL && *vp->modif == 'u') {
153 if (curlwp != NULL)
154 f = curlwp->l_md.md_tf;
155 } else f = DDB_REGS;
156 tfaddr = f == NULL ? &zeroval : &f->tf_regs[(u_long)vp->valuep];
157 switch (opcode) {
158 case DB_VAR_GET:
159 *val = *tfaddr;
160 break;
161
162 case DB_VAR_SET:
163 *tfaddr = *val;
164 break;
165
166 default:
167 panic("db_alpha_regop: unknown op %d", opcode);
168 }
169
170 return (0);
171 }
172
173 /*
174 * ddb_trap - field a kernel trap
175 */
176 int
ddb_trap(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long entry,db_regs_t * regs)177 ddb_trap(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long entry, db_regs_t *regs)
178 {
179 struct cpu_info *ci = curcpu();
180 unsigned long psl;
181
182 if (entry != ALPHA_KENTRY_IF ||
183 (a0 != ALPHA_IF_CODE_BPT && a0 != ALPHA_IF_CODE_BUGCHK)) {
184 if (db_recover != 0) {
185 /* This will longjmp back into db_command_loop() */
186 db_error("Caught exception in ddb.\n");
187 /* NOTREACHED */
188 }
189
190 /*
191 * Tell caller "We did NOT handle the trap."
192 * Caller should panic, or whatever.
193 */
194 return (0);
195 }
196
197 /*
198 * alpha_debug() switches us to the debugger stack.
199 */
200
201 /* Our register state is simply the trapframe. */
202 ddb_regp = ci->ci_db_regs = regs;
203
204 /*
205 * Use SWPIPL directly; we want to avoid processing
206 * software interrrupts when we go back. Soft ints
207 * will be caught later, so not to worry.
208 */
209 psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
210
211 db_active++;
212 cnpollc(true); /* Set polling mode, unblank video */
213
214 db_trap(entry, a0); /* Where the work happens */
215
216 cnpollc(false); /* Resume interrupt mode */
217 db_active--;
218
219 alpha_pal_swpipl(psl);
220
221 ddb_regp = ci->ci_db_regs = NULL;
222
223 /*
224 * Tell caller "We HAVE handled the trap."
225 */
226 return (1);
227 }
228
229 /*
230 * Read bytes from kernel address space for debugger.
231 */
232 void
db_read_bytes(vaddr_t addr,register size_t size,register char * data)233 db_read_bytes(vaddr_t addr, register size_t size, register char *data)
234 {
235 register char *src;
236
237 src = (char *)addr;
238 while (size-- > 0)
239 *data++ = *src++;
240 }
241
242 /*
243 * Write bytes to kernel address space for debugger.
244 */
245 void
db_write_bytes(vaddr_t addr,register size_t size,register const char * data)246 db_write_bytes(vaddr_t addr, register size_t size, register const char *data)
247 {
248 register char *dst;
249
250 dst = (char *)addr;
251 while (size-- > 0)
252 *dst++ = *data++;
253 alpha_pal_imb();
254 }
255
256 void
cpu_Debugger(void)257 cpu_Debugger(void)
258 {
259
260 __asm volatile("call_pal 0x81"); /* bugchk */
261 }
262
263 /*
264 * Alpha-specific ddb commands:
265 *
266 * cpu tell DDB to use register state from the
267 * CPU specified (MULTIPROCESSOR)
268 */
269
270 #if defined(MULTIPROCESSOR)
271 void
db_mach_cpu(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)272 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char * modif)
273 {
274 struct cpu_info *ci;
275
276 if (!have_addr) {
277 cpu_debug_dump();
278 return;
279 }
280
281 if (addr < 0 || addr >= ALPHA_MAXPROCS) {
282 db_printf("CPU %ld out of range\n", addr);
283 return;
284 }
285
286 ci = cpu_info[addr];
287 if (ci == NULL) {
288 db_printf("CPU %ld is not configured\n", addr);
289 return;
290 }
291
292 if (ci != curcpu()) {
293 if ((ci->ci_flags & CPUF_PAUSED) == 0) {
294 db_printf("CPU %ld not paused\n", addr);
295 return;
296 }
297 }
298
299 if (ci->ci_db_regs == NULL) {
300 db_printf("CPU %ld has no register state\n", addr);
301 return;
302 }
303
304 db_printf("Using CPU %ld\n", addr);
305 ddb_regp = ci->ci_db_regs;
306 }
307 #endif /* MULTIPROCESSOR */
308
309 /*
310 * Map Alpha register numbers to trapframe/db_regs_t offsets.
311 */
312 static int reg_to_frame[32] = {
313 FRAME_V0,
314 FRAME_T0,
315 FRAME_T1,
316 FRAME_T2,
317 FRAME_T3,
318 FRAME_T4,
319 FRAME_T5,
320 FRAME_T6,
321 FRAME_T7,
322
323 FRAME_S0,
324 FRAME_S1,
325 FRAME_S2,
326 FRAME_S3,
327 FRAME_S4,
328 FRAME_S5,
329 FRAME_S6,
330
331 FRAME_A0,
332 FRAME_A1,
333 FRAME_A2,
334 FRAME_A3,
335 FRAME_A4,
336 FRAME_A5,
337
338 FRAME_T8,
339 FRAME_T9,
340 FRAME_T10,
341 FRAME_T11,
342 FRAME_RA,
343 FRAME_T12,
344 FRAME_AT,
345 FRAME_GP,
346 FRAME_SP,
347 -1, /* zero */
348 };
349
350 u_long
db_register_value(db_regs_t * regs,int regno)351 db_register_value(db_regs_t *regs, int regno)
352 {
353
354 if (regno > 31 || regno < 0) {
355 db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno);
356 return (0);
357 }
358
359 if (regno == 31)
360 return (0);
361
362 return (regs->tf_regs[reg_to_frame[regno]]);
363 }
364
365 /*
366 * Support functions for software single-step.
367 */
368
369 bool
db_inst_call(int ins)370 db_inst_call(int ins)
371 {
372 alpha_instruction insn;
373
374 insn.bits = ins;
375 return ((insn.branch_format.opcode == op_bsr) ||
376 ((insn.jump_format.opcode == op_j) &&
377 (insn.jump_format.action & 1)));
378 }
379
380 bool
db_inst_return(int ins)381 db_inst_return(int ins)
382 {
383 alpha_instruction insn;
384
385 insn.bits = ins;
386 return ((insn.jump_format.opcode == op_j) &&
387 (insn.jump_format.action == op_ret));
388 }
389
390 bool
db_inst_trap_return(int ins)391 db_inst_trap_return(int ins)
392 {
393 alpha_instruction insn;
394
395 insn.bits = ins;
396 return ((insn.pal_format.opcode == op_pal) &&
397 (insn.pal_format.function == PAL_OSF1_rti));
398 }
399
400 bool
db_inst_branch(int ins)401 db_inst_branch(int ins)
402 {
403 alpha_instruction insn;
404
405 insn.bits = ins;
406 switch (insn.branch_format.opcode) {
407 case op_j:
408 case op_br:
409 case op_fbeq:
410 case op_fblt:
411 case op_fble:
412 case op_fbne:
413 case op_fbge:
414 case op_fbgt:
415 case op_blbc:
416 case op_beq:
417 case op_blt:
418 case op_ble:
419 case op_blbs:
420 case op_bne:
421 case op_bge:
422 case op_bgt:
423 return (true);
424 }
425
426 return (false);
427 }
428
429 bool
db_inst_unconditional_flow_transfer(int ins)430 db_inst_unconditional_flow_transfer(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 bool
454 db_inst_spill(int ins, int regn)
455 {
456 alpha_instruction insn;
457
458 insn.bits = ins;
459 return ((insn.mem_format.opcode == op_stq) &&
460 (insn.mem_format.rd == regn));
461 }
462 #endif
463
464 bool
db_inst_load(int ins)465 db_inst_load(int ins)
466 {
467 alpha_instruction insn;
468
469 insn.bits = ins;
470
471 /* Loads. */
472 if (insn.mem_format.opcode == op_ldbu ||
473 insn.mem_format.opcode == op_ldq_u ||
474 insn.mem_format.opcode == op_ldwu)
475 return (true);
476 if ((insn.mem_format.opcode >= op_ldf) &&
477 (insn.mem_format.opcode <= op_ldt))
478 return (true);
479 if ((insn.mem_format.opcode >= op_ldl) &&
480 (insn.mem_format.opcode <= op_ldq_l))
481 return (true);
482
483 /* Prefetches. */
484 if (insn.mem_format.opcode == op_special) {
485 /* Note: MB is treated as a store. */
486 if ((insn.mem_format.displacement == (short)op_fetch) ||
487 (insn.mem_format.displacement == (short)op_fetch_m))
488 return (true);
489 }
490
491 return (false);
492 }
493
494 bool
db_inst_store(int ins)495 db_inst_store(int ins)
496 {
497 alpha_instruction insn;
498
499 insn.bits = ins;
500
501 /* Stores. */
502 if (insn.mem_format.opcode == op_stw ||
503 insn.mem_format.opcode == op_stb ||
504 insn.mem_format.opcode == op_stq_u)
505 return (true);
506 if ((insn.mem_format.opcode >= op_stf) &&
507 (insn.mem_format.opcode <= op_stt))
508 return (true);
509 if ((insn.mem_format.opcode >= op_stl) &&
510 (insn.mem_format.opcode <= op_stq_c))
511 return (true);
512
513 /* Barriers. */
514 if (insn.mem_format.opcode == op_special) {
515 if (insn.mem_format.displacement == op_mb)
516 return (true);
517 }
518
519 return (false);
520 }
521
522 db_addr_t
db_branch_taken(int ins,db_addr_t pc,db_regs_t * regs)523 db_branch_taken(int ins, db_addr_t pc, db_regs_t *regs)
524 {
525 long signed_immediate;
526 alpha_instruction insn;
527 db_addr_t newpc;
528
529 insn.bits = ins;
530 switch (insn.branch_format.opcode) {
531 /*
532 * Jump format: target PC is (contents of instruction's "RB") & ~3.
533 */
534 case op_j:
535 newpc = db_register_value(regs, insn.jump_format.rb) & ~3;
536 break;
537
538 /*
539 * Branch format: target PC is
540 * (new PC) + (4 * sign-ext(displacement)).
541 */
542 case op_br:
543 case op_fbeq:
544 case op_fblt:
545 case op_fble:
546 case op_bsr:
547 case op_fbne:
548 case op_fbge:
549 case op_fbgt:
550 case op_blbc:
551 case op_beq:
552 case op_blt:
553 case op_ble:
554 case op_blbs:
555 case op_bne:
556 case op_bge:
557 case op_bgt:
558 signed_immediate = insn.branch_format.displacement;
559 newpc = (pc + 4) + (signed_immediate << 2);
560 break;
561
562 default:
563 printf("DDB: db_inst_branch_taken on non-branch!\n");
564 newpc = pc; /* XXX */
565 }
566
567 return (newpc);
568 }
569