1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/compiler.h>
8 #include <linux/hw_breakpoint.h>
9 #include <linux/kernel.h>
14 #include "../perf-sys.h"
16 #define WP_TEST_ASSERT_VAL(fd, text, val) \
19 wp_read(fd, &count, sizeof(long long)); \
20 TEST_ASSERT_VAL(text, count == val); \
24 /* Only breakpoint length less-than 8 has hardware support on i386. */
32 static int wp_read(int fd
, long long *count
, int size
)
34 int ret
= read(fd
, count
, size
);
37 pr_debug("failed to read: %d\n", ret
);
43 static void get__perf_event_attr(struct perf_event_attr
*attr
, int wp_type
,
44 void *wp_addr
, unsigned long wp_len
)
46 memset(attr
, 0, sizeof(struct perf_event_attr
));
47 attr
->type
= PERF_TYPE_BREAKPOINT
;
48 attr
->size
= sizeof(struct perf_event_attr
);
50 attr
->bp_type
= wp_type
;
51 attr
->bp_addr
= (unsigned long)wp_addr
;
52 attr
->bp_len
= wp_len
;
53 attr
->sample_period
= 1;
54 attr
->sample_type
= PERF_SAMPLE_IP
;
55 attr
->exclude_kernel
= 1;
59 static int __event(int wp_type
, void *wp_addr
, unsigned long wp_len
)
62 struct perf_event_attr attr
;
64 get__perf_event_attr(&attr
, wp_type
, wp_addr
, wp_len
);
65 fd
= sys_perf_event_open(&attr
, 0, -1, -1,
66 perf_event_open_cloexec_flag());
69 pr_debug("failed opening event %x\n", attr
.bp_type
);
76 static int test__wp_ro(struct test_suite
*test __maybe_unused
,
77 int subtest __maybe_unused
)
79 #if defined(__s390x__) || defined(__x86_64__) || defined(__i386__)
83 unsigned long tmp
, tmp1
= rand();
85 fd
= __event(HW_BREAKPOINT_R
, (void *)&data1
, sizeof(data1
));
87 return fd
== -ENODEV
? TEST_SKIP
: -1;
90 WP_TEST_ASSERT_VAL(fd
, "RO watchpoint", 1);
93 WP_TEST_ASSERT_VAL(fd
, "RO watchpoint", 1);
100 static int test__wp_wo(struct test_suite
*test __maybe_unused
,
101 int subtest __maybe_unused
)
103 #if defined(__s390x__)
107 unsigned long tmp
, tmp1
= rand();
109 fd
= __event(HW_BREAKPOINT_W
, (void *)&data1
, sizeof(data1
));
111 return fd
== -ENODEV
? TEST_SKIP
: -1;
114 WP_TEST_ASSERT_VAL(fd
, "WO watchpoint", 0);
117 WP_TEST_ASSERT_VAL(fd
, "WO watchpoint", 1);
124 static int test__wp_rw(struct test_suite
*test __maybe_unused
,
125 int subtest __maybe_unused
)
127 #if defined(__s390x__)
131 unsigned long tmp
, tmp1
= rand();
133 fd
= __event(HW_BREAKPOINT_R
| HW_BREAKPOINT_W
, (void *)&data1
,
136 return fd
== -ENODEV
? TEST_SKIP
: -1;
139 WP_TEST_ASSERT_VAL(fd
, "RW watchpoint", 1);
142 WP_TEST_ASSERT_VAL(fd
, "RW watchpoint", 2);
149 static int test__wp_modify(struct test_suite
*test __maybe_unused
, int subtest __maybe_unused
)
151 #if defined(__s390x__)
155 unsigned long tmp
= rand();
156 struct perf_event_attr new_attr
;
158 fd
= __event(HW_BREAKPOINT_W
, (void *)&data1
, sizeof(data1
));
160 return fd
== -ENODEV
? TEST_SKIP
: -1;
163 WP_TEST_ASSERT_VAL(fd
, "Modify watchpoint", 1);
165 /* Modify watchpoint with disabled = 1 */
166 get__perf_event_attr(&new_attr
, HW_BREAKPOINT_W
, (void *)&data2
[0],
168 new_attr
.disabled
= 1;
169 ret
= ioctl(fd
, PERF_EVENT_IOC_MODIFY_ATTRIBUTES
, &new_attr
);
171 if (errno
== ENOTTY
) {
172 test
->test_cases
[subtest
].skip_reason
= "missing kernel support";
176 pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
181 data2
[1] = tmp
; /* Not Counted */
182 WP_TEST_ASSERT_VAL(fd
, "Modify watchpoint", 1);
184 /* Enable the event */
185 ioctl(fd
, PERF_EVENT_IOC_ENABLE
, 0);
187 pr_debug("Failed to enable event\n");
192 data2
[1] = tmp
; /* Counted */
193 WP_TEST_ASSERT_VAL(fd
, "Modify watchpoint", 2);
195 data2
[2] = tmp
; /* Not Counted */
196 WP_TEST_ASSERT_VAL(fd
, "Modify watchpoint", 2);
203 static struct test_case wp_tests
[] = {
204 TEST_CASE_REASON("Read Only Watchpoint", wp_ro
, "missing hardware support"),
205 TEST_CASE_REASON("Write Only Watchpoint", wp_wo
, "missing hardware support"),
206 TEST_CASE_REASON("Read / Write Watchpoint", wp_rw
, "missing hardware support"),
207 TEST_CASE_REASON("Modify Watchpoint", wp_modify
, "missing hardware support"),
211 struct test_suite suite__wp
= {
212 .desc
= "Watchpoint",
213 .test_cases
= wp_tests
,