Page MenuHomeFreeBSD

D29153.diff
No OneTemporary

D29153.diff

diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c
--- a/sys/amd64/amd64/db_trace.c
+++ b/sys/amd64/amd64/db_trace.c
@@ -128,11 +128,6 @@
static void db_print_stack_entry(const char *, db_addr_t, void *);
static void decode_syscall(int, struct thread *);
-static const char * watchtype_str(int type);
-int amd64_set_watch(int watchnum, unsigned long watchaddr, int size,
- int access, struct dbreg *d);
-int amd64_clr_watch(int watchnum, struct dbreg *d);
-
static void
db_print_stack_entry(const char *name, db_addr_t callpc, void *frame)
{
@@ -391,223 +386,22 @@
}
int
-amd64_set_watch(watchnum, watchaddr, size, access, d)
- int watchnum;
- unsigned long watchaddr;
- int size;
- int access;
- struct dbreg *d;
-{
- int i, len;
-
- if (watchnum == -1) {
- for (i = 0; i < 4; i++)
- if (!DBREG_DR7_ENABLED(d->dr[7], i))
- break;
- if (i < 4)
- watchnum = i;
- else
- return (-1);
- }
-
- switch (access) {
- case DBREG_DR7_EXEC:
- size = 1; /* size must be 1 for an execution breakpoint */
- /* fall through */
- case DBREG_DR7_WRONLY:
- case DBREG_DR7_RDWR:
- break;
- default:
- return (-1);
- }
-
- /*
- * we can watch a 1, 2, 4, or 8 byte sized location
- */
- switch (size) {
- case 1:
- len = DBREG_DR7_LEN_1;
- break;
- case 2:
- len = DBREG_DR7_LEN_2;
- break;
- case 4:
- len = DBREG_DR7_LEN_4;
- break;
- case 8:
- len = DBREG_DR7_LEN_8;
- break;
- default:
- return (-1);
- }
-
- /* clear the bits we are about to affect */
- d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-
- /* set drN register to the address, N=watchnum */
- DBREG_DRX(d, watchnum) = watchaddr;
-
- /* enable the watchpoint */
- d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
- DBREG_DR7_GLOBAL_ENABLE);
-
- return (watchnum);
-}
-
-int
-amd64_clr_watch(watchnum, d)
- int watchnum;
- struct dbreg *d;
-{
-
- if (watchnum < 0 || watchnum >= 4)
- return (-1);
-
- d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
- DBREG_DRX(d, watchnum) = 0;
-
- return (0);
-}
-
-int
-db_md_set_watchpoint(addr, size)
- db_expr_t addr;
- db_expr_t size;
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
{
- struct dbreg *d;
- struct pcpu *pc;
- int avail, c, cpu, i, wsize;
-
- d = (struct dbreg *)PCPU_PTR(dbreg);
- cpu = PCPU_GET(cpuid);
- fill_dbregs(NULL, d);
-
- avail = 0;
- for (i = 0; i < 4; i++) {
- if (!DBREG_DR7_ENABLED(d->dr[7], i))
- avail++;
- }
-
- if (avail * 8 < size)
- return (-1);
-
- for (i = 0; i < 4 && size > 0; i++) {
- if (!DBREG_DR7_ENABLED(d->dr[7], i)) {
- if (size >= 8 || (avail == 1 && size > 4))
- wsize = 8;
- else if (size > 2)
- wsize = 4;
- else
- wsize = size;
- amd64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, d);
- addr += wsize;
- size -= wsize;
- avail--;
- }
- }
-
- set_dbregs(NULL, d);
- CPU_FOREACH(c) {
- if (c == cpu)
- continue;
- pc = pcpu_find(c);
- memcpy(pc->pc_dbreg, d, sizeof(*d));
- pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
- }
- return (0);
+ return (dbreg_set_watchpoint((vm_offset_t)addr, (vm_size_t)size));
}
int
-db_md_clr_watchpoint(addr, size)
- db_expr_t addr;
- db_expr_t size;
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
{
- struct dbreg *d;
- struct pcpu *pc;
- int i, c, cpu;
-
- d = (struct dbreg *)PCPU_PTR(dbreg);
- cpu = PCPU_GET(cpuid);
- fill_dbregs(NULL, d);
-
- for (i = 0; i < 4; i++) {
- if (DBREG_DR7_ENABLED(d->dr[7], i)) {
- if (DBREG_DRX((d), i) >= addr &&
- DBREG_DRX((d), i) < addr + size)
- amd64_clr_watch(i, d);
- }
- }
-
- set_dbregs(NULL, d);
- CPU_FOREACH(c) {
- if (c == cpu)
- continue;
- pc = pcpu_find(c);
- memcpy(pc->pc_dbreg, d, sizeof(*d));
- pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
- }
- return (0);
-}
-
-static const char *
-watchtype_str(type)
- int type;
-{
- switch (type) {
- case DBREG_DR7_EXEC : return "execute"; break;
- case DBREG_DR7_RDWR : return "read/write"; break;
- case DBREG_DR7_WRONLY : return "write"; break;
- default : return "invalid"; break;
- }
+ return (dbreg_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size));
}
void
db_md_list_watchpoints(void)
{
- struct dbreg d;
- int i, len, type;
-
- fill_dbregs(NULL, &d);
-
- db_printf("\nhardware watchpoints:\n");
- db_printf(" watch status type len address\n");
- db_printf(" ----- -------- ---------- --- ------------------\n");
- for (i = 0; i < 4; i++) {
- if (DBREG_DR7_ENABLED(d.dr[7], i)) {
- type = DBREG_DR7_ACCESS(d.dr[7], i);
- len = DBREG_DR7_LEN(d.dr[7], i);
- if (len == DBREG_DR7_LEN_8)
- len = 8;
- else
- len++;
- db_printf(" %-5d %-8s %10s %3d ",
- i, "enabled", watchtype_str(type), len);
- db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
- db_printf("\n");
- } else {
- db_printf(" %-5d disabled\n", i);
- }
- }
- db_printf("\ndebug register values:\n");
- for (i = 0; i < 8; i++)
- if (i != 4 && i != 5)
- db_printf(" dr%d 0x%016lx\n", i, DBREG_DRX(&d, i));
- db_printf("\n");
-}
-
-void
-amd64_db_resume_dbreg(void)
-{
- struct dbreg *d;
-
- switch (PCPU_GET(dbreg_cmd)) {
- case PC_DBREG_CMD_LOAD:
- d = (struct dbreg *)PCPU_PTR(dbreg);
- set_dbregs(NULL, d);
- PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
- break;
- }
+ dbreg_list_watchpoints();
}
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -320,6 +320,7 @@
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
x86/x86/cpu_machdep.c standard
+x86/x86/dbreg.c optional ddb
x86/x86/dump_machdep.c standard
x86/x86/fdt_machdep.c optional fdt
x86/x86/identcpu.c standard
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
--- a/sys/i386/i386/db_trace.c
+++ b/sys/i386/i386/db_trace.c
@@ -198,11 +198,6 @@
void *);
static void decode_syscall(int, struct thread *);
-static const char * watchtype_str(int type);
-int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
- struct dbreg *d);
-int i386_clr_watch(int watchnum, struct dbreg *d);
-
/*
* Figure out how many arguments were passed into the frame at "fp".
*/
@@ -618,180 +613,22 @@
}
int
-i386_set_watch(watchnum, watchaddr, size, access, d)
- int watchnum;
- unsigned int watchaddr;
- int size;
- int access;
- struct dbreg *d;
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
{
- int i, len;
-
- if (watchnum == -1) {
- for (i = 0; i < 4; i++)
- if (!DBREG_DR7_ENABLED(d->dr[7], i))
- break;
- if (i < 4)
- watchnum = i;
- else
- return (-1);
- }
-
- switch (access) {
- case DBREG_DR7_EXEC:
- size = 1; /* size must be 1 for an execution breakpoint */
- /* fall through */
- case DBREG_DR7_WRONLY:
- case DBREG_DR7_RDWR:
- break;
- default:
- return (-1);
- }
- /*
- * we can watch a 1, 2, or 4 byte sized location
- */
- switch (size) {
- case 1:
- len = DBREG_DR7_LEN_1;
- break;
- case 2:
- len = DBREG_DR7_LEN_2;
- break;
- case 4:
- len = DBREG_DR7_LEN_4;
- break;
- default:
- return (-1);
- }
-
- /* clear the bits we are about to affect */
- d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-
- /* set drN register to the address, N=watchnum */
- DBREG_DRX(d, watchnum) = watchaddr;
-
- /* enable the watchpoint */
- d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
- DBREG_DR7_GLOBAL_ENABLE);
-
- return (watchnum);
+ return (dbreg_set_watchpoint((vm_offset_t)addr, (vm_size_t)size));
}
int
-i386_clr_watch(watchnum, d)
- int watchnum;
- struct dbreg *d;
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
{
- if (watchnum < 0 || watchnum >= 4)
- return (-1);
-
- d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
- DBREG_DRX(d, watchnum) = 0;
-
- return (0);
-}
-
-int
-db_md_set_watchpoint(addr, size)
- db_expr_t addr;
- db_expr_t size;
-{
- struct dbreg d;
- int avail, i, wsize;
-
- fill_dbregs(NULL, &d);
-
- avail = 0;
- for(i = 0; i < 4; i++) {
- if (!DBREG_DR7_ENABLED(d.dr[7], i))
- avail++;
- }
-
- if (avail * 4 < size)
- return (-1);
-
- for (i = 0; i < 4 && (size > 0); i++) {
- if (!DBREG_DR7_ENABLED(d.dr[7], i)) {
- if (size > 2)
- wsize = 4;
- else
- wsize = size;
- i386_set_watch(i, addr, wsize,
- DBREG_DR7_WRONLY, &d);
- addr += wsize;
- size -= wsize;
- }
- }
-
- set_dbregs(NULL, &d);
-
- return(0);
-}
-
-int
-db_md_clr_watchpoint(addr, size)
- db_expr_t addr;
- db_expr_t size;
-{
- struct dbreg d;
- int i;
-
- fill_dbregs(NULL, &d);
-
- for(i = 0; i < 4; i++) {
- if (DBREG_DR7_ENABLED(d.dr[7], i)) {
- if ((DBREG_DRX((&d), i) >= addr) &&
- (DBREG_DRX((&d), i) < addr+size))
- i386_clr_watch(i, &d);
- }
- }
-
- set_dbregs(NULL, &d);
-
- return(0);
-}
-
-static const char *
-watchtype_str(type)
- int type;
-{
- switch (type) {
- case DBREG_DR7_EXEC : return "execute"; break;
- case DBREG_DR7_RDWR : return "read/write"; break;
- case DBREG_DR7_WRONLY : return "write"; break;
- default : return "invalid"; break;
- }
+ return (dbreg_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size));
}
void
db_md_list_watchpoints(void)
{
- struct dbreg d;
- int i, len, type;
-
- fill_dbregs(NULL, &d);
-
- db_printf("\nhardware watchpoints:\n");
- db_printf(" watch status type len address\n");
- db_printf(" ----- -------- ---------- --- ----------\n");
- for (i = 0; i < 4; i++) {
- if (DBREG_DR7_ENABLED(d.dr[7], i)) {
- type = DBREG_DR7_ACCESS(d.dr[7], i);
- len = DBREG_DR7_LEN(d.dr[7], i);
- db_printf(" %-5d %-8s %10s %3d ",
- i, "enabled", watchtype_str(type), len + 1);
- db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
- db_printf("\n");
- } else {
- db_printf(" %-5d disabled\n", i);
- }
- }
- db_printf("\ndebug register values:\n");
- for (i = 0; i < 8; i++)
- if (i != 4 && i != 5)
- db_printf(" dr%d 0x%08x\n", i, DBREG_DRX(&d, i));
- db_printf("\n");
+ dbreg_list_watchpoints();
}
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -120,6 +120,9 @@
bool cpu_mwait_usable(void);
void cpu_probe_amdc1e(void);
void cpu_setregs(void);
+int dbreg_set_watchpoint(vm_offset_t addr, vm_size_t size);
+int dbreg_clr_watchpoint(vm_offset_t addr, vm_size_t size);
+void dbreg_list_watchpoints(void);
bool disable_wp(void);
void restore_wp(bool old_wp);
void finishidentcpu(void);
diff --git a/sys/x86/x86/dbreg.c b/sys/x86/x86/dbreg.c
new file mode 100644
--- /dev/null
+++ b/sys/x86/x86/dbreg.c
@@ -0,0 +1,267 @@
+/*-
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * 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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS 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.
+ */
+
+#include "opt_ddb.h"
+
+#include <sys/types.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
+#include <sys/systm.h>
+
+#include <machine/frame.h>
+#include <machine/md_var.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+
+#define NDBREGS 4
+#ifdef __amd64__
+#define MAXWATCHSIZE 8
+#else
+#define MAXWATCHSIZE 4
+#endif
+
+/*
+ * Set a watchpoint in the debug register denoted by 'watchnum'.
+ */
+static void
+dbreg_set_watchreg(int watchnum, vm_offset_t watchaddr, vm_size_t size,
+ int access, struct dbreg *d)
+{
+ int len;
+
+ MPASS(watchnum >= 0 && watchnum < NDBREGS);
+
+ /* size must be 1 for an execution breakpoint */
+ if (access == DBREG_DR7_EXEC)
+ size = 1;
+
+ /*
+ * we can watch a 1, 2, or 4 byte sized location
+ */
+ switch (size) {
+ case 1:
+ len = DBREG_DR7_LEN_1;
+ break;
+ case 2:
+ len = DBREG_DR7_LEN_2;
+ break;
+ case 4:
+ len = DBREG_DR7_LEN_4;
+ break;
+#if MAXWATCHSIZE >= 8
+ case 8:
+ len = DBREG_DR7_LEN_8;
+ break;
+#endif
+ default:
+ return;
+ }
+
+ /* clear the bits we are about to affect */
+ d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
+
+ /* set drN register to the address, N=watchnum */
+ DBREG_DRX(d, watchnum) = watchaddr;
+
+ /* enable the watchpoint */
+ d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
+ DBREG_DR7_GLOBAL_ENABLE);
+}
+
+/*
+ * Remove a watchpoint from the debug register denoted by 'watchnum'.
+ */
+static void
+dbreg_clr_watchreg(int watchnum, struct dbreg *d)
+{
+ MPASS(watchnum >= 0 && watchnum < NDBREGS);
+
+ d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
+ DBREG_DRX(d, watchnum) = 0;
+}
+
+/*
+ * Sync the debug registers. Other cores will read these values from the PCPU
+ * area when they resume. See amd64_db_resume_dbreg() below.
+ */
+static void
+dbreg_sync(struct dbreg *dp)
+{
+#ifdef __amd64__
+ struct pcpu *pc;
+ int cpu, c;
+
+ cpu = PCPU_GET(cpuid);
+ CPU_FOREACH(c) {
+ if (c == cpu)
+ continue;
+ pc = pcpu_find(c);
+ memcpy(pc->pc_dbreg, dp, sizeof(*dp));
+ pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
+ }
+#endif
+}
+
+int
+dbreg_set_watchpoint(vm_offset_t addr, vm_size_t size)
+{
+ struct dbreg *d;
+ int avail, i, wsize;
+
+#ifdef __amd64__
+ d = (struct dbreg *)PCPU_PTR(dbreg);
+#else
+ /* debug registers aren't stored in PCPU on i386. */
+ struct dbreg d_temp;
+ d = &d_temp;
+#endif
+
+ fill_dbregs(NULL, d);
+
+ /*
+ * Check if there are enough available registers to cover the desired
+ * area.
+ */
+ avail = 0;
+ for (i = 0; i < NDBREGS; i++) {
+ if (!DBREG_DR7_ENABLED(d->dr[7], i))
+ avail++;
+ }
+
+ if (avail * MAXWATCHSIZE < size)
+ return (-1);
+
+ for (i = 0; i < NDBREGS && size > 0; i++) {
+ if (!DBREG_DR7_ENABLED(d->dr[7], i)) {
+ if ((size >= 8 || (avail == 1 && size > 4)) &&
+ MAXWATCHSIZE == 8)
+ wsize = 8;
+ else if (size > 2)
+ wsize = 4;
+ else
+ wsize = size;
+ dbreg_set_watchreg(i, addr, wsize, DBREG_DR7_WRONLY, d);
+ addr += wsize;
+ size -= wsize;
+ avail--;
+ }
+ }
+
+ set_dbregs(NULL, d);
+ dbreg_sync(d);
+
+ return (0);
+}
+
+int
+dbreg_clr_watchpoint(vm_offset_t addr, vm_size_t size)
+{
+ struct dbreg *d;
+ int i;
+
+#ifdef __amd64__
+ d = (struct dbreg *)PCPU_PTR(dbreg);
+#else
+ /* debug registers aren't stored in PCPU on i386. */
+ struct dbreg d_temp;
+ d = &d_temp;
+#endif
+ fill_dbregs(NULL, d);
+
+ for (i = 0; i < NDBREGS; i++) {
+ if (DBREG_DR7_ENABLED(d->dr[7], i)) {
+ if (DBREG_DRX((d), i) >= addr &&
+ DBREG_DRX((d), i) < addr + size)
+ dbreg_clr_watchreg(i, d);
+ }
+ }
+
+ set_dbregs(NULL, d);
+ dbreg_sync(d);
+
+ return (0);
+}
+
+#ifdef DDB
+static const char *
+watchtype_str(int type)
+{
+
+ switch (type) {
+ case DBREG_DR7_EXEC:
+ return ("execute");
+ case DBREG_DR7_RDWR:
+ return ("read/write");
+ case DBREG_DR7_WRONLY:
+ return ("write");
+ default:
+ return ("invalid");
+ }
+}
+
+void
+dbreg_list_watchpoints(void)
+{
+ struct dbreg d;
+ int i, len, type;
+
+ fill_dbregs(NULL, &d);
+
+ db_printf("\nhardware watchpoints:\n");
+ db_printf(" watch status type len address\n");
+ db_printf(" ----- -------- ---------- --- ----------\n");
+ for (i = 0; i < NDBREGS; i++) {
+ if (DBREG_DR7_ENABLED(d.dr[7], i)) {
+ type = DBREG_DR7_ACCESS(d.dr[7], i);
+ len = DBREG_DR7_LEN(d.dr[7], i);
+ db_printf(" %-5d %-8s %10s %3d ",
+ i, "enabled", watchtype_str(type), len + 1);
+ db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
+ db_printf("\n");
+ } else {
+ db_printf(" %-5d disabled\n", i);
+ }
+ }
+}
+#endif
+
+#ifdef __amd64__
+/* Sync debug registers when resuming from debugger. */
+void
+amd64_db_resume_dbreg(void)
+{
+ struct dbreg *d;
+
+ switch (PCPU_GET(dbreg_cmd)) {
+ case PC_DBREG_CMD_LOAD:
+ d = (struct dbreg *)PCPU_PTR(dbreg);
+ set_dbregs(NULL, d);
+ PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
+ break;
+ }
+}
+#endif

File Metadata

Mime Type
text/plain
Expires
Tue, Oct 1, 11:09 AM (6 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13187352
Default Alt Text
D29153.diff (15 KB)

Event Timeline