- 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:
parent
061e9aafc0
commit
2cbfee21ba
|
@ -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, "");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue