|
@@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
|
|
|
*dr7 |= encode_dr7(i, info->len, info->type);
|
|
*dr7 |= encode_dr7(i, info->len, info->type);
|
|
|
|
|
|
|
|
set_debugreg(*dr7, 7);
|
|
set_debugreg(*dr7, 7);
|
|
|
|
|
+ if (info->mask)
|
|
|
|
|
+ set_dr_addr_mask(info->mask, i);
|
|
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
@@ -161,29 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
|
|
|
*dr7 &= ~__encode_dr7(i, info->len, info->type);
|
|
*dr7 &= ~__encode_dr7(i, info->len, info->type);
|
|
|
|
|
|
|
|
set_debugreg(*dr7, 7);
|
|
set_debugreg(*dr7, 7);
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-static int get_hbp_len(u8 hbp_len)
|
|
|
|
|
-{
|
|
|
|
|
- unsigned int len_in_bytes = 0;
|
|
|
|
|
-
|
|
|
|
|
- switch (hbp_len) {
|
|
|
|
|
- case X86_BREAKPOINT_LEN_1:
|
|
|
|
|
- len_in_bytes = 1;
|
|
|
|
|
- break;
|
|
|
|
|
- case X86_BREAKPOINT_LEN_2:
|
|
|
|
|
- len_in_bytes = 2;
|
|
|
|
|
- break;
|
|
|
|
|
- case X86_BREAKPOINT_LEN_4:
|
|
|
|
|
- len_in_bytes = 4;
|
|
|
|
|
- break;
|
|
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
|
|
- case X86_BREAKPOINT_LEN_8:
|
|
|
|
|
- len_in_bytes = 8;
|
|
|
|
|
- break;
|
|
|
|
|
-#endif
|
|
|
|
|
- }
|
|
|
|
|
- return len_in_bytes;
|
|
|
|
|
|
|
+ if (info->mask)
|
|
|
|
|
+ set_dr_addr_mask(0, i);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -196,7 +177,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp)
|
|
|
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
|
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
|
|
|
|
|
|
|
va = info->address;
|
|
va = info->address;
|
|
|
- len = get_hbp_len(info->len);
|
|
|
|
|
|
|
+ len = bp->attr.bp_len;
|
|
|
|
|
|
|
|
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
|
|
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
|
|
|
}
|
|
}
|
|
@@ -277,6 +258,8 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Len */
|
|
/* Len */
|
|
|
|
|
+ info->mask = 0;
|
|
|
|
|
+
|
|
|
switch (bp->attr.bp_len) {
|
|
switch (bp->attr.bp_len) {
|
|
|
case HW_BREAKPOINT_LEN_1:
|
|
case HW_BREAKPOINT_LEN_1:
|
|
|
info->len = X86_BREAKPOINT_LEN_1;
|
|
info->len = X86_BREAKPOINT_LEN_1;
|
|
@@ -293,11 +276,17 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
break;
|
|
break;
|
|
|
#endif
|
|
#endif
|
|
|
default:
|
|
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;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
/*
|
|
/*
|
|
|
* Validate the arch-specific HW Breakpoint register settings
|
|
* Validate the arch-specific HW Breakpoint register settings
|
|
|
*/
|
|
*/
|
|
@@ -312,11 +301,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
if (ret)
|
|
if (ret)
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
|
- ret = -EINVAL;
|
|
|
|
|
-
|
|
|
|
|
switch (info->len) {
|
|
switch (info->len) {
|
|
|
case X86_BREAKPOINT_LEN_1:
|
|
case X86_BREAKPOINT_LEN_1:
|
|
|
align = 0;
|
|
align = 0;
|
|
|
|
|
+ if (info->mask)
|
|
|
|
|
+ align = info->mask;
|
|
|
break;
|
|
break;
|
|
|
case X86_BREAKPOINT_LEN_2:
|
|
case X86_BREAKPOINT_LEN_2:
|
|
|
align = 1;
|
|
align = 1;
|
|
@@ -330,7 +319,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
break;
|
|
break;
|
|
|
#endif
|
|
#endif
|
|
|
default:
|
|
default:
|
|
|
- return ret;
|
|
|
|
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|