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