Linux Audio

Check our new training course

Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdlib.h>
  3#include <string.h>
  4#include <unistd.h>
  5#include <sys/ioctl.h>
  6#include <linux/hw_breakpoint.h>
  7#include <linux/kernel.h>
  8#include "tests.h"
  9#include "debug.h"
 10#include "event.h"
 11#include "cloexec.h"
 12#include "../perf-sys.h"
 13
 14#define WP_TEST_ASSERT_VAL(fd, text, val)       \
 15do {                                            \
 16	long long count;                        \
 17	wp_read(fd, &count, sizeof(long long)); \
 18	TEST_ASSERT_VAL(text, count == val);    \
 19} while (0)
 20
 21volatile u64 data1;
 22volatile u8 data2[3];
 23
 24static int wp_read(int fd, long long *count, int size)
 25{
 26	int ret = read(fd, count, size);
 27
 28	if (ret != size) {
 29		pr_debug("failed to read: %d\n", ret);
 30		return -1;
 31	}
 32	return 0;
 33}
 34
 35static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
 36				 void *wp_addr, unsigned long wp_len)
 37{
 38	memset(attr, 0, sizeof(struct perf_event_attr));
 39	attr->type           = PERF_TYPE_BREAKPOINT;
 40	attr->size           = sizeof(struct perf_event_attr);
 41	attr->config         = 0;
 42	attr->bp_type        = wp_type;
 43	attr->bp_addr        = (unsigned long)wp_addr;
 44	attr->bp_len         = wp_len;
 45	attr->sample_period  = 1;
 46	attr->sample_type    = PERF_SAMPLE_IP;
 47	attr->exclude_kernel = 1;
 48	attr->exclude_hv     = 1;
 49}
 50
 51static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
 52{
 53	int fd;
 54	struct perf_event_attr attr;
 55
 56	get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
 57	fd = sys_perf_event_open(&attr, 0, -1, -1,
 58				 perf_event_open_cloexec_flag());
 59	if (fd < 0)
 60		pr_debug("failed opening event %x\n", attr.bp_type);
 61
 62	return fd;
 63}
 64
 65static int wp_ro_test(void)
 66{
 67	int fd;
 68	unsigned long tmp, tmp1 = rand();
 69
 70	fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
 71	if (fd < 0)
 72		return -1;
 73
 74	tmp = data1;
 75	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
 76
 77	data1 = tmp1 + tmp;
 78	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
 79
 80	close(fd);
 81	return 0;
 82}
 83
 84static int wp_wo_test(void)
 85{
 86	int fd;
 87	unsigned long tmp, tmp1 = rand();
 88
 89	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
 90	if (fd < 0)
 91		return -1;
 92
 93	tmp = data1;
 94	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
 95
 96	data1 = tmp1 + tmp;
 97	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
 98
 99	close(fd);
100	return 0;
101}
102
103static int wp_rw_test(void)
104{
105	int fd;
106	unsigned long tmp, tmp1 = rand();
107
108	fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
109		     sizeof(data1));
110	if (fd < 0)
111		return -1;
112
113	tmp = data1;
114	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
115
116	data1 = tmp1 + tmp;
117	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
118
119	close(fd);
120	return 0;
121}
122
123static int wp_modify_test(void)
124{
125	int fd, ret;
126	unsigned long tmp = rand();
127	struct perf_event_attr new_attr;
128
129	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
130	if (fd < 0)
131		return -1;
132
133	data1 = tmp;
134	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
135
136	/* Modify watchpoint with disabled = 1 */
137	get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
138			     sizeof(u8) * 2);
139	new_attr.disabled = 1;
140	ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
141	if (ret < 0) {
142		pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
143		close(fd);
144		return ret;
145	}
146
147	data2[1] = tmp; /* Not Counted */
148	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
149
150	/* Enable the event */
151	ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
152	if (ret < 0) {
153		pr_debug("Failed to enable event\n");
154		close(fd);
155		return ret;
156	}
157
158	data2[1] = tmp; /* Counted */
159	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
160
161	data2[2] = tmp; /* Not Counted */
162	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
163
164	close(fd);
165	return 0;
166}
167
168static bool wp_ro_supported(void)
169{
170#if defined (__x86_64__) || defined (__i386__)
171	return false;
172#else
173	return true;
174#endif
175}
176
177static void wp_ro_skip_msg(void)
178{
179#if defined (__x86_64__) || defined (__i386__)
180	pr_debug("Hardware does not support read only watchpoints.\n");
 
 
181#endif
182}
183
184static struct {
185	const char *desc;
186	int (*target_func)(void);
187	bool (*is_supported)(void);
188	void (*skip_msg)(void);
189} wp_testcase_table[] = {
190	{
191		.desc = "Read Only Watchpoint",
192		.target_func = &wp_ro_test,
193		.is_supported = &wp_ro_supported,
194		.skip_msg = &wp_ro_skip_msg,
195	},
196	{
197		.desc = "Write Only Watchpoint",
198		.target_func = &wp_wo_test,
199	},
200	{
201		.desc = "Read / Write Watchpoint",
202		.target_func = &wp_rw_test,
203	},
204	{
205		.desc = "Modify Watchpoint",
206		.target_func = &wp_modify_test,
207	},
208};
209
210int test__wp_subtest_get_nr(void)
211{
212	return (int)ARRAY_SIZE(wp_testcase_table);
213}
214
215const char *test__wp_subtest_get_desc(int i)
216{
217	if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
218		return NULL;
219	return wp_testcase_table[i].desc;
220}
221
 
 
 
 
 
 
 
 
 
