166174Sbsd/*
266174Sbsd * Copyright 2000  Brian S. Dean <bsd@bsdhome.com>
366174Sbsd * All Rights Reserved.
466174Sbsd *
566174Sbsd * Redistribution and use in source and binary forms, with or without
666174Sbsd * modification, are permitted provided that the following conditions
766174Sbsd * are met:
866174Sbsd *
966174Sbsd * 1. Redistributions of source code must retain the above copyright
1066174Sbsd *    notice, this list of conditions and the following disclaimer.
1166174Sbsd * 2. Redistributions in binary form must reproduce the above copyright
1266174Sbsd *    notice, this list of conditions and the following disclaimer in the
1366174Sbsd *    documentation and/or other materials provided with the distribution.
1466174Sbsd *
1566174Sbsd * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
1666174Sbsd * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1766174Sbsd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1866174Sbsd * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
1966174Sbsd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2066174Sbsd * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
2166174Sbsd * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2266174Sbsd * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2366174Sbsd * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2466174Sbsd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2566174Sbsd * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2666174Sbsd * DAMAGE.
2766174Sbsd */
2866174Sbsd
2992986Sobrien#include <sys/cdefs.h>
3092986Sobrien__FBSDID("$FreeBSD$");
3166174Sbsd
3266174Sbsd#include <machine/reg.h>
3366174Sbsd#include <machine/sysarch.h>
3466174Sbsd
3566174Sbsdint
3666174Sbsdi386_set_watch(int watchnum, unsigned int watchaddr, int size,
3766174Sbsd               int access, struct dbreg * d)
3866174Sbsd{
3966174Sbsd	int i;
4066174Sbsd	unsigned int mask;
4166174Sbsd
4266174Sbsd	if (watchnum == -1) {
4366174Sbsd		for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
44105604Ssam			if ((DBREG_DRX(d,7) & mask) == 0)
4566174Sbsd				break;
4666174Sbsd		if (i < 4)
4766174Sbsd			watchnum = i;
4866174Sbsd		else
4966174Sbsd			return -1;
5066174Sbsd	}
5166174Sbsd
5266174Sbsd	switch (access) {
5366174Sbsd	case DBREG_DR7_EXEC:
5466174Sbsd		size = 1; /* size must be 1 for an execution breakpoint */
5566174Sbsd		/* fall through */
5666174Sbsd	case DBREG_DR7_WRONLY:
5766174Sbsd	case DBREG_DR7_RDWR:
5866174Sbsd		break;
5966174Sbsd	default : return -1; break;
6066174Sbsd	}
6166174Sbsd
6266174Sbsd	/*
6366174Sbsd	 * we can watch a 1, 2, or 4 byte sized location
6466174Sbsd	 */
6566174Sbsd	switch (size) {
6666174Sbsd	case 1  : mask = 0x00; break;
6766174Sbsd	case 2  : mask = 0x01 << 2; break;
6866174Sbsd	case 4  : mask = 0x03 << 2; break;
6966174Sbsd	default : return -1; break;
7066174Sbsd	}
7166174Sbsd
7266174Sbsd	mask |= access;
7366174Sbsd
7466174Sbsd	/* clear the bits we are about to affect */
75105604Ssam	DBREG_DRX(d,7) &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
7666174Sbsd
7766174Sbsd	/* set drN register to the address, N=watchnum */
7866174Sbsd	DBREG_DRX(d,watchnum) = watchaddr;
7966174Sbsd
8066174Sbsd	/* enable the watchpoint */
81105604Ssam	DBREG_DRX(d,7) |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
8266174Sbsd
8366174Sbsd	return watchnum;
8466174Sbsd}
85