Pull in geocast mips ddb improvements and start bringing in kgdb support.

Add ddb support for QED opcodes, fill in enough routines so "next" usually
works, kdbpoke support for any size.  Add callback that ports can hook when
entering and leaving ddb.  This can be used for things like turning
off watchdogs while in ddb.
This commit is contained in:
jeffs 2000-07-17 07:04:19 +00:00
parent fc1ba82306
commit 116a6f8233
5 changed files with 550 additions and 109 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.mips,v 1.26 2000/05/23 04:21:39 soren Exp $
# $NetBSD: files.mips,v 1.27 2000/07/17 07:04:19 jeffs Exp $
#
defopt opt_cputype.h NOTYET # MIPS1 MIPS3 MIPS4 NOFPU
@ -9,9 +9,10 @@ defopt opt_cputype.h NOTYET # MIPS1 MIPS3 MIPS4 NOFPU
defopt opt_mips_cache.h MIPS3_L2CACHE_ABSENT
MIPS3_L2CACHE_PRESENT
file arch/mips/mips/db_disasm.c ddb
file arch/mips/mips/db_interface.c ddb
file arch/mips/mips/db_interface.c ddb | kgdb
file arch/mips/mips/db_trace.c ddb
file arch/mips/mips/cpu_exec.c
file arch/mips/mips/kgdb_machdep.c kgdb
file arch/mips/mips/mem.c
file arch/mips/mips/mips_mcclock.c mcclock # CPU speed via mcclock
file arch/mips/mips/pmap.c

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_machdep.h,v 1.9 2000/06/26 14:59:02 mrg Exp $ */
/* $NetBSD: db_machdep.h,v 1.10 2000/07/17 07:04:19 jeffs Exp $ */
/*
* Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author)
@ -55,20 +55,21 @@ db_regs_t ddb_regs; /* register state */
if ((db_get_value((regs)->f_regs[PC], sizeof(int), FALSE) & \
0xfc00003f) == 0xd) \
(regs)->f_regs[PC] += BKPT_SIZE; \
} while(0) /* XXX endianness? */
} while(0)
#define BKPT_INST 0x0001000D /* XXX endianness? */
/* Similar to PC_ADVANCE(), except only advance on cpu_Debugger()'s bpt */
#define PC_BREAK_ADVANCE(regs) do { \
if (db_get_value((regs)->f_regs[PC], sizeof(int), FALSE) == 0xd) \
(regs)->f_regs[PC] += BKPT_SIZE; \
} while(0)
#define BKPT_INST 0x0001000D
#define BKPT_SIZE (4) /* size of breakpoint inst */
#define BKPT_SET(inst) (BKPT_INST)
#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAK)
#define IS_WATCHPOINT_TRAP(type, code) (0) /* XXX mips3 watchpoint */
#define inst_trap_return(ins) ((ins)&0)
#define inst_return(ins) ((ins)&0)
#define inst_load(ins) 0
#define inst_store(ins) 0
/*
* Interface to disassembly (shared with mdb)
*/
@ -79,17 +80,30 @@ db_addr_t db_disasm_insn __P((int insn, db_addr_t loc, boolean_t altfmt));
* Entrypoints to DDB for kernel, keyboard drivers, init hook
*/
void kdb_kbd_trap __P((db_regs_t *));
void db_set_ddb_regs __P((int type, mips_reg_t *));
int kdb_trap __P((int type, mips_reg_t *));
void db_machine_init __P((void));
/*
* Constants for KGDB.
*/
typedef mips_reg_t kgdb_reg_t;
#define KGDB_NUMREGS 90
#define KGDB_BUFLEN 1024
/*
* MIPS cpus have no hardware single-step.
*/
#define SOFTWARE_SSTEP
#define inst_trap_return(ins) ((ins)&0)
boolean_t inst_branch __P((int inst));
boolean_t inst_call __P((int inst));
boolean_t inst_return __P((int inst));
boolean_t inst_load __P((int inst));
boolean_t inst_store __P((int inst));
boolean_t inst_unconditional_flow_transfer __P((int inst));
db_addr_t branch_taken __P((int inst, db_addr_t pc, db_regs_t *regs));
db_addr_t next_instr_address __P((db_addr_t pc, boolean_t bd));
@ -99,4 +113,9 @@ db_addr_t next_instr_address __P((db_addr_t pc, boolean_t bd));
*/
#define DB_MACHINE_COMMANDS
/*
* Hook to MIPS platform code to allow management of kernel breakpoints.
*/
extern void (*db_mach_break_hook)(int);
#endif /* _MIPS_DB_MACHDEP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_disasm.c,v 1.5 1999/12/27 21:12:25 castor Exp $ */
/* $NetBSD: db_disasm.c,v 1.6 2000/07/17 07:04:19 jeffs Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -76,6 +76,10 @@ static char *spec_name[64] = {
/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
};
static char *spec2_name[4] = { /* QED RM4650, R5000, etc. */
/* 0 */ "mad", "madu", "mul", "spec3"
};
static char *bcond_name[32] = {
/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
@ -251,6 +255,21 @@ db_disasm_insn(insn, loc, altfmt)
}
break;
case OP_SPECIAL2:
if (i.RType.func == OP_MUL)
db_printf("%s\t%s,%s,%s",
spec2_name[i.RType.func & 0x3],
reg_name[i.RType.rd],
reg_name[i.RType.rs],
reg_name[i.RType.rt]);
else
db_printf("%s\t%s,%s",
spec2_name[i.RType.func & 0x3],
reg_name[i.RType.rs],
reg_name[i.RType.rt]);
break;
case OP_BCOND:
db_printf("%s\t%s,", bcond_name[i.IType.rt],
reg_name[i.IType.rs]);
@ -412,6 +431,14 @@ db_disasm_insn(insn, loc, altfmt)
i.IType.imm);
break;
case OP_CACHE:
db_printf("%s\t0x%x,0x%x(%s)",
op_name[i.IType.op],
i.IType.rt,
i.IType.imm,
reg_name[i.IType.rs]);
break;
case OP_ADDI:
case OP_DADDI:
case OP_ADDIU:
@ -432,7 +459,7 @@ db_disasm_insn(insn, loc, altfmt)
db_printf("\n");
if (bdslot) {
db_printf("\t\tbdslot:\t");
db_print_loc_and_inst(loc+4);
db_disasm(loc+4, FALSE);
return (loc + 8);
}
return (loc + 4);

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_interface.c,v 1.29 2000/06/29 08:11:27 mrg Exp $ */
/* $NetBSD: db_interface.c,v 1.30 2000/07/17 07:04:20 jeffs Exp $ */
/*
* Mach Operating System
@ -46,21 +46,29 @@
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#ifndef KGDB
#include <ddb/db_command.h>
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#endif
int db_active = 0;
mips_reg_t kdbaux[11]; /* XXX struct switchframe: better inside curpcb? XXX */
void (*db_mach_break_hook)(int);
void db_tlbdump_cmd __P((db_expr_t, int, db_expr_t, char *));
void db_kvtophys_cmd __P((db_expr_t, int, db_expr_t, char *));
void kdbpoke __P((vaddr_t addr, int newval));
vaddr_t MachEmulateBranch __P((struct frame *, vaddr_t, unsigned, int));
static void kdbpoke_4 __P((vaddr_t addr, int newval));
static void kdbpoke_2 __P((vaddr_t addr, short newval));
static void kdbpoke_1 __P((vaddr_t addr, char newval));
static short kdbpeek_2 __P((vaddr_t addr));
static char kdbpeek_1 __P((vaddr_t addr));
extern vaddr_t MachEmulateBranch __P((struct frame *, vaddr_t, unsigned, int));
paddr_t kvtophys __P((vaddr_t));
extern paddr_t kvtophys __P((vaddr_t));
#ifdef DDB_TRACE
int
@ -72,27 +80,43 @@ kdbpeek(addr)
return *(int *)addr;
}
#endif
static short
kdbpeek_2(addr)
vaddr_t addr;
{
return *(short *)addr;
}
static char
kdbpeek_1(addr)
vaddr_t addr;
{
return *(char *)addr;
}
/*
* kdbpoke -- write a value to a kernel virtual address.
* XXX should handle KSEG2 addresses and check for unmapped pages.
* XXX user-space addresess?
*/
void
kdbpoke(vaddr_t addr, int newval)
static void
kdbpoke_4(vaddr_t addr, int newval)
{
*(int*) addr = newval;
wbflush();
#ifdef MIPS1
if (cpu_arch == 1)
mips1_FlushICache((vaddr_t) addr, sizeof(int));
#endif
#ifdef MIPS3
if (cpu_arch == 3) {
mips3_HitFlushDCache((vaddr_t) addr, sizeof(int));
mips3_FlushICache((vaddr_t) addr, sizeof(int));
}
#endif
static void
kdbpoke_2(vaddr_t addr, short newval)
{
*(short*) addr = newval;
wbflush();
}
static void
kdbpoke_1(vaddr_t addr, char newval)
{
*(char*) addr = newval;
wbflush();
}
#if 0 /* UNUSED */
@ -110,6 +134,7 @@ kdb_kbd_trap(tf)
}
#endif
#ifndef KGDB
int
kdb_trap(type, tfp)
int type;
@ -132,51 +157,15 @@ kdb_trap(type, tfp)
}
#endif
/* Should switch to kdb`s own stack here. */
if (type & T_USER)
*f = *(struct frame *)curproc->p_md.md_regs;
else {
/* Synthetic full scale register context when trap happens */
f->f_regs[AST] = tfp[0];
f->f_regs[V0] = tfp[1];
f->f_regs[V1] = tfp[2];
f->f_regs[A0] = tfp[3];
f->f_regs[A1] = tfp[4];
f->f_regs[A2] = tfp[5];
f->f_regs[A3] = tfp[6];
f->f_regs[T0] = tfp[7];
f->f_regs[T1] = tfp[8];
f->f_regs[T2] = tfp[9];
f->f_regs[T3] = tfp[10];
f->f_regs[T4] = tfp[11];
f->f_regs[T5] = tfp[12];
f->f_regs[T6] = tfp[13];
f->f_regs[T7] = tfp[14];
f->f_regs[T8] = tfp[15];
f->f_regs[T9] = tfp[16];
f->f_regs[RA] = tfp[17];
f->f_regs[SR] = tfp[18];
f->f_regs[MULLO] = tfp[19];
f->f_regs[MULHI] = tfp[20];
f->f_regs[PC] = tfp[21];
f->f_regs[S0] = kdbaux[0];
f->f_regs[S1] = kdbaux[1];
f->f_regs[S2] = kdbaux[2];
f->f_regs[S3] = kdbaux[3];
f->f_regs[S4] = kdbaux[4];
f->f_regs[S5] = kdbaux[5];
f->f_regs[S6] = kdbaux[6];
f->f_regs[S7] = kdbaux[7];
f->f_regs[SP] = kdbaux[8];
f->f_regs[S8] = kdbaux[9];
f->f_regs[GP] = kdbaux[10];
}
db_set_ddb_regs(type, tfp);
db_active++;
if (db_mach_break_hook) db_mach_break_hook(db_active);
cnpollc(1);
db_trap(type & ~T_USER, 0 /*code*/);
cnpollc(0);
db_active--;
if (db_mach_break_hook) db_mach_break_hook(db_active);
if (type & T_USER)
*(struct frame *)curproc->p_md.md_regs = *f;
@ -225,7 +214,56 @@ cpu_Debugger()
{
asm("break");
}
#endif /* !KGDB */
void
db_set_ddb_regs(type, tfp)
int type;
mips_reg_t *tfp;
{
struct frame *f = (struct frame *)&ddb_regs;
/* Should switch to kdb`s own stack here. */
if (type & T_USER)
*f = *(struct frame *)curproc->p_md.md_regs;
else {
/* Synthetic full scale register context when trap happens */
f->f_regs[AST] = tfp[0];
f->f_regs[V0] = tfp[1];
f->f_regs[V1] = tfp[2];
f->f_regs[A0] = tfp[3];
f->f_regs[A1] = tfp[4];
f->f_regs[A2] = tfp[5];
f->f_regs[A3] = tfp[6];
f->f_regs[T0] = tfp[7];
f->f_regs[T1] = tfp[8];
f->f_regs[T2] = tfp[9];
f->f_regs[T3] = tfp[10];
f->f_regs[T4] = tfp[11];
f->f_regs[T5] = tfp[12];
f->f_regs[T6] = tfp[13];
f->f_regs[T7] = tfp[14];
f->f_regs[T8] = tfp[15];
f->f_regs[T9] = tfp[16];
f->f_regs[RA] = tfp[17];
f->f_regs[SR] = tfp[18];
f->f_regs[MULLO] = tfp[19];
f->f_regs[MULHI] = tfp[20];
f->f_regs[PC] = tfp[21];
f->f_regs[S0] = kdbaux[0];
f->f_regs[S1] = kdbaux[1];
f->f_regs[S2] = kdbaux[2];
f->f_regs[S3] = kdbaux[3];
f->f_regs[S4] = kdbaux[4];
f->f_regs[S5] = kdbaux[5];
f->f_regs[S6] = kdbaux[6];
f->f_regs[S7] = kdbaux[7];
f->f_regs[SP] = kdbaux[8];
f->f_regs[S8] = kdbaux[9];
f->f_regs[GP] = kdbaux[10];
}
}
/*
* Read bytes from kernel address space for debugger.
@ -238,25 +276,10 @@ db_read_bytes(addr, size, data)
{
while (size >= 4)
*((int*)data)++ = kdbpeek(addr), addr += 4, size -= 4;
if (size) {
unsigned tmp;
char *dst = (char*)data;
tmp = kdbpeek(addr);
while (size--) {
#if BYTE_ORDER == BIG_ENDIAN
int shift = 24;
/* want highest -> lowest byte */
*dst++ = (tmp >> shift) & 0xFF;
shift -= 8;
#else /* BYTE_ORDER == LITTLE_ENDIAN */
*dst++ = tmp & 0xFF;
tmp >>= 8;
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
}
}
while (size >= 2)
*((short*)data)++ = kdbpeek_2(addr), addr += 2, size -= 2;
if (size == 1)
*((char*)data)++ = kdbpeek_1(addr);
}
/*
@ -268,27 +291,41 @@ db_write_bytes(addr, size, data)
size_t size;
char *data;
{
vaddr_t p = addr;
size_t n = size;
#ifdef DEBUG_DDB
printf("db_write_bytes(%lx, %d, %p, val %x)\n", addr, size, data,
(addr &3 ) == 0? *(u_int*)addr: -1);
#endif
while (size >= 4)
kdbpoke(addr++, *(int*)data), addr += 4, size -= 4;
if (size) {
unsigned tmp = kdbpeek(addr), tmp1 = 0;
char *src = (char*)data;
tmp >>= (size << 3);
tmp <<= (size << 3);
while (size--) {
tmp1 <<= 8;
tmp1 |= src[size] & 0xff;
while (n >= 4) {
kdbpoke_4(p, *(int*)data);
p += 4;
data += 4;
n -= 4;
}
kdbpoke(addr, tmp|tmp1);
if (n >= 2) {
kdbpoke_2(p, *(short*)data);
p += 2;
data += 2;
n -= 2;
}
if (n == 1) {
kdbpoke_1(p, *(char*)data);
}
#ifdef MIPS1
if (cpu_arch == 1)
mips1_FlushICache((vaddr_t) addr, size);
#endif
#ifdef MIPS3
if (cpu_arch >= 3) {
MachHitFlushDCache((vaddr_t) addr, size);
MachFlushICache((vaddr_t) addr, size);
}
#endif
}
#ifndef KGDB
void
db_tlbdump_cmd(addr, have_addr, count, modif)
db_expr_t addr;
@ -371,6 +408,8 @@ db_machine_init()
db_machine_commands_install(mips_db_command_table);
}
#endif /* !KGDB */
/*
* Determine whether the instruction involves a delay slot.
*/
@ -406,6 +445,11 @@ inst_branch(inst)
delay = 1;
}
break;
case OP_SPECIAL:
if (i.RType.op == OP_JR || i.RType.op == OP_JALR)
delay = 1;
break;
}
return delay;
}
@ -422,7 +466,8 @@ inst_call(inst)
i.word = inst;
if (i.JType.op == OP_SPECIAL
&& (i.RType.func == OP_JR || i.RType.func == OP_JALR))
&& ((i.RType.func == OP_JR && i.RType.rs != 31) ||
i.RType.func == OP_JALR))
call = 1;
else if (i.JType.op == OP_JAL)
call = 1;
@ -431,6 +476,23 @@ inst_call(inst)
return call;
}
/*
* Determine whether the instruction returns from a function (j ra). The
* compiler can use this construct for other jumps, but usually will not.
* This lets the ddb "next" command to work (also need inst_trap_return()).
*/
boolean_t
inst_return(inst)
int inst;
{
InstFmt i;
i.word = inst;
return (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR &&
i.RType.rs == 31);
}
/*
* Determine whether the instruction makes a jump.
*/
@ -442,10 +504,67 @@ inst_unconditional_flow_transfer(inst)
boolean_t jump;
i.word = inst;
jump = (i.JType.op == OP_J);
jump = (i.JType.op == OP_J) ||
(i.JType.op == OP_SPECIAL && i.RType.func == OP_JR);
return jump;
}
/*
* Determine whether the instruction is a load/store as appropriate.
*/
boolean_t
inst_load(inst)
int inst;
{
InstFmt i;
i.word = inst;
switch (i.JType.op) {
case OP_LWC1:
case OP_LB:
case OP_LH:
case OP_LW:
case OP_LD:
case OP_LBU:
case OP_LHU:
case OP_LWU:
case OP_LDL:
case OP_LDR:
case OP_LWL:
case OP_LWR:
case OP_LL:
return 1;
default:
return 0;
}
}
boolean_t
inst_store(inst)
int inst;
{
InstFmt i;
i.word = inst;
switch (i.JType.op) {
case OP_SWC1:
case OP_SB:
case OP_SH:
case OP_SW:
case OP_SD:
case OP_SDL:
case OP_SDR:
case OP_SWL:
case OP_SWR:
case OP_SCD:
return 1;
default:
return 0;
}
}
/*
* Return the next pc if the given branch is taken.
* MachEmulateBranch() runs analysis for branch delay slot.
@ -465,18 +584,25 @@ branch_taken(inst, pc, regs)
}
/*
* Return the next pc of arbitrary instructions.
* MachEmulateBranch() runs analysis for branch delay slots.
* Return the next pc of an arbitrary instruction.
*/
db_addr_t
next_instr_address(pc, bd)
db_addr_t pc;
boolean_t bd;
{
vaddr_t ra;
unsigned fpucsr;
unsigned ins;
fpucsr = (curproc) ? curproc->p_addr->u_pcb.pcb_fpregs.r_regs[32] : 0;
ra = MachEmulateBranch((struct frame *)&ddb_regs, pc, fpucsr, 1);
return ra;
if (bd == FALSE)
return (pc + 4);
if (pc < MIPS_KSEG0_START)
ins = fuiword((void *)pc);
else
ins = *(unsigned *)pc;
if (inst_branch(ins) || inst_call(ins) || inst_return(ins))
return (pc + 4);
return (pc);
}