222int test__wp(struct test *test __maybe_unused, int i)
223{
224	if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
225		return TEST_FAIL;
226
227	if (wp_testcase_table[i].is_supported &&
228	    !wp_testcase_table[i].is_supported()) {
229		wp_testcase_table[i].skip_msg();
230		return TEST_SKIP;
231	}
232
233	return !wp_testcase_table[i].target_func() ? TEST_OK : TEST_FAIL;
234}
235
236/* The s390 so far does not have support for
237 * instruction breakpoint using the perf_event_open() system call.
238 */
239bool test__wp_is_supported(void)
240{
241#if defined(__s390x__)
242	return false;
243#else
244	return true;
245#endif
246}
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdlib.h>
  3#include <string.h>
  4#include <unistd.h>
  5#include <sys/ioctl.h>
  6#include <linux/hw_breakpoint.h>
  7#include <linux/kernel.h>
  8#include "tests.h"
  9#include "debug.h"
 10#include "event.h"
 11#include "cloexec.h"
 12#include "../perf-sys.h"
 13
 14#define WP_TEST_ASSERT_VAL(fd, text, val)       \
 15do {                                            \
 16	long long count;                        \
 17	wp_read(fd, &count, sizeof(long long)); \
 18	TEST_ASSERT_VAL(text, count == val);    \
 19} while (0)
 20
 21volatile u64 data1;
 22volatile u8 data2[3];
 23
 24static int wp_read(int fd, long long *count, int size)
 25{
 26	int ret = read(fd, count, size);
 27
 28	if (ret != size) {
 29		pr_debug("failed to read: %d\n", ret);
 30		return -1;
 31	}
 32	return 0;
 33}
 34
 35static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
 36				 void *wp_addr, unsigned long wp_len)
 37{
 38	memset(attr, 0, sizeof(struct perf_event_attr));
 39	attr->type           = PERF_TYPE_BREAKPOINT;
 40	attr->size           = sizeof(struct perf_event_attr);
 41	attr->config         = 0;
 42	attr->bp_type        = wp_type;
 43	attr->bp_addr        = (unsigned long)wp_addr;
 44	attr->bp_len         = wp_len;
 45	attr->sample_period  = 1;
 46	attr->sample_type    = PERF_SAMPLE_IP;
 47	attr->exclude_kernel = 1;
 48	attr->exclude_hv     = 1;
 49}
 50
 51static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
 52{
 53	int fd;
 54	struct perf_event_attr attr;
 55
 56	get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
 57	fd = sys_perf_event_open(&attr, 0, -1, -1,
 58				 perf_event_open_cloexec_flag());
 59	if (fd < 0)
 60		pr_debug("failed opening event %x\n", attr.bp_type);
 61
 62	return fd;
 63}
 64
 65static int wp_ro_test(void)
 66{
 67	int fd;
 68	unsigned long tmp, tmp1 = rand();
 69
 70	fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
 71	if (fd < 0)
 72		return -1;
 73
 74	tmp = data1;
 75	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
 76
 77	data1 = tmp1 + tmp;
 78	WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
 79
 80	close(fd);
 81	return 0;
 82}
 83
 84static int wp_wo_test(void)
 85{
 86	int fd;
 87	unsigned long tmp, tmp1 = rand();
 88
 89	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
 90	if (fd < 0)
 91		return -1;
 92
 93	tmp = data1;
 94	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
 95
 96	data1 = tmp1 + tmp;
 97	WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
 98
 99	close(fd);
100	return 0;
101}
102
103static int wp_rw_test(void)
104{
105	int fd;
106	unsigned long tmp, tmp1 = rand();
107
108	fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
109		     sizeof(data1));
110	if (fd < 0)
111		return -1;
112
113	tmp = data1;
114	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
115
116	data1 = tmp1 + tmp;
117	WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
118
119	close(fd);
120	return 0;
121}
122
123static int wp_modify_test(void)
124{
125	int fd, ret;
126	unsigned long tmp = rand();
127	struct perf_event_attr new_attr;
128
129	fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
130	if (fd < 0)
131		return -1;
132
133	data1 = tmp;
134	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
135
136	/* Modify watchpoint with disabled = 1 */
137	get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
138			     sizeof(u8) * 2);
139	new_attr.disabled = 1;
140	ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
141	if (ret < 0) {
142		pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
143		close(fd);
144		return ret;
145	}
146
147	data2[1] = tmp; /* Not Counted */
148	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
149
150	/* Enable the event */
151	ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
152	if (ret < 0) {
153		pr_debug("Failed to enable event\n");
154		close(fd);
155		return ret;
156	}
157
158	data2[1] = tmp; /* Counted */
159	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
160
161	data2[2] = tmp; /* Not Counted */
162	WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
163
164	close(fd);
165	return 0;
166}
167
168static bool wp_ro_supported(void)
169{
170#if defined (__x86_64__) || defined (__i386__)
171	return false;
172#else
173	return true;
174#endif
175}
176
177static const char *wp_ro_skip_msg(void)
178{
179#if defined (__x86_64__) || defined (__i386__)
180	return "missing hardware support";
181#else
182	return NULL;
183#endif
184}
185
186static struct {
187	const char *desc;
188	int (*target_func)(void);
189	bool (*is_supported)(void);
190	const char *(*skip_msg)(void);
191} wp_testcase_table[] = {
192	{
193		.desc = "Read Only Watchpoint",
194		.target_func = &wp_ro_test,
195		.is_supported = &wp_ro_supported,
196		.skip_msg = &wp_ro_skip_msg,
197	},
198	{
199		.desc = "Write Only Watchpoint",
200		.target_func = &wp_wo_test,
201	},
202	{
203		.desc = "Read / Write Watchpoint",
204		.target_func = &wp_rw_test,
205	},
206	{
207		.desc = "Modify Watchpoint",
208		.target_func = &wp_modify_test,
209	},
210};
211
212int test__wp_subtest_get_nr(void)
213{
214	return (int)ARRAY_SIZE(wp_testcase_table);
215}
216
217const char *test__wp_subtest_get_desc(int i)
218{
219	if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
220		return NULL;
221	return wp_testcase_table[i].desc;
222}
223
224const char *test__wp_subtest_skip_reason(int i)
225{
226	if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
227		return NULL;
228	if (!wp_testcase_table[i].skip_msg)
229		return NULL;
230	return wp_testcase_table[i].skip_msg();
231}
232
233int test__wp(struct test *test __maybe_unused, int i)
234{
235	if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
236		return TEST_FAIL;
237
238	if (wp_testcase_table[i].is_supported &&
239	    !wp_testcase_table[i].is_supported())
 
240		return TEST_SKIP;
 
241
242	return !wp_testcase_table[i].target_func() ? TEST_OK : TEST_FAIL;
243}
244
245/* The s390 so far does not have support for
246 * instruction breakpoint using the perf_event_open() system call.
247 */
248bool test__wp_is_supported(void)
249{
250#if defined(__s390x__)
251	return false;
252#else
253	return true;
254#endif
255}