|
@@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
|
|
|
*dr7 |= encode_dr7(i, info->len, info->type);
|
|
|
|
|
|
set_debugreg(*dr7, 7);
|
|
|
+ if (info->mask)
|
|
|
+ set_dr_addr_mask(info->mask, i);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -161,6 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
|
|
|
*dr7 &= ~__encode_dr7(i, info->len, info->type);
|
|
|
|
|
|
set_debugreg(*dr7, 7);
|
|
|
+ if (info->mask)
|
|
|
+ set_dr_addr_mask(0, i);
|
|
|
}
|
|
|
|
|
|
static int get_hbp_len(u8 hbp_len)
|
|
@@ -277,6 +281,8 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
}
|
|
|
|
|
|
/* Len */
|
|
|
+ info->mask = 0;
|
|
|
+
|
|
|
switch (bp->attr.bp_len) {
|
|
|
case HW_BREAKPOINT_LEN_1:
|
|
|
info->len = X86_BREAKPOINT_LEN_1;
|
|
@@ -293,11 +299,17 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
break;
|
|
|
#endif
|
|
|
default:
|
|
|
- return -EINVAL;
|
|
|
+ if (!is_power_of_2(bp->attr.bp_len))
|
|
|
+ return -EINVAL;
|
|
|
+ if (!cpu_has_bpext)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ info->mask = bp->attr.bp_len - 1;
|
|
|
+ info->len = X86_BREAKPOINT_LEN_1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
/*
|
|
|
* Validate the arch-specific HW Breakpoint register settings
|
|
|
*/
|
|
@@ -312,11 +324,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- ret = -EINVAL;
|
|
|
-
|
|
|
switch (info->len) {
|
|
|
case X86_BREAKPOINT_LEN_1:
|
|
|
align = 0;
|
|
|
+ if (info->mask)
|
|
|
+ align = info->mask;
|
|
|
break;
|
|
|
case X86_BREAKPOINT_LEN_2:
|
|
|
align = 1;
|
|
@@ -330,7 +342,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
break;
|
|
|
#endif
|
|
|
default:
|
|
|
- return ret;
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
}
|
|
|
|
|
|
/*
|