diff options
Diffstat (limited to 'lib/libc/i386/sys/i386_set_watch.c')
-rw-r--r-- | lib/libc/i386/sys/i386_set_watch.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/libc/i386/sys/i386_set_watch.c b/lib/libc/i386/sys/i386_set_watch.c new file mode 100644 index 0000000..bb710dc --- /dev/null +++ b/lib/libc/i386/sys/i386_set_watch.c @@ -0,0 +1,88 @@ +/* + * Copyright 2000 Brian S. Dean <bsd@bsdhome.com> + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* + * $FreeBSD$ + */ + + +#include <machine/reg.h> +#include <machine/sysarch.h> + + +int +i386_set_watch(int watchnum, unsigned int watchaddr, int size, + int access, struct dbreg * d) +{ + int i; + unsigned int mask; + + if (watchnum == -1) { + for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2) + if ((d->dr7 & mask) == 0) + 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; break; + } + + /* + * we can watch a 1, 2, or 4 byte sized location + */ + switch (size) { + case 1 : mask = 0x00; break; + case 2 : mask = 0x01 << 2; break; + case 4 : mask = 0x03 << 2; break; + default : return -1; break; + } + + mask |= access; + + /* clear the bits we are about to affect */ + d->dr7 &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16))); + + /* set drN register to the address, N=watchnum */ + DBREG_DRX(d,watchnum) = watchaddr; + + /* enable the watchpoint */ + d->dr7 |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16)); + + return watchnum; +} |