- option MIPS_DDB_WATCH is dedprecated, removed; now using

(MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 for conditional
compile of db_mach_watch stuff
- MIPS CPU (COP0) watchpoint support moved from db_interface.c
to cpu_subr.c, cpu.h; ddb_mach_watch &etc now use those cpu functions.
- ddb_cpu now volatile
- 'struct db_mach_watch' definition &etc moved to mips/include/db_machdep.h
- db_mach_watch_tab is replaced by curcpu()->ci_watch_tab
to allow per-cpu watchpoint control
- improve MP function in kdb_trap()
- fix conditions for printing cp0 regs
This commit is contained in:
cliff 2011-04-14 05:09:34 +00:00
parent 061e9aafc0
commit 2cbfee21ba
1 changed files with 104 additions and 169 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_interface.c,v 1.70 2011/04/06 05:53:27 matt Exp $ */
/* $NetBSD: db_interface.c,v 1.71 2011/04/14 05:09:34 cliff Exp $ */
/*
* Mach Operating System
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.70 2011/04/06 05:53:27 matt Exp $");
__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.71 2011/04/14 05:09:34 cliff Exp $");
#include "opt_multiprocessor.h"
#include "opt_cputype.h" /* which mips CPUs do we support? */
@ -67,34 +67,15 @@ __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.70 2011/04/06 05:53:27 matt Exp $
#endif
#define NOCPU ~0
u_int ddb_cpu = NOCPU;
volatile u_int ddb_cpu = NOCPU;
int db_active = 0;
db_regs_t ddb_regs;
#ifdef MIPS_DDB_WATCH
struct db_mach_watch {
register_t addr;
register_t mask;
uint32_t asid;
uint32_t mode;
};
/* mode bits */
#define DB_WATCH_WRITE __BIT(0)
#define DB_WATCH_READ __BIT(1)
#define DB_WATCH_EXEC __BIT(2)
#define DB_WATCH_MASK __BIT(3)
#define DB_WATCH_ASID __BIT(4)
#define DB_WATCH_RWX (DB_WATCH_EXEC|DB_WATCH_READ|DB_WATCH_WRITE)
#define DBNWATCH 1
static volatile struct db_mach_watch db_mach_watch_tab[DBNWATCH];
static void db_mach_watch_set(int, register_t, register_t, uint32_t, uint32_t,
bool);
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
static void db_watch_cmd(db_expr_t, bool, db_expr_t, const char *);
static void db_unwatch_cmd(db_expr_t, bool, db_expr_t, const char *);
#endif /* MIPS_DDB_WATCH */
#endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
#ifdef MULTIPROCESSOR
static void db_mach_cpu(db_expr_t, bool, db_expr_t, const char *);
@ -146,6 +127,8 @@ kdb_trap(int type, struct reg *regs)
break;
}
s = splhigh();
#ifdef MULTIPROCESSOR
bool first_in_ddb = false;
const u_int cpu_me = cpu_number();
@ -155,26 +138,25 @@ kdb_trap(int type, struct reg *regs)
cpu_pause_others();
} else {
if (old_ddb_cpu != cpu_me) {
KASSERT(cpu_is_paused(cpu_me));
cpu_pause(regs);
splx(s);
return 1;
}
}
KASSERT(! cpu_is_paused(cpu_me));
#endif
/* Should switch to kdb`s own stack here. */
ddb_regs = *regs;
s = splhigh();
db_active++;
cnpollc(1);
db_trap(type & ~T_USER, 0 /*code*/);
cnpollc(0);
db_active--;
splx(s);
*regs = ddb_regs;
#ifdef MULTIPROCESSOR
if (ddb_cpu == cpu_me) {
ddb_cpu = NOCPU;
if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
cpu_resume_others();
} else {
cpu_resume(ddb_cpu);
@ -183,9 +165,8 @@ kdb_trap(int type, struct reg *regs)
}
#endif
*regs = ddb_regs;
return (1);
splx(s);
return 1;
}
void
@ -411,10 +392,12 @@ db_cp0dump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
SHOW32(MIPS_COP_0_COUNT, "count");
}
if ((cp0flags & MIPS_CP0FL_EIRR) != 0)
SHOW64SEL(9, 6, "eirr");
if ((cp0flags & MIPS_CP0FL_EIMR) != 0)
SHOW64SEL(9, 7, "eimr");
if ((cp0flags & MIPS_CP0FL_USE) != 0) {
if ((cp0flags & MIPS_CP0FL_EIRR) != 0)
SHOW64SEL(9, 6, "eirr");
if ((cp0flags & MIPS_CP0FL_EIMR) != 0)
SHOW64SEL(9, 7, "eimr");
}
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_TLB_HI, "entryhi");
@ -479,146 +462,98 @@ db_cp0dump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
else
SHOW32(MIPS_COP_0_LLADDR, "lladdr");
}
}
SHOW32(MIPS_COP_0_WATCH_HI, "watchhi");
if (CPUIS64BITS)
SHOW64(MIPS_COP_0_WATCH_LO, "watchlo");
else
SHOW32(MIPS_COP_0_WATCH_LO, "watchlo");
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
for (int i=0; i < curcpu()->ci_cpuwatch_count; i++) {
uint32_t r = mipsNN_cp0_watchlo_read(i);
printf(" %s%d:%*s %#x\n", "watchlo", i, FLDWIDTH - 8, "", r);
}
for (int i=0; i < curcpu()->ci_cpuwatch_count; i++) {
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext");
}
if (CPUISMIPSNN) {
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_PERFCNT, "perfcnt");
} else {
SHOW32(MIPS_COP_0_PERFCNT, "perfcnt");
}
}
if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
((cp0flags & MIPS_CP0FL_ECC) != 0))
SHOW32(MIPS_COP_0_ECC, "ecc");
if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
((cp0flags & MIPS_CP0FL_CACHE_ERR) != 0))
SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr");
SHOW32(MIPS_COP_0_TAG_LO, "cachelo");
SHOW32(MIPS_COP_0_TAG_HI, "cachehi");
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_ERROR_PC, "errorpc");
uint32_t r = mipsNN_cp0_watchhi_read(i);
printf(" %s%d:%*s %#x\n",
"watchhi", i, FLDWIDTH - 8, "", r);
} else {
SHOW32(MIPS_COP_0_ERROR_PC, "errorpc");
uint64_t r = mipsNN_cp0_watchhi_read(i);
printf(" %s%d:%*s %#" PRIx64 "\n",
"watchhi", i, FLDWIDTH - 8, "", r);
}
}
}
#ifdef MIPS_DDB_WATCH
void
db_mach_watch_set_all(void)
{
volatile struct db_mach_watch *wp;
int i;
for (i=0; i < DBNWATCH; i++) {
wp = &db_mach_watch_tab[i];
db_mach_watch_set(i, wp->addr, wp->mask, wp->asid, wp->mode,
true);
}
}
/*
* db_mach_watch_set - write the COP0 registers
*/
static void
db_mach_watch_set(int wnum, register_t addr, register_t mask, uint32_t asid,
uint32_t mode, bool quiet)
{
uint32_t watchhi;
register_t watchlo;
const char *strhi = (quiet) ? NULL : "watchhi";
const char *strlo = (quiet) ? NULL : "watchlo";
KASSERT(wnum == 0); /* TBD */
watchlo = addr;
if (mode & DB_WATCH_WRITE)
watchlo |= __BIT(0);
if (mode & DB_WATCH_READ)
watchlo |= __BIT(1);
if (mode & DB_WATCH_EXEC)
watchlo |= __BIT(2);
if (mode & DB_WATCH_ASID)
watchhi = asid << 16; /* addr qualified by asid */
else
watchhi = __BIT(30); /* addr not qualified by asid (Global)*/
if (mode & DB_WATCH_MASK)
watchhi |= mask; /* set "dont care" addr match bits */
SET32(MIPS_COP_0_WATCH_HI, strhi, watchhi);
#endif
if (CPUIS64BITS) {
MIPS64_SET64(MIPS_COP_0_WATCH_LO, 0, strlo, watchlo);
SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext");
}
if (CPUISMIPSNN) {
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_PERFCNT, "perfcnt");
} else {
SHOW32(MIPS_COP_0_PERFCNT, "perfcnt");
}
}
if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
((cp0flags & MIPS_CP0FL_ECC) != 0))
SHOW32(MIPS_COP_0_ECC, "ecc");
if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
((cp0flags & MIPS_CP0FL_CACHE_ERR) != 0))
SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr");
SHOW32(MIPS_COP_0_TAG_LO, "cachelo");
SHOW32(MIPS_COP_0_TAG_HI, "cachehi");
if (CPUIS64BITS) {
SHOW64(MIPS_COP_0_ERROR_PC, "errorpc");
} else {
SET32(MIPS_COP_0_WATCH_LO, strlo, (uint32_t)watchlo);
SHOW32(MIPS_COP_0_ERROR_PC, "errorpc");
}
}
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
static void
db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
const char *modif)
{
volatile struct db_mach_watch *wp;
struct cpu_info * const ci = curcpu();
cpu_watchpoint_t *cwp;
register_t mask=0;
uint32_t asid;
uint32_t mode;
db_expr_t value;
int wnum;
char str[6];
if (!have_addr) {
db_printf("%-3s %-5s %-16s %4s %4s\n",
"#", "MODE", "ADDR", "MASK", "ASID");
for (int i=0; i < DBNWATCH; i++) {
wp = &db_mach_watch_tab[i];
mode = wp->mode;
if ((mode & DB_WATCH_RWX) == 0)
for (int i=0; i < ci->ci_cpuwatch_count; i++) {
cwp = &ci->ci_cpuwatch_tab[i];
mode = cwp->cw_mode;
if ((mode & CPUWATCH_RWX) == 0)
continue; /* empty/disabled/invalid */
str[0] = (mode & DB_WATCH_READ) ? 'r' : '-';
str[1] = (mode & DB_WATCH_WRITE) ? 'w' : '-';
str[2] = (mode & DB_WATCH_EXEC) ? 'x' : '-';
str[3] = (mode & DB_WATCH_MASK) ? 'm' : '-';
str[4] = (mode & DB_WATCH_ASID) ? 'a' : 'g';
str[0] = (mode & CPUWATCH_READ) ? 'r' : '-';
str[1] = (mode & CPUWATCH_WRITE) ? 'w' : '-';
str[2] = (mode & CPUWATCH_EXEC) ? 'x' : '-';
str[3] = (mode & CPUWATCH_MASK) ? 'm' : '-';
str[4] = (mode & CPUWATCH_ASID) ? 'a' : 'g';
str[5] = '\0';
db_printf("%2d: %s %16" PRIxREGISTER
" %4" PRIxREGISTER " %4x\n",
i, str, wp->addr, wp->mask, wp->asid);
i, str, cwp->cw_addr, cwp->cw_mask, cwp->cw_asid);
}
db_flush_lex();
return;
}
/*
* find an empty slot
* no lock for the table since only 1 CPU active in ddb at a time
* (other CPUs are paused)
*/
for (int i=0; i < DBNWATCH; i++) {
wp = &db_mach_watch_tab[i]; /* empty/disabled/invalid */
if ((wp->mode & DB_WATCH_RWX) == 0) {
wnum = i;
goto found;
}
cwp = cpuwatch_alloc();
if (cwp == NULL) {
db_printf("no watchpoint available\n");
db_flush_lex();
return;
}
db_printf("no watchpoint available\n");
db_flush_lex();
return;
found:
/*
* parse modif to define mode
*/
@ -627,19 +562,19 @@ db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
for (int i=0; modif[i] != '\0'; i++) {
switch(modif[i]) {
case 'w':
mode |= DB_WATCH_WRITE;
mode |= CPUWATCH_WRITE;
break;
case 'm':
mode |= DB_WATCH_MASK;
mode |= CPUWATCH_MASK;
break;
case 'r':
mode |= DB_WATCH_READ;
mode |= CPUWATCH_READ;
break;
case 'x':
mode |= DB_WATCH_EXEC;
mode |= CPUWATCH_EXEC;
break;
case 'a':
mode |= DB_WATCH_ASID;
mode |= CPUWATCH_ASID;
break;
}
}
@ -652,7 +587,7 @@ db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
/*
* if mask mode is requested get the mask,
*/
if (mode & DB_WATCH_MASK) {
if (mode & CPUWATCH_MASK) {
if (! db_expression(&value)) {
db_printf("mask missing\n");
db_flush_lex();
@ -665,7 +600,7 @@ db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
* if asid mode is requested, get the asid;
* otherwise use global mode (and set asid=0)
*/
if (mode & DB_WATCH_ASID) {
if (mode & CPUWATCH_ASID) {
if (! db_expression(&value)) {
db_printf("asid missing\n");
db_flush_lex();
@ -676,7 +611,7 @@ db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
asid = 0;
}
if (mode & (DB_WATCH_MASK|DB_WATCH_ASID))
if (mode & (CPUWATCH_MASK|CPUWATCH_ASID))
db_skip_to_eol();
else
db_flush_lex();
@ -685,31 +620,32 @@ db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
* store to the (volatile) table entry
* other CPUs can see this and load when resuming from pause
*/
wp->addr = (register_t)address;
wp->mask = (register_t)mask;
wp->asid = asid;
wp->mode = mode;
cwp->cw_addr = (register_t)address;
cwp->cw_mask = (register_t)mask;
cwp->cw_asid = asid;
cwp->cw_mode = mode;
db_mach_watch_set(wnum, (register_t)address, mask, asid, mode, false);
/*
* program the CPU watchpoint regs
*/
cpuwatch_set(cwp);
}
static void
db_unwatch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
const char *modif)
{
volatile struct db_mach_watch *wp;
struct cpu_info * const ci = curcpu();
cpu_watchpoint_t *cwp;
int i, n;
bool unwatch_all = !have_addr;
n = 0;
for (i=0; i < DBNWATCH; i++) {
wp = &db_mach_watch_tab[i];
if (unwatch_all || (wp->addr == (register_t)address)) {
for (i=0; i < ci->ci_cpuwatch_count; i++) {
cwp = &ci->ci_cpuwatch_tab[i];
if (unwatch_all || (cwp->cw_addr == (register_t)address)) {
cpuwatch_free(cwp);
n++;
wp->mode = 0;
wp->asid = 0;
wp->addr = 0;
db_mach_watch_set(i, 0, 0, 0, 0, false);
}
}
if (n == 0)
@ -717,7 +653,7 @@ db_unwatch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
(register_t)address);
}
#endif /* MIPS_DDB_WATCH */
#endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
#ifdef MIPS64_XLS
void
@ -787,14 +723,14 @@ const struct db_command db_machine_command_table[] = {
{ DDB_ADD_CMD("cp0", db_cp0dump_cmd, 0,
"Dump CP0 registers.",
NULL, NULL) },
#ifdef MIPS_DDB_WATCH
#if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
{ DDB_ADD_CMD("watch", db_watch_cmd, CS_MORE,
"set cp0 watchpoint",
"address <mask> <asid> </rwxma>", NULL) },
{ DDB_ADD_CMD("unwatch",db_unwatch_cmd, 0,
"delete cp0 watchpoint",
"address", NULL) },
#endif /* MIPS_DDB_WATCH */
#endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
{ DDB_ADD_CMD("kvtop", db_kvtophys_cmd, 0,
"Print the physical address for a given kernel virtual address",
"address",
@ -1029,8 +965,7 @@ db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
db_printf("CPU %ld not paused\n", (long)addr);
return;
}
/* no locking needed - all other cpus are paused */
ddb_cpu = cpu_index(ci);
(void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci));
db_continue_cmd(0, false, 0, "");
}
}