4.3BSD-Reno/src/sys/tahoe/kdb_machdep.c
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)kdb_machdep.c 7.9 (Berkeley) 4/3/90
*/
#include "param.h"
#include "conf.h"
#include "user.h"
#include "proc.h"
#include "systm.h"
#include "reboot.h"
#include "vmmac.h"
#include "ioctl.h"
#include "tty.h"
#include "cpu.h"
#include "mtpr.h"
#include "psl.h"
#include "pte.h"
#include "reg.h"
#include "trap.h"
#include "kdbparam.h"
#define KDBSPACE 1024 /* 1K of memory for breakpoint table */
static char kdbbuf[KDBSPACE];
static char *kdbend = kdbbuf;
int kdb_escape; /* allow kdb to be entered on console escape */
int kdb_panic; /* allow kdb to be entered on panic/trap */
/*
* Dynamically allocate space for the debugger.
*/
char *
kdbmalloc(n)
u_int n;
{
char *old = kdbend;
if (kdbend+n >= kdbbuf+KDBSPACE) {
printf("kdb: Out of space\n");
return ((char *)-1);
}
kdbend += n;
return (old);
}
/*
* Initialize the kernel debugger.
*/
kdb_init()
{
char *symtab, *strtab;
int strsize;
extern int end;
kdbsetup();
if (bootesym > (char *)&end) {
symtab = (char *)&end + sizeof (int);
#define symsize *(int *)&end
strtab = symtab + symsize;
strsize = roundup(*(int *)strtab, sizeof (int));
if (strtab + strsize == bootesym) {
printf("[Preserving %d bytes of symbol information]\n",
symsize + strsize);
kdbsetsym(symtab, strtab, strtab, strsize);
} else
printf("kdb_init: bad bootesym %x, calculated %x\n",
bootesym, strtab + strsize);
}
/*
* Transfer control to the debugger when magic console sequence
* is typed only if the system was booted with RB_KDB and the trap
* enable flag (RB_NOYSNC) set.
*/
if ((boothowto&(RB_KDB|RB_NOSYNC)) == (RB_KDB|RB_NOSYNC))
kdb_escape = 1;
if (boothowto&RB_KDB)
kdb_panic = 1;
/*
* If boot flags indicate, force entry into the debugger.
*/
if ((boothowto&(RB_HALT|RB_KDB)) == (RB_HALT|RB_KDB))
setsoftkdb();
#undef symsize
}
int kdbactive = 0;
#define ESC CTRL('[')
/*
* Process a keyboard interrupt from the console.
* We look for an escape sequence which signals
* a request to enter the debugger.
*/
kdbrintr(c, tp)
int c;
struct tty *tp;
{
static int escape = 0;
/*
* Transfer control to the debugger only if the
* system was booted with RB_KDB and the trap
* enable flag (RB_NOYSNC) is set.
*/
if (kdb_escape == 0)
return (0);
c &= 0177; /* strip parity also */
if (!escape)
return (c == ESC && ++escape);
escape = 0;
if ((c != 'k' && c != 'K' && c != CTRL('k'))) {
(*linesw[tp->t_line].l_rint)(ESC, tp);
return (0);
}
if (!kdbactive)
setsoftkdb();
return (1);
}
#define TYPE SP+1
#define CODE PC-1
#define USER 040
static caddr_t kdbnofault; /* label for peek & poke */
/*
* Field a kdb-related trap or fault.
*/
kdb_trap(apsl)
register int *apsl;
{
register int *locr0, type;
int code, retval, kstack = 0;
static int prevtype = -1, prevcode;
extern char *trap_type[];
/*
* Allow panic if the debugger is not enabled.
*/
if (kdb_panic == 0)
return (0);
locr0 = apsl - PS;
type = locr0[TYPE];
/*
* If we were invoked from kernel stack and are now back
* on the interrupt stack, restore the saved type and code.
* If we return, trap will have the correct type.
*/
if (type == T_KDBTRAP && prevtype != -1) {
locr0[TYPE] = type = prevtype;
locr0[CODE] = prevcode;
prevtype = -1;
}
code = locr0[CODE];
if (type != T_TRCTRAP && type != T_BPTFLT) {
/*
* Catch traps from kdbpeek and kdbpoke and perform
* non-local goto to error label setup in routines.
*/
if (kdbnofault) {
locr0[PC] = (int)kdbnofault;
return (1);
}
type &= ~USER;
}
/*
* We prefer to run the debugger from the interrupt stack to
* avoid overflowing the kernel stack. Thus, if we're not
* currently on the interrupt stack and the ipl is low, schedule
* a software interrupt to force reentry on the interrupt stack
* immediately after the rei that'll take place on return.
*/
if ((movpsl()&PSL_IS) == 0) {
int s = splhigh();
if (s < KDB_IPL) {
prevtype = type, prevcode = code;
setsoftkdb();
return (1);
}
splx(s);
kstack++;
}
getpcb(locr0);
/*
* Mark debugger active and initiate input
* polling in the console device driver.
*/
cnpoll(kdbactive = 1);
retval = kdb(type, code, noproc ? (struct proc *)0 : u.u_procp, kstack);
cnpoll(kdbactive = 0);
setpcb(locr0);
/*
* Return 1 (return from trap) if this was a kdb trap
* (from breakpoint, keyboard or panic)
* unless a panic has been requested (kdb returns 0).
* Otherwise, return 0 (panic because of trap).
*/
return ((type == T_KDBTRAP && retval != 0) ||
type == T_TRCTRAP || type == T_BPTFLT);
}
static char *codenames[] = {
"code = 0", /* not defined */
"integer overflow",
"integer divide by zero",
"floating divide by zero",
"floating overflow",
"float underflow"
};
#define NCODES (sizeof (codenames) / sizeof (codenames[0]))
/*
* Announce a trap.
*/
kdbprinttrap(type, code)
long type, code;
{
extern int TRAP_TYPES;
extern char *trap_type[];
if (type != T_TRCTRAP && type != T_BPTFLT) {
if (type < TRAP_TYPES && trap_type[type])
printf(trap_type[type]);
else
printf("trap type %d", type);
if (type == T_ARITHTRAP && (unsigned)code < NCODES)
printf(", %s", code);
else if (code)
printf(", code = %x", code);
printf("\n");
}
}
/*
* Read character from the console.
*/
kdbreadc(cp)
char *cp;
{
*cp = cngetc();
return (1);
}
/*
* Write characters to the console.
*/
kdbwrite(cp, len)
register char *cp;
register int len;
{
while (len-- > 0)
cnputc(*cp++);
}
/*
* Fetch a longword carefully.
*/
kdbpeek(addr)
register caddr_t addr;
{
register long v = 0;
asm("movab 1f,_kdbnofault");
switch ((int)addr&03) {
case 0:
v = *(long *)addr;
break;
case 2:
v = *(u_short *)addr, addr += sizeof (short);
v = (v << 16) | *(u_short *)addr;
break;
case 1: case 3:
v = *(u_char *)addr++;
v = (v << 8) | *(u_char *)addr++;
v = (v << 8) | *(u_char *)addr++;
v = (v << 8) | *(u_char *)addr;
break;
}
asm("1:");
kdbnofault = 0;
return (v);
}
/*
* Put a longword carefully.
*/
kdbpoke(addr, v)
register caddr_t addr;
long v;
{
register int pn, *pte, opte = 0;
extern caddr_t Sysbase;
extern int etext;
u_short *wp;
u_char *cp;
/*
* If we're writing to the kernel's text space,
* make the page writeable for the duration of
* the access.
*/
if (Sysbase <= addr && addr <= (caddr_t)&etext) {
pn = btop((int)addr &~ 0xc0000000);
pte = (int *)&Sysmap[pn];
opte = *pte;
*pte = (*pte &~ PG_PROT)|PG_KW;
mtpr(TBIS, addr);
}
asm("movab 1f,_kdbnofault");
switch ((int)addr&03) {
case 0:
*(long *)addr = v;
break;
case 2:
wp = (u_short *)&v;
*(u_short*)addr = *wp++, addr += sizeof (short);
*(u_short *)addr = *wp;
break;
case 1: case 3:
cp = (u_char *)&v;
*(u_char *)addr++ = *cp++;
*(u_char *)addr++ = *cp++;
*(u_char *)addr++ = *cp++;
*(u_char *)addr = *cp;
break;
}
asm("1:");
kdbnofault = 0;
if (opte) {
*pte = opte;
mtpr(TBIS, addr);
mtpr(PACC, 1);
}
}
static
getpcb(locr0)
register int *locr0;
{
extern struct pcb kdbpcb;
register struct pcb *pcb = &kdbpcb;
pcb->pcb_r0 = locr0[R0];
pcb->pcb_r1 = locr0[R1];
pcb->pcb_r2 = locr0[R2];
pcb->pcb_r3 = locr0[R3];
pcb->pcb_r4 = locr0[R4];
pcb->pcb_r5 = locr0[R5];
pcb->pcb_r6 = locr0[R6];
pcb->pcb_r7 = locr0[R7];
pcb->pcb_r8 = locr0[R8];
pcb->pcb_r9 = locr0[R9];
pcb->pcb_r10 = locr0[R10];
pcb->pcb_r11 = locr0[R11];
pcb->pcb_r12 = locr0[R12];
pcb->pcb_fp = locr0[FP];
pcb->pcb_usp = locr0[SP];
pcb->pcb_pc = locr0[PC];
pcb->pcb_psl = locr0[PS];
pcb->pcb_ksp = mfpr(KSP);
pcb->pcb_p0br = (struct pte *)mfpr(P0BR);
pcb->pcb_p0lr = mfpr(P0LR);
pcb->pcb_p1br = (struct pte *)mfpr(P1BR);
pcb->pcb_p1lr = mfpr(P1LR);
pcb->pcb_p2br = (struct pte *)mfpr(P2BR);
pcb->pcb_p2lr = mfpr(P2LR);
pcb->pcb_ach = locr0[RACH];
pcb->pcb_acl = locr0[RACL];
}
static
setpcb(locr0)
register int *locr0;
{
extern struct pcb kdbpcb;
register struct pcb *pcb = &kdbpcb;
locr0[R0] = pcb->pcb_r0;
locr0[R1] = pcb->pcb_r1;
locr0[R2] = pcb->pcb_r2;
locr0[R3] = pcb->pcb_r3;
locr0[R4] = pcb->pcb_r4;
locr0[R5] = pcb->pcb_r5;
locr0[R6] = pcb->pcb_r6;
locr0[R7] = pcb->pcb_r7;
locr0[R8] = pcb->pcb_r8;
locr0[R9] = pcb->pcb_r9;
locr0[R10] = pcb->pcb_r10;
locr0[R11] = pcb->pcb_r11;
locr0[R12] = pcb->pcb_r12;
locr0[FP] = pcb->pcb_fp;
locr0[SP] = pcb->pcb_usp;
locr0[PC] = pcb->pcb_pc;
locr0[PS] = pcb->pcb_psl;
locr0[RACH] = pcb->pcb_ach;
locr0[RACL] = pcb->pcb_acl;
}