diff options
author | jlemon <jlemon@FreeBSD.org> | 1999-07-09 04:16:00 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 1999-07-09 04:16:00 +0000 |
commit | fb9048b07bd1c35bc75d6a5619a8a66c0cf40b4f (patch) | |
tree | 5035c891109a8a7303adbff335bde82a04b1c903 /sys/amd64 | |
parent | 8402d41bdeafb13d775baf552ba6f1faba0aadca (diff) | |
download | FreeBSD-src-fb9048b07bd1c35bc75d6a5619a8a66c0cf40b4f.zip FreeBSD-src-fb9048b07bd1c35bc75d6a5619a8a66c0cf40b4f.tar.gz |
Implement support for hardware debug registers on the i386.
Submitted by: Brian Dean <brdean@unx.sas.com>
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/cpu_switch.S | 40 | ||||
-rw-r--r-- | sys/amd64/amd64/genassym.c | 9 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 83 | ||||
-rw-r--r-- | sys/amd64/amd64/swtch.s | 40 | ||||
-rw-r--r-- | sys/amd64/include/md_var.h | 4 | ||||
-rw-r--r-- | sys/amd64/include/pcb.h | 11 | ||||
-rw-r--r-- | sys/amd64/include/ptrace.h | 4 | ||||
-rw-r--r-- | sys/amd64/include/reg.h | 15 |
8 files changed, 198 insertions, 8 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 428b0ae..82c9737 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.82 1999/06/01 18:19:45 jlemon Exp $ + * $Id: swtch.s,v 1.83 1999/07/03 06:33:24 alc Exp $ */ #include "npx.h" @@ -480,6 +480,26 @@ ENTRY(cpu_switch) movl %edi,PCB_EDI(%edx) movl %gs,PCB_GS(%edx) + /* test if debug regisers should be saved */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl %dr7,%eax /* yes, do the save */ + movl %eax,PCB_DR7(%edx) + andl $0x0000ff00, %eax /* disable all watchpoints */ + movl %eax,%dr7 + movl %dr6,%eax + movl %eax,PCB_DR6(%edx) + movl %dr3,%eax + movl %eax,PCB_DR3(%edx) + movl %dr2,%eax + movl %eax,PCB_DR2(%edx) + movl %dr1,%eax + movl %eax,PCB_DR1(%edx) + movl %dr0,%eax + movl %eax,PCB_DR0(%edx) +1: + #ifdef SMP movl _mp_lock, %eax /* XXX FIXME: we should be saving the local APIC TPR */ @@ -718,6 +738,24 @@ swtch_com: cpu_switch_load_gs: movl PCB_GS(%edx),%gs + /* test if debug regisers should be restored */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl PCB_DR6(%edx),%eax /* yes, do the restore */ + movl %eax,%dr6 + movl PCB_DR3(%edx),%eax + movl %eax,%dr3 + movl PCB_DR2(%edx),%eax + movl %eax,%dr2 + movl PCB_DR1(%edx),%eax + movl %eax,%dr1 + movl PCB_DR0(%edx),%eax + movl %eax,%dr0 + movl PCB_DR7(%edx),%eax + movl %eax,%dr7 +1: + sti ret diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index 3e92787..dc5a18d 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91 - * $Id: genassym.c,v 1.71 1999/06/28 09:21:41 peter Exp $ + * $Id: genassym.c,v 1.72 1999/07/06 07:13:32 cracauer Exp $ */ #include "opt_user_ldt.h" @@ -128,6 +128,13 @@ main() printf("#define\tTSS_ESP0 %#x\n", OS(i386tss, tss_esp0)); printf("#define\tPCB_USERLDT %#x\n", OS(pcb, pcb_ldt)); printf("#define\tPCB_GS %#x\n", OS(pcb, pcb_gs)); + printf("#define\tPCB_DR0 %#x\n", OS(pcb, pcb_dr0)); + printf("#define\tPCB_DR1 %#x\n", OS(pcb, pcb_dr1)); + printf("#define\tPCB_DR2 %#x\n", OS(pcb, pcb_dr2)); + printf("#define\tPCB_DR3 %#x\n", OS(pcb, pcb_dr3)); + printf("#define\tPCB_DR6 %#x\n", OS(pcb, pcb_dr6)); + printf("#define\tPCB_DR7 %#x\n", OS(pcb, pcb_dr7)); + printf("#define\tPCB_DBREGS %#x\n", PCB_DBREGS ); printf("#define\tPCB_EXT %#x\n", OS(pcb, pcb_ext)); #ifdef SMP printf("#define\tPCB_MPNEST %#x\n", OS(pcb, pcb_mpnest)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index ec11c98..423de12 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.353 1999/07/06 07:13:33 cracauer Exp $ + * $Id: machdep.c,v 1.354 1999/07/08 06:05:48 mckusick Exp $ */ #include "apm.h" @@ -1927,6 +1927,87 @@ set_fpregs(p, fpregs) return (0); } +int +fill_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + dbregs->dr0 = pcb->pcb_dr0; + dbregs->dr1 = pcb->pcb_dr1; + dbregs->dr2 = pcb->pcb_dr2; + dbregs->dr3 = pcb->pcb_dr3; + dbregs->dr4 = 0; + dbregs->dr5 = 0; + dbregs->dr6 = pcb->pcb_dr6; + dbregs->dr7 = pcb->pcb_dr7; + return (0); +} + +int +set_dbregs(p, dbregs) + struct proc *p; + struct dbreg *dbregs; +{ + struct pcb *pcb; + + pcb = &p->p_addr->u_pcb; + + /* + * Don't let a process set a breakpoint that is not within the + * process's address space. If a process could do this, it + * could halt the system by setting a breakpoint in the kernel + * (if ddb was enabled). Thus, we need to check to make sure + * that no breakpoints are being enabled for addresses outside + * process's address space, unless, perhaps, we were called by + * uid 0. + * + * XXX - what about when the watched area of the user's + * address space is written into from within the kernel + * ... wouldn't that still cause a breakpoint to be generated + * from within kernel mode? + */ + + if (p->p_cred->pc_ucred->cr_uid != 0) { + if (dbregs->dr7 & 0x3) { + /* dr0 is enabled */ + if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<2)) { + /* dr1 is enabled */ + if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<4)) { + /* dr2 is enabled */ + if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + + if (dbregs->dr7 & (0x3<<6)) { + /* dr3 is enabled */ + if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) + return (EINVAL); + } + } + + pcb->pcb_dr0 = dbregs->dr0; + pcb->pcb_dr1 = dbregs->dr1; + pcb->pcb_dr2 = dbregs->dr2; + pcb->pcb_dr3 = dbregs->dr3; + pcb->pcb_dr6 = dbregs->dr6; + pcb->pcb_dr7 = dbregs->dr7; + + pcb->pcb_flags |= PCB_DBREGS; + + return (0); +} + #ifndef DDB void Debugger(const char *msg) diff --git a/sys/amd64/amd64/swtch.s b/sys/amd64/amd64/swtch.s index 428b0ae..82c9737 100644 --- a/sys/amd64/amd64/swtch.s +++ b/sys/amd64/amd64/swtch.s @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.82 1999/06/01 18:19:45 jlemon Exp $ + * $Id: swtch.s,v 1.83 1999/07/03 06:33:24 alc Exp $ */ #include "npx.h" @@ -480,6 +480,26 @@ ENTRY(cpu_switch) movl %edi,PCB_EDI(%edx) movl %gs,PCB_GS(%edx) + /* test if debug regisers should be saved */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl %dr7,%eax /* yes, do the save */ + movl %eax,PCB_DR7(%edx) + andl $0x0000ff00, %eax /* disable all watchpoints */ + movl %eax,%dr7 + movl %dr6,%eax + movl %eax,PCB_DR6(%edx) + movl %dr3,%eax + movl %eax,PCB_DR3(%edx) + movl %dr2,%eax + movl %eax,PCB_DR2(%edx) + movl %dr1,%eax + movl %eax,PCB_DR1(%edx) + movl %dr0,%eax + movl %eax,PCB_DR0(%edx) +1: + #ifdef SMP movl _mp_lock, %eax /* XXX FIXME: we should be saving the local APIC TPR */ @@ -718,6 +738,24 @@ swtch_com: cpu_switch_load_gs: movl PCB_GS(%edx),%gs + /* test if debug regisers should be restored */ + movb PCB_FLAGS(%edx),%al + andb $PCB_DBREGS,%al + jz 1f /* no, skip over */ + movl PCB_DR6(%edx),%eax /* yes, do the restore */ + movl %eax,%dr6 + movl PCB_DR3(%edx),%eax + movl %eax,%dr3 + movl PCB_DR2(%edx),%eax + movl %eax,%dr2 + movl PCB_DR1(%edx),%eax + movl %eax,%dr1 + movl PCB_DR0(%edx),%eax + movl %eax,%dr0 + movl PCB_DR7(%edx),%eax + movl %eax,%dr7 +1: + sti ret diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 35b6545..491eb46 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: md_var.h,v 1.28 1999/01/08 16:29:58 bde Exp $ + * $Id: md_var.h,v 1.29 1999/04/28 01:04:02 luoqi Exp $ */ #ifndef _MACHINE_MD_VAR_H_ @@ -64,6 +64,7 @@ typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss)); struct proc; struct reg; struct fpreg; +struct dbreg; void bcopyb __P((const void *from, void *to, size_t len)); void busdma_swi __P((void)); @@ -80,6 +81,7 @@ void doreti_popl_fs __P((void)) __asm(__STRING(doreti_popl_fs)); void doreti_popl_fs_fault __P((void)) __asm(__STRING(doreti_popl_fs_fault)); int fill_fpregs __P((struct proc *, struct fpreg *)); int fill_regs __P((struct proc *p, struct reg *regs)); +int fill_dbregs __P((struct proc *p, struct dbreg *dbregs)); void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); void i486_bzero __P((void *buf, size_t len)); void i586_bcopy __P((const void *from, void *to, size_t len)); diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 2dbc707..5cee924 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91 - * $Id: pcb.h,v 1.27 1999/04/28 01:04:05 luoqi Exp $ + * $Id: pcb.h,v 1.28 1999/06/01 18:20:06 jlemon Exp $ */ #ifndef _I386_PCB_H_ @@ -54,11 +54,20 @@ struct pcb { int pcb_esp; int pcb_ebx; int pcb_eip; + + int pcb_dr0; + int pcb_dr1; + int pcb_dr2; + int pcb_dr3; + int pcb_dr6; + int pcb_dr7; + caddr_t pcb_ldt; /* per process (user) LDT */ int pcb_ldt_len; /* number of LDT entries */ struct save87 pcb_savefpu; /* floating point state for 287/387 */ u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ +#define PCB_DBREGS 0x02 /* process using debug registers */ caddr_t pcb_onfault; /* copyin/out fault recovery */ #ifdef SMP u_long pcb_mpnest; diff --git a/sys/amd64/include/ptrace.h b/sys/amd64/include/ptrace.h index ec3d5aa..2c43a2e 100644 --- a/sys/amd64/include/ptrace.h +++ b/sys/amd64/include/ptrace.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 - * $Id: ptrace.h,v 1.5 1997/02/22 09:35:03 peter Exp $ + * $Id: ptrace.h,v 1.6 1998/05/19 00:00:12 tegge Exp $ */ #ifndef _MACHINE_PTRACE_H_ @@ -44,6 +44,8 @@ #define PT_SETREGS (PT_FIRSTMACH + 2) #define PT_GETFPREGS (PT_FIRSTMACH + 3) #define PT_SETFPREGS (PT_FIRSTMACH + 4) +#define PT_GETDBREGS (PT_FIRSTMACH + 5) +#define PT_SETDBREGS (PT_FIRSTMACH + 6) #ifdef KERNEL int ptrace_read_u_check __P((struct proc *p, vm_offset_t off, size_t len)); diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h index 2470116..994bdfd 100644 --- a/sys/amd64/include/reg.h +++ b/sys/amd64/include/reg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)reg.h 5.5 (Berkeley) 1/18/91 - * $Id: reg.h,v 1.17 1999/04/03 22:19:59 jdp Exp $ + * $Id: reg.h,v 1.18 1999/04/28 01:04:06 luoqi Exp $ */ #ifndef _MACHINE_REG_H_ @@ -118,6 +118,18 @@ struct fpreg { unsigned char fpr_pad[64]; }; +struct dbreg { + unsigned int dr0; /* debug address register 0 */ + unsigned int dr1; /* debug address register 1 */ + unsigned int dr2; /* debug address register 2 */ + unsigned int dr3; /* debug address register 3 */ + unsigned int dr4; /* reserved */ + unsigned int dr5; /* reserved */ + unsigned int dr6; /* debug status register */ + unsigned int dr7; /* debug control register */ +}; + + #ifdef KERNEL /* * XXX these interfaces are MI, so they should be declared in a MI place. @@ -125,6 +137,7 @@ struct fpreg { int set_fpregs __P((struct proc *, struct fpreg *)); int set_regs __P((struct proc *p, struct reg *regs)); void setregs __P((struct proc *, u_long, u_long, u_long)); +int set_dbregs __P((struct proc *p, struct dbreg *dbregs)); #endif #endif /* !_MACHINE_REG_H_ */ |