View File

@ -0,0 +1,268 @@
/* $NetBSD: kgdb_machdep.c,v 1.1 2000/07/17 07:04:20 jeffs Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1996 Matthias Pfaller.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Matthias Pfaller.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_ddb.h"
#if defined(DDB)
#error "Can't build DDB and KGDB together."
#endif
/*
* Machine-dependent functions for remote KGDB. Originally written
* for NetBSD/pc532 by Matthias Pfaller. Modified for NetBSD/i386
* by Jason R. Thorpe. Modified for NetBSD/mips by Ethan Solomita
*/
#include "opt_cputype.h" /* which mips CPUs do we support? */
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/reboot.h>
#include <sys/kgdb.h>
#include <vm/vm.h>
#include <mips/pte.h>
#include <mips/cpu.h>
#include <mips/locore.h>
#include <mips/mips_opcode.h>
#include <mips/reg.h>
#include <mips/trap.h>
#include <dev/cons.h>
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
extern int kvacc __P((vaddr_t));
/*
* Determine if the memory at va..(va+len) is valid.
*/
int
kgdb_acc(va, len)
vaddr_t va;
size_t len;
{
vaddr_t last_va;
last_va = va + len + NBPG - 1;
va &= ~PGOFSET;
last_va &= ~PGOFSET;
for (; va < last_va; va += NBPG) {
if (kvacc(va) == 0)
return 0;
}
return (1);
}
/*
* Translate a trap number into a unix compatible signal value.
* (gdb only understands unix signal numbers).
*/
int
kgdb_signal(type)
int type;
{
switch (type) {
case T_TLB_MOD:
case T_TLB_MOD+T_USER:
case T_TLB_LD_MISS:
case T_TLB_ST_MISS:
case T_TLB_LD_MISS+T_USER:
case T_TLB_ST_MISS+T_USER:
case T_ADDR_ERR_LD: /* misaligned access */
case T_ADDR_ERR_ST: /* misaligned access */
case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */
case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */
case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */
case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */
case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */
return (SIGSEGV);
case T_BREAK:
case T_BREAK+T_USER:
return (SIGTRAP);
case T_RES_INST+T_USER:
case T_COP_UNUSABLE+T_USER:
return (SIGILL);
case T_FPE+T_USER:
case T_OVFLOW+T_USER:
return (SIGFPE);
default:
return (SIGEMT);
}
}
mips_reg_t kgdb_cause, kgdb_vaddr; /* set by trap() */
/*
* Translate the values stored in the db_regs_t struct to the format
* understood by gdb.
*/
void
kgdb_getregs(regs, gdb_regs)
db_regs_t *regs;
kgdb_reg_t *gdb_regs;
{
struct frame *f = (struct frame *)regs;
bzero(gdb_regs, KGDB_NUMREGS * sizeof(kgdb_reg_t));
gdb_regs[ 1] = f->f_regs[AST]; /* AT */
gdb_regs[ 2] = f->f_regs[V0]; /* V0 */
gdb_regs[ 3] = f->f_regs[V1]; /* V1 */
gdb_regs[ 4] = f->f_regs[A0]; /* A0 */
gdb_regs[ 5] = f->f_regs[A1]; /* A1 */
gdb_regs[ 6] = f->f_regs[A2]; /* A2 */
gdb_regs[ 7] = f->f_regs[A3]; /* A3 */
gdb_regs[ 8] = f->f_regs[T0]; /* T0 */
gdb_regs[ 9] = f->f_regs[T1]; /* T1 */
gdb_regs[10] = f->f_regs[T2]; /* T2 */
gdb_regs[11] = f->f_regs[T3]; /* T3 */
gdb_regs[12] = f->f_regs[T4]; /* T4 */
gdb_regs[13] = f->f_regs[T5]; /* T5 */
gdb_regs[14] = f->f_regs[T6]; /* T6 */
gdb_regs[15] = f->f_regs[T7]; /* T7 */
gdb_regs[16] = f->f_regs[S0]; /* S0 */
gdb_regs[17] = f->f_regs[S1]; /* S1 */
gdb_regs[18] = f->f_regs[S2]; /* S2 */
gdb_regs[19] = f->f_regs[S3]; /* S3 */
gdb_regs[20] = f->f_regs[S4]; /* S4 */
gdb_regs[21] = f->f_regs[S5]; /* S5 */
gdb_regs[22] = f->f_regs[S6]; /* S6 */
gdb_regs[23] = f->f_regs[S7]; /* S7 */
gdb_regs[24] = f->f_regs[T8]; /* T8 */
gdb_regs[25] = f->f_regs[T9]; /* T9 */
gdb_regs[28] = f->f_regs[GP]; /* GP */
gdb_regs[29] = f->f_regs[SP]; /* SP */
gdb_regs[30] = f->f_regs[S8]; /* S8 */
gdb_regs[31] = f->f_regs[RA]; /* RA */
gdb_regs[32] = f->f_regs[SR]; /* SR */
gdb_regs[33] = f->f_regs[MULLO]; /* MULLO */
gdb_regs[34] = f->f_regs[MULHI]; /* MULHI */
gdb_regs[35] = kgdb_vaddr; /* BAD VADDR */
gdb_regs[36] = kgdb_cause; /* CAUSE */
gdb_regs[37] = f->f_regs[PC]; /* PC */
}
/*
* Reverse the above.
*/
void
kgdb_setregs(regs, gdb_regs)
db_regs_t *regs;
kgdb_reg_t *gdb_regs;
{
struct frame *f = (struct frame *)regs;
f->f_regs[PC] = gdb_regs[37]; /* PC */
}
/*
* Trap into kgdb to wait for debugger to connect,
* noting on the console why nothing else is going on.
*/
void
kgdb_connect(verbose)
int verbose;
{
verbose = 1; /* ETHAN !!! */
if (kgdb_dev < 0)
return;
if (verbose)
printf("kgdb waiting...");
asm("break");
if (verbose)
printf("connected.\n");
kgdb_debug_panic = 1;
}
/*
* Decide what to do on panic.
* (This is called by panic, like Debugger())
*/
void
kgdb_panic()
{
if (kgdb_dev >= 0 && kgdb_debug_panic) {
printf("entering kgdb\n");
kgdb_connect(kgdb_active == 0);
}
}