#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <uvm/uvm_extern.h>
#include <machine/asm_macro.h>
#include <machine/cmmu.h>
#include <machine/trap.h>
#include <machine/db_machdep.h>
#include <machine/cpu.h>
#ifdef M88100
#include <machine/m88100.h>
#include <machine/m8820x.h>
#endif
#include <ddb/db_access.h>
#include <ddb/db_command.h>
#include <ddb/db_extern.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>
#include <ddb/db_run.h>
#include <ddb/db_sym.h>
extern label_t *db_recover;
extern int frame_is_sane(db_regs_t *, int);
extern void cnpollc(int);
void kdbprinttrap(int);
int m88k_dmx_print(u_int, u_int, u_int, u_int);
void m88k_db_trap(int, struct trapframe *);
void m88k_db_print_frame(db_expr_t, int, db_expr_t, char *);
void m88k_db_registers(db_expr_t, int, db_expr_t, char *);
void m88k_db_where(db_expr_t, int, db_expr_t, char *);
void m88k_db_frame_search(db_expr_t, int, db_expr_t, char *);
db_regs_t ddb_regs;
#ifdef MULTIPROCESSOR
#include <sys/mplock.h>
struct __mp_lock ddb_mp_lock;
cpuid_t ddb_mp_nextcpu = (cpuid_t)-1;
void m88k_db_cpu_cmd(db_expr_t, int, db_expr_t, char *);
#endif
#ifdef M88100
int
m88k_dmx_print(u_int t, u_int d, u_int a, u_int no)
{
static const u_int addr_mod[16] = {
0, 3, 2, 2, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static const char *mode[16] = {
"?", ".b", ".b", ".h", ".b", "?", "?", "?",
".b", "?", "?" , "?" , ".h" , "?", "?", ""
};
static const u_int mask[16] = {
0, 0xff, 0xff00, 0xffff,
0xff0000, 0, 0, 0,
0xff000000, 0, 0, 0,
0xffff0000, 0, 0, 0xffffffff
};
static const u_int shift[16] = {
0, 0, 8, 0, 16, 0, 0, 0,
24, 0, 0, 0, 16, 0, 0, 0
};
int reg = DMT_DREGBITS(t);
if (ISSET(t, DMT_LOCKBAR)) {
db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),",
DMT_ENBITS(t) == 0x0f ? "" : ".bu",
ISSET(t, DMT_DAS) ? "" : ".usr", reg,
((t >> 2 & 0xf) == 0xf) ? d : (d & 0xff), a);
return 1;
} else if (DMT_ENBITS(t) == 0xf) {
if (ISSET(t, DMT_WRITE)) {
if (ISSET(t, DMT_DOUB1) && no == 2)
db_printf("st.d%s -> mem(0x%x) (** restart sxip **)",
ISSET(t, DMT_DAS) ? "" : ".usr", a);
else
db_printf("st%s (0x%x) -> mem(0x%x)",
ISSET(t, DMT_DAS) ? "" : ".usr", d, a);
} else {
if (ISSET(t, DMT_DOUB1) && no == 2)
db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)",
ISSET(t, DMT_DAS) ? "" : ".usr", reg, a, reg+1, a+4);
else
db_printf("ld%s r%d <- mem(0x%x)",
ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
}
} else {
a += addr_mod[DMT_ENBITS(t)];
if (ISSET(t, DMT_WRITE))
db_printf("st%s%s (0x%x) -> mem(0x%x)",
mode[DMT_ENBITS(t)],
ISSET(t, DMT_DAS) ? "" : ".usr",
(d & mask[DMT_ENBITS(t)]) >> shift[DMT_ENBITS(t)],
a);
else
db_printf("ld%s%s%s r%d <- mem(0x%x)",
mode[DMT_ENBITS(t)],
ISSET(t, DMT_SIGNED) ? "" : "u",
ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
}
return (0);
}
#endif
void
m88k_db_print_frame(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
struct trapframe *s = (struct trapframe *)addr;
const char *name;
db_expr_t offset;
#ifdef M88100
int suppress1 = 0, suppress2 = 0;
#endif
int c, force = 0, help = 0;
if (!have_addr) {
db_printf("requires address of frame\n");
help = 1;
}
while (modif && *modif) {
switch (c = *modif++, c) {
case 'f':
force = 1;
break;
case 'h':
help = 1;
break;
default:
db_printf("unknown modifier [%c]\n", c);
help = 1;
break;
}
}
if (help) {
db_printf("usage: mach frame/[f] ADDRESS\n");
db_printf(" /f force printing of insane frames.\n");
return;
}
if (badaddr((vaddr_t)s, 4) ||
badaddr((vaddr_t)(&((db_regs_t*)s)->fpit), 4)) {
db_printf("frame at %8p is unreadable\n", s);
return;
}
if (frame_is_sane((db_regs_t *)s, 0) == 0) {
if (force == 0)
return;
}
#define R(i) s->tf_r[i]
#define IPMASK(x) ((x) & ~(3))
db_printf("R00-05: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
R(0), R(1), R(2), R(3), R(4), R(5));
db_printf("R06-11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
R(6), R(7), R(8), R(9), R(10), R(11));
db_printf("R12-17: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
R(12), R(13), R(14), R(15), R(16), R(17));
db_printf("R18-23: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
R(18), R(19), R(20), R(21), R(22), R(23));
db_printf("R24-29: 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
R(24), R(25), R(26), R(27), R(28), R(29));
db_printf("R30-31: 0x%08lx 0x%08lx\n", R(30), R(31));
db_printf("%cxip: 0x%08lx ",
CPU_IS88110 ? 'e' : 's', s->tf_sxip & XIP_ADDR);
db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sxip),
&name, &offset);
if (name != NULL && (u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name, (u_int)offset);
db_printf("\n");
if (s->tf_snip != s->tf_sxip + 4) {
db_printf("%cnip: 0x%08lx ",
CPU_IS88110 ? 'e' : 's', s->tf_snip);
db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_snip),
&name, &offset);
if (name != NULL && (u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name, (u_int)offset);
db_printf("\n");
}
#ifdef M88100
if (CPU_IS88100) {
if (s->tf_sfip != s->tf_snip + 4) {
db_printf("sfip: 0x%08lx ", s->tf_sfip);
db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sfip),
&name, &offset);
if (name != NULL && (u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name, (u_int)offset);
db_printf("\n");
}
}
#endif
#ifdef M88110
if (CPU_IS88110) {
db_printf("fpsr: 0x%08lx fpcr: 0x%08lx fpecr: 0x%08lx\n",
s->tf_fpsr, s->tf_fpcr, s->tf_fpecr);
db_printf("dsap 0x%08lx duap 0x%08lx dsr 0x%08lx dlar 0x%08lx dpar 0x%08lx\n",
s->tf_dsap, s->tf_duap, s->tf_dsr, s->tf_dlar, s->tf_dpar);
db_printf("isap 0x%08lx iuap 0x%08lx isr 0x%08lx ilar 0x%08lx ipar 0x%08lx\n",
s->tf_isap, s->tf_iuap, s->tf_isr, s->tf_ilar, s->tf_ipar);
}
#endif
db_printf("epsr: 0x%08lx current process: %p\n",
s->tf_epsr, curproc);
db_printf("vector: 0x%02lx interrupt mask: 0x%08lx\n",
s->tf_vector, s->tf_mask);
if (!(s->tf_vector <= 10 ||
(114 <= s->tf_vector && s->tf_vector <= 127))) {
db_printf("\n");
return;
}
#ifdef M88100
if (CPU_IS88100) {
if (s->tf_vector == 3 || s->tf_dmt0 & DMT_VALID) {
db_printf("dmt,d,a0: 0x%08lx 0x%08lx 0x%08lx ",
s->tf_dmt0, s->tf_dmd0, s->tf_dma0);
db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma0,
&name, &offset);
if (name != NULL && (u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name, (u_int)offset);
db_printf("\n ");
suppress1 = m88k_dmx_print(s->tf_dmt0, s->tf_dmd0,
s->tf_dma0, 0);
db_printf("\n");
if ((s->tf_dmt1 & DMT_VALID) && (!suppress1)) {
db_printf("dmt,d,a1: 0x%08lx 0x%08lx 0x%08lx ",
s->tf_dmt1, s->tf_dmd1, s->tf_dma1);
db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma1,
&name, &offset);
if (name != NULL && (u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name,
(u_int)offset);
db_printf("\n ");
suppress2 = m88k_dmx_print(s->tf_dmt1,
s->tf_dmd1, s->tf_dma1, 1);
db_printf("\n");
if ((s->tf_dmt2 & DMT_VALID) && (!suppress2)) {
db_printf("dmt,d,a2: 0x%08lx 0x%08lx 0x%08lx ",
s->tf_dmt2, s->tf_dmd2, s->tf_dma2);
db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma2,
&name, &offset);
if (name != 0 &&
(u_int)offset <= db_maxoff)
db_printf("%s+0x%08x", name,
(u_int)offset);
db_printf("\n ");
m88k_dmx_print(s->tf_dmt2, s->tf_dmd2,
s->tf_dma2, 2);
db_printf("\n");
}
}
db_printf("fault code %ld\n",
CMMU_PFSR_FAULT(s->tf_dpfsr));
}
}
#endif
if (s->tf_fpecr & 255) {
db_printf("fpecr: 0x%08lx fpsr: 0x%08lx fpcr: 0x%08lx\n",
s->tf_fpecr, s->tf_fpsr, s->tf_fpcr);
#ifdef M88100
if (CPU_IS88100) {
db_printf("fcr1-4: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
s->tf_fphs1, s->tf_fpls1, s->tf_fphs2, s->tf_fpls2);
db_printf("fcr5-8: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
s->tf_fppt, s->tf_fprh, s->tf_fprl, s->tf_fpit);
}
#endif
}
db_printf("\n");
}
void
m88k_db_registers(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
m88k_db_print_frame((db_expr_t)&ddb_regs, TRUE, 0, modif);
}
void
m88k_db_trap(int type, struct trapframe *frame)
{
#ifdef MULTIPROCESSOR
struct cpu_info *ci = curcpu();
#endif
switch(type) {
case T_KDB_BREAK:
case T_KDB_TRACE:
case T_KDB_ENTRY:
break;
case -1:
break;
default:
kdbprinttrap(type);
if (db_recover != 0) {
db_error("Caught exception in ddb.\n");
}
}
#ifdef MULTIPROCESSOR
ci->ci_ddb_state = CI_DDB_ENTERDDB;
__mp_lock(&ddb_mp_lock);
ci->ci_ddb_state = CI_DDB_INDDB;
ddb_mp_nextcpu = (cpuid_t)-1;
m88k_broadcast_ipi(CI_IPI_DDB);
#endif
ddb_regs = frame->tf_regs;
db_active++;
cnpollc(1);
db_trap(type, 0);
cnpollc(0);
db_active--;
frame->tf_regs = ddb_regs;
#ifdef MULTIPROCESSOR
ci->ci_ddb_state = CI_DDB_RUNNING;
__mp_release_all(&ddb_mp_lock);
#endif
}
extern const char *trap_type[];
extern const int trap_types;
void
kdbprinttrap(int type)
{
printf("kernel: ");
if (type >= trap_types || type < 0)
printf("type %d", type);
else
printf("%s", trap_type[type]);
printf(" trap\n");
}
void
db_enter(void)
{
asm (ENTRY_ASM);
return;
}
int
ddb_break_trap(int type, db_regs_t *eframe)
{
m88k_db_trap(type, (struct trapframe *)eframe);
if (type == T_KDB_BREAK) {
if (CPU_IS88100)
m88100_rewind_insn(eframe);
}
return 0;
}
int
ddb_entry_trap(int level, db_regs_t *eframe)
{
m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe);
return 0;
}
void
db_read_bytes(vaddr_t addr, size_t size, void *datap)
{
char *data = datap, *src;
src = (char *)addr;
while (size-- > 0) {
*data++ = *src++;
}
}
void
db_write_bytes(vaddr_t addr, size_t size, void *datap)
{
extern pt_entry_t *pmap_pte(pmap_t, vaddr_t);
char *data = datap, *dst = (char *)addr;
vaddr_t va;
paddr_t pa;
pt_entry_t *pte, opte, npte;
size_t len, olen;
int cpu = cpu_number();
while (size != 0) {
va = trunc_page((vaddr_t)dst);
#ifdef M88100
if (CPU_IS88100 && va >= BATC8_VA)
pte = NULL;
else
#endif
pte = pmap_pte(pmap_kernel(), va);
if (pte != NULL) {
opte = *pte;
pa = (opte & PG_FRAME) | ((vaddr_t)dst & PAGE_MASK);
}
len = PAGE_SIZE - ((vaddr_t)dst & PAGE_MASK);
if (len > size)
len = size;
size -= olen = len;
if (pte != NULL && (opte & PG_RO)) {
npte = opte & ~PG_RO;
*pte = npte;
cmmu_tlbis(cpu, va, npte);
}
while (len-- != 0)
*dst++ = *data++;
if (pte != NULL && (opte & PG_RO)) {
*pte = opte;
cmmu_tlbis(cpu, va, opte);
}
if (pte != NULL && (opte & (CACHE_INH | CACHE_WT)) == 0) {
cmmu_dcache_wb(cpu, pa, olen);
cmmu_icache_inv(cpu, pa, olen);
}
}
}
void
m88k_db_where(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
const char *name;
db_expr_t offset;
vaddr_t l;
l = PC_REGS(&ddb_regs);
db_find_xtrn_sym_and_offset(l, &name, &offset);
if (name && (u_int)offset <= db_maxoff)
db_printf("stopped at 0x%lx (%s+0x%lx)\n", l, name, offset);
else
db_printf("stopped at 0x%lx\n", l);
}
void
m88k_db_frame_search(db_expr_t addr, int have_addr, db_expr_t count,
char *modif)
{
if (have_addr)
addr &= ~3;
else
addr = (ddb_regs.r[31]);
while (addr & ((8 * 1024) - 1)) {
if (frame_is_sane((db_regs_t *)addr, 1) != 0)
db_printf("frame found at 0x%lx\n", addr);
addr += 4;
}
db_printf("(Walked back until 0x%lx)\n",addr);
}
#ifdef MULTIPROCESSOR
void
m88k_db_cpu_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
cpuid_t cpu;
struct cpu_info *ci;
char state[15];
if (have_addr) {
cpu = (cpuid_t)addr;
if (cpu >= 0 && cpu < MAX_CPUS &&
ISSET(m88k_cpus[cpu].ci_flags, CIF_ALIVE)) {
ddb_mp_nextcpu = cpu;
db_cmd_loop_done = 1;
} else {
db_printf("cpu%ld is not active\n", cpu);
}
return;
}
db_printf(" cpu flags state curproc curpcb depth ipi\n");
CPU_INFO_FOREACH(cpu, ci) {
switch (ci->ci_ddb_state) {
case CI_DDB_RUNNING:
strlcpy(state, "running", sizeof state);
break;
case CI_DDB_ENTERDDB:
strlcpy(state, "entering ddb", sizeof state);
break;
case CI_DDB_INDDB:
strlcpy(state, "in ddb", sizeof state);
break;
case CI_DDB_PAUSE:
strlcpy(state, "paused", sizeof state);
break;
default:
snprintf(state, sizeof state, "unknown (%d)",
ci->ci_ddb_state);
break;
}
db_printf("%ccpu%d %02x %-14s %08lx %08lx %3u %08x\n",
(cpu == cpu_number()) ? '*' : ' ', CPU_INFO_UNIT(ci),
ci->ci_flags, state, (register_t)ci->ci_curproc,
(register_t)ci->ci_curpcb, ci->ci_idepth, ci->ci_ipi);
}
}
#endif
const struct db_command db_machine_command_table[] = {
#ifdef MULTIPROCESSOR
{ "ddbcpu", m88k_db_cpu_cmd, 0, NULL },
#endif
{ "frame", m88k_db_print_frame, 0, NULL },
{ "regs", m88k_db_registers, 0, NULL },
{ "searchframe",m88k_db_frame_search, 0, NULL },
{ "where", m88k_db_where, 0, NULL },
#if defined(EXTRA_MACHDEP_COMMANDS)
EXTRA_MACHDEP_COMMANDS
#endif
{ NULL, NULL, 0, NULL }
};
void
db_machine_init()
{
#ifdef MULTIPROCESSOR
__mp_lock_init(&ddb_mp_lock);
#endif
}