File: [local] / sys / arch / m88k / m88k / db_interface.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:07:10 2008 UTC (16 years, 6 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: db_interface.c,v 1.7 2007/05/19 20:33:49 miod Exp $ */
/*
* Mach Operating System
* Copyright (c) 1993-1991 Carnegie Mellon University
* Copyright (c) 1991 OMRON Corporation
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*
* m88k interface to ddb debugger
*/
#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_sym.h>
extern label_t *db_recover;
extern int frame_is_sane(db_regs_t *, int); /* db_trace */
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 ddb_error_trap(char *, db_regs_t *);
void m88k_db_pause(u_int);
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 *);
void m88k_db_translate(db_expr_t, int, db_expr_t, char *);
void m88k_db_cmmucfg(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;
void m88k_db_cpu_cmd(db_expr_t, int, db_expr_t, char *);
#endif
/*
* If you really feel like understanding the following procedure and
* macros, see pages 6-22 to 6-30 (Section 6.7.3) of
*
* MC88100 RISC Microprocessor User's Manual Second Edition
* (Motorola Order: MC88100UM/AD REV 1)
*
* and ERRATA-5 (6-23, 6-24, 6-24) of
*
* Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1
* (Oct 2, 1990)
* (Motorola Order: MC88100UMAD/AD)
*/
#ifdef M88100
/* macros for decoding dmt registers */
/*
* return 1 if the printing of the next stage should be suppressed
*/
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) {
/* full or double word */
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 {
/* load */
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 {
/* fractional word - check if load or store */
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 /* M88100 */
void
m88k_db_print_frame(addr, have_addr, count, modif)
db_expr_t addr;
int have_addr;
db_expr_t count;
char *modif;
{
struct trapframe *s = (struct trapframe *)addr;
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%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
R(0), R(1), R(2), R(3), R(4), R(5));
db_printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
R(6), R(7), R(8), R(9), R(10), R(11));
db_printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
R(12), R(13), R(14), R(15), R(16), R(17));
db_printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
R(18), R(19), R(20), R(21), R(22), R(23));
db_printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
R(24), R(25), R(26), R(27), R(28), R(29));
db_printf("R30-31: 0x%08x 0x%08x\n", R(30), R(31));
db_printf("%cxip: 0x%08x ",
CPU_IS88110 ? 'e' : 's', s->tf_sxip & XIP_ADDR);
db_find_xtrn_sym_and_offset((db_addr_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%08x ",
CPU_IS88110 ? 'e' : 's', s->tf_snip);
db_find_xtrn_sym_and_offset((db_addr_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%08x ", s->tf_sfip);
db_find_xtrn_sym_and_offset((db_addr_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%08x fpcr: 0x%08x fpecr: 0x%08x\n",
s->tf_fpsr, s->tf_fpcr, s->tf_fpecr);
db_printf("dsap 0x%08x duap 0x%08x dsr 0x%08x dlar 0x%08x dpar 0x%08x\n",
s->tf_dsap, s->tf_duap, s->tf_dsr, s->tf_dlar, s->tf_dpar);
db_printf("isap 0x%08x iuap 0x%08x isr 0x%08x ilar 0x%08x ipar 0x%08x\n",
s->tf_isap, s->tf_iuap, s->tf_isr, s->tf_ilar, s->tf_ipar);
}
#endif
db_printf("epsr: 0x%08x current process: %p\n",
s->tf_epsr, curproc);
db_printf("vector: 0x%02x interrupt mask: 0x%08x\n",
s->tf_vector, s->tf_mask);
/*
* If the vector indicates trap, instead of an exception or
* interrupt, skip the check of dmt and fp regs.
*
* Interrupt and exceptions are vectored at 0-10 and 114-127.
*/
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 == /*data*/3 || s->tf_dmt0 & DMT_VALID) {
db_printf("dmt,d,a0: 0x%08x 0x%08x 0x%08x ",
s->tf_dmt0, s->tf_dmd0, s->tf_dma0);
db_find_xtrn_sym_and_offset((db_addr_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%08x 0x%08x 0x%08x ",
s->tf_dmt1, s->tf_dmd1, s->tf_dma1);
db_find_xtrn_sym_and_offset((db_addr_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%08x 0x%08x 0x%08x ",
s->tf_dmt2, s->tf_dmd2, s->tf_dma2);
db_find_xtrn_sym_and_offset((db_addr_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 %d\n",
CMMU_PFSR_FAULT(s->tf_dpfsr));
}
}
#endif /* M88100 */
if (s->tf_fpecr & 255) { /* floating point error occurred */
db_printf("fpecr: 0x%08x fpsr: 0x%08x fpcr: 0x%08x\n",
s->tf_fpecr, s->tf_fpsr, s->tf_fpcr);
#ifdef M88100
if (CPU_IS88100) {
db_printf("fcr1-4: 0x%08x 0x%08x 0x%08x 0x%08x\n",
s->tf_fphs1, s->tf_fpls1, s->tf_fphs2, s->tf_fpls2);
db_printf("fcr5-8: 0x%08x 0x%08x 0x%08x 0x%08x\n",
s->tf_fppt, s->tf_fprh, s->tf_fprl, s->tf_fpit);
}
#endif
}
db_printf("\n");
}
void
m88k_db_registers(addr, have_addr, count, modif)
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);
}
/*
* pause for 2*ticks many cycles
*/
void
m88k_db_pause(ticks)
u_int volatile ticks;
{
while (ticks)
ticks -= 1;
}
/*
* m88k_db_trap - field a TRACE or BPT trap
* Note that only the tf_regs part of the frame is valid - some ddb routines
* invoke this function with a promoted struct reg!
*/
void
m88k_db_trap(type, frame)
int type;
struct trapframe *frame;
{
if (get_psr() & PSR_IND)
db_printf("WARNING: entered debugger with interrupts disabled\n");
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");
/*NOTREACHED*/
}
}
#ifdef MULTIPROCESSOR
curcpu()->ci_ddb_state = CI_DDB_ENTERDDB;
__mp_lock(&ddb_mp_lock);
curcpu()->ci_ddb_state = CI_DDB_INDDB;
m88k_broadcast_ipi(CI_IPI_DDB); /* pause other processors */
#endif
ddb_regs = frame->tf_regs;
cnpollc(TRUE);
db_trap(type, 0);
cnpollc(FALSE);
frame->tf_regs = ddb_regs;
#ifdef MULTIPROCESSOR
curcpu()->ci_ddb_state = CI_DDB_RUNNING;
__mp_release_all(&ddb_mp_lock);
#endif
}
extern const char *trap_type[];
extern const int trap_types;
/*
* Print trap reason.
*/
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
Debugger()
{
asm (ENTRY_ASM); /* entry trap */
/* ends up at ddb_entry_trap below */
return;
}
/*
* When the below routine is entered interrupts should be on
* but spl should be high
*
* The following routine is for breakpoint and watchpoint entry.
*/
/* breakpoint/watchpoint entry */
int
ddb_break_trap(type, eframe)
int type;
db_regs_t *eframe;
{
m88k_db_trap(type, (struct trapframe *)eframe);
if (type == T_KDB_BREAK) {
/*
* back up an instruction and retry the instruction
* at the breakpoint address. mc88110's exip reg
* already has the address of the exception instruction.
*/
if (CPU_IS88100) {
eframe->sfip = eframe->snip;
eframe->snip = eframe->sxip;
}
}
return 0;
}
/* enter at splhigh */
int
ddb_entry_trap(level, eframe)
int level;
db_regs_t *eframe;
{
m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe);
return 0;
}
/*
* When the below routine is entered interrupts should be on
* but spl should be high
*/
/* error trap - unreturnable */
void
ddb_error_trap(error, regs)
char *error;
db_regs_t *regs;
{
db_printf("KERNEL: unrecoverable error [%s]\n", error);
db_printf("KERNEL: Exiting debugger will cause abort to rom\n");
db_printf("at 0x%x ", regs->sxip & XIP_ADDR);
db_printf("dmt0 0x%x dma0 0x%x", regs->dmt0, regs->dma0);
m88k_db_pause(1000000);
m88k_db_trap(T_KDB_BREAK, (struct trapframe *)regs);
}
/*
* Read bytes from kernel address space for debugger.
*/
void
db_read_bytes(db_addr_t addr, size_t size, char *data)
{
char *src;
src = (char *)addr;
while (size-- > 0) {
*data++ = *src++;
}
}
/*
* Write bytes to kernel address space for debugger.
*/
void
db_write_bytes(db_addr_t addr, size_t size, char *data)
{
extern pt_entry_t *pmap_pte(pmap_t, vaddr_t);
char *dst = (char *)addr;
vaddr_t va;
paddr_t pa;
pt_entry_t *pte, opte;
size_t len, olen;
int cpu = cpu_number();
while (size != 0) {
va = trunc_page((vaddr_t)dst);
pte = pmap_pte(pmap_kernel(), va);
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 (opte & PG_RO) {
*pte = opte & ~PG_RO;
cmmu_flush_tlb(cpu, TRUE, va, 1);
}
while (len-- != 0)
*dst++ = *data++;
if (opte & PG_RO) {
*pte = opte;
cmmu_flush_tlb(cpu, TRUE, va, 1);
}
cmmu_flush_cache(cpu, pa, olen);
}
}
/* display where all the cpus are stopped at */
void
m88k_db_where(addr, have_addr, count, modif)
db_expr_t addr;
int have_addr;
db_expr_t count;
char *modif;
{
char *name;
db_expr_t offset;
db_addr_t l;
l = PC_REGS(DDB_REGS); /* clear low bits */
db_find_xtrn_sym_and_offset(l, &name, &offset);
if (name && (u_int)offset <= db_maxoff)
db_printf("stopped at 0x%lx (%s+0x%x)\n", l, name, offset);
else
db_printf("stopped at 0x%lx\n", l);
}
/*
* Walk back a stack, looking for exception frames.
* These frames are recognized by the routine frame_is_sane. Frames
* only start with zero, so we only call frame_is_sane if the
* current address contains zero.
*
* If addr is given, it is assumed to an address on the stack to be
* searched. Otherwise, r31 of the current cpu is used.
*/
void
m88k_db_frame_search(addr, have_addr, count, modif)
db_expr_t addr;
int have_addr;
db_expr_t count;
char *modif;
{
if (have_addr)
addr &= ~3; /* round to word */
else
addr = (DDB_REGS->r[31]);
/* walk back up stack until 8k boundry, looking for 0 */
while (addr & ((8 * 1024) - 1)) {
if (frame_is_sane((db_regs_t *)addr, 1) != 0)
db_printf("frame found at 0x%x\n", addr);
addr += 4;
}
db_printf("(Walked back until 0x%x)\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;
CPU_INFO_FOREACH(cpu, ci) {
db_printf("%c%4d: ", (cpu == cpu_number()) ? '*' : ' ',
CPU_INFO_UNIT(ci));
switch (ci->ci_ddb_state) {
case CI_DDB_RUNNING:
db_printf("running\n");
break;
case CI_DDB_ENTERDDB:
db_printf("entering ddb\n");
break;
case CI_DDB_INDDB:
db_printf("ddb\n");
break;
default:
db_printf("? (%d)\n",
ci->ci_ddb_state);
break;
}
}
}
#endif /* MULTIPROCESSOR */
/************************/
/* COMMAND TABLE / INIT */
/************************/
struct db_command db_machine_cmds[] = {
#ifdef MULTIPROCESSOR
{ "cpu", 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()
{
db_machine_commands_install(db_machine_cmds);
#ifdef MULTIPROCESSOR
__mp_lock_init(&ddb_mp_lock);
#endif
}