xref: /minix3/minix/kernel/arch/i386/breakpoints.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include "kernel/kernel.h"
2*433d6423SLionel Sambuc #include "arch_proto.h"
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc #include "debugreg.h"
5*433d6423SLionel Sambuc 
breakpoint_set(phys_bytes linaddr,int bp,const int flags)6*433d6423SLionel Sambuc int breakpoint_set(phys_bytes linaddr, int bp, const int flags)
7*433d6423SLionel Sambuc {
8*433d6423SLionel Sambuc 	unsigned long dr7, dr7flags;
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc 	if (bp >= BREAKPOINT_COUNT)
11*433d6423SLionel Sambuc 		return EINVAL;
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc 	/* convert flags */
14*433d6423SLionel Sambuc 	dr7flags = 0;
15*433d6423SLionel Sambuc 	switch (flags & BREAKPOINT_FLAG_RW_MASK) {
16*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_RW_EXEC:  dr7flags |= DR7_RW_EXEC(bp);  break;
17*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_RW_WRITE: dr7flags |= DR7_RW_WRITE(bp); break;
18*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_RW_RW:    dr7flags |= DR7_RW_RW(bp);    break;
19*433d6423SLionel Sambuc 		default: return EINVAL;
20*433d6423SLionel Sambuc 	}
21*433d6423SLionel Sambuc 	switch (flags & BREAKPOINT_FLAG_LEN_MASK) {
22*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_LEN_1: dr7flags |= DR7_LN_1(bp); break;
23*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_LEN_2: dr7flags |= DR7_LN_2(bp); break;
24*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_LEN_4: dr7flags |= DR7_LN_4(bp); break;
25*433d6423SLionel Sambuc 		default: return EINVAL;
26*433d6423SLionel Sambuc 	}
27*433d6423SLionel Sambuc 	switch (flags & BREAKPOINT_FLAG_MODE_MASK) {
28*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_MODE_OFF: break;
29*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_MODE_LOCAL: dr7flags |= DR7_L(bp); break;
30*433d6423SLionel Sambuc 		case BREAKPOINT_FLAG_MODE_GLOBAL: dr7flags |= DR7_G(bp); break;
31*433d6423SLionel Sambuc 		default: return EINVAL;
32*433d6423SLionel Sambuc 	}
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc 	/* disable breakpoint before setting address */
35*433d6423SLionel Sambuc 	dr7 = st_dr7();
36*433d6423SLionel Sambuc 	dr7 &= ~(DR7_L(bp) | DR7_G(bp) | DR7_RW_MASK(bp) | DR7_LN_MASK(bp));
37*433d6423SLionel Sambuc 	ld_dr7(dr7);
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc 	/* need to set new breakpoint? */
40*433d6423SLionel Sambuc 	if ((flags & BREAKPOINT_FLAG_MODE_MASK) == BREAKPOINT_FLAG_MODE_OFF)
41*433d6423SLionel Sambuc 		return 0;
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc 	/* set breakpoint address */
44*433d6423SLionel Sambuc 	switch (bp) {
45*433d6423SLionel Sambuc 		case 0: ld_dr0(linaddr); break;
46*433d6423SLionel Sambuc 		case 1: ld_dr1(linaddr); break;
47*433d6423SLionel Sambuc 		case 2: ld_dr2(linaddr); break;
48*433d6423SLionel Sambuc 		case 3: ld_dr3(linaddr); break;
49*433d6423SLionel Sambuc 		default: panic("%s:%d: invalid breakpoint index", __FILE__,  __LINE__);
50*433d6423SLionel Sambuc 	}
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc 	/* set new flags */
53*433d6423SLionel Sambuc 	dr7 |= dr7flags;
54*433d6423SLionel Sambuc 	ld_dr7(dr7);
55*433d6423SLionel Sambuc 	return 0;
56*433d6423SLionel Sambuc }
57*433d6423SLionel Sambuc 
58