Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2016 Google, Inc.
  4 *
 
 
 
 
 
 
 
 
 
  5 * Original Code by Pavel Labath <labath@google.com>
  6 *
  7 * Code modified by Pratyush Anand <panand@redhat.com>
  8 * for testing different byte select for each access size.
 
  9 */
 10
 11#define _GNU_SOURCE
 12
 13#include <asm/ptrace.h>
 14#include <sys/types.h>
 15#include <sys/wait.h>
 16#include <sys/ptrace.h>
 17#include <sys/param.h>
 18#include <sys/uio.h>
 19#include <stdint.h>
 20#include <stdbool.h>
 21#include <stddef.h>
 22#include <string.h>
 23#include <stdio.h>
 24#include <unistd.h>
 25#include <elf.h>
 26#include <errno.h>
 27#include <signal.h>
 28
 29#include "../kselftest.h"
 30
 31static volatile uint8_t var[96] __attribute__((__aligned__(32)));
 32
 33static void child(int size, int wr)
 34{
 35	volatile uint8_t *addr = &var[32 + wr];
 36
 37	if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
 38		ksft_print_msg(
 39			"ptrace(PTRACE_TRACEME) failed: %s\n",
 40			strerror(errno));
 41		_exit(1);
 42	}
 43
 44	if (raise(SIGSTOP) != 0) {
 45		ksft_print_msg(
 46			"raise(SIGSTOP) failed: %s\n", strerror(errno));
 47		_exit(1);
 48	}
 49
 50	if ((uintptr_t) addr % size) {
 51		ksft_print_msg(
 52			 "Wrong address write for the given size: %s\n",
 53			 strerror(errno));
 54		_exit(1);
 55	}
 56
 57	switch (size) {
 58	case 1:
 59		*addr = 47;
 60		break;
 61	case 2:
 62		*(uint16_t *)addr = 47;
 63		break;
 64	case 4:
 65		*(uint32_t *)addr = 47;
 66		break;
 67	case 8:
 68		*(uint64_t *)addr = 47;
 69		break;
 70	case 16:
 71		__asm__ volatile ("stp x29, x30, %0" : "=m" (addr[0]));
 72		break;
 73	case 32:
 74		__asm__ volatile ("stp q29, q30, %0" : "=m" (addr[0]));
 75		break;
 76	}
 77
 78	_exit(0);
 79}
 80
 81static bool set_watchpoint(pid_t pid, int size, int wp)
 82{
 83	const volatile uint8_t *addr = &var[32 + wp];
 84	const int offset = (uintptr_t)addr % 8;
 85	const unsigned int byte_mask = ((1 << size) - 1) << offset;
 86	const unsigned int type = 2; /* Write */
 87	const unsigned int enable = 1;
 88	const unsigned int control = byte_mask << 5 | type << 3 | enable;
 89	struct user_hwdebug_state dreg_state;
 90	struct iovec iov;
 91
 92	memset(&dreg_state, 0, sizeof(dreg_state));
 93	dreg_state.dbg_regs[0].addr = (uintptr_t)(addr - offset);
 94	dreg_state.dbg_regs[0].ctrl = control;
 95	iov.iov_base = &dreg_state;
 96	iov.iov_len = offsetof(struct user_hwdebug_state, dbg_regs) +
 97				sizeof(dreg_state.dbg_regs[0]);
 98	if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0)
 99		return true;
100
101	if (errno == EIO)
102		ksft_print_msg(
103			"ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) not supported on this hardware: %s\n",
104			strerror(errno));
105
106	ksft_print_msg(
107		"ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed: %s\n",
108		strerror(errno));
109	return false;
110}
111
112static bool run_test(int wr_size, int wp_size, int wr, int wp)
113{
114	int status;
115	siginfo_t siginfo;
116	pid_t pid = fork();
117	pid_t wpid;
118
119	if (pid < 0) {
120		ksft_test_result_fail(
121			"fork() failed: %s\n", strerror(errno));
122		return false;
123	}
124	if (pid == 0)
125		child(wr_size, wr);
126
127	wpid = waitpid(pid, &status, __WALL);
128	if (wpid != pid) {
129		ksft_print_msg(
130			"waitpid() failed: %s\n", strerror(errno));
131		return false;
132	}
133	if (!WIFSTOPPED(status)) {
134		ksft_print_msg(
135			"child did not stop: %s\n", strerror(errno));
136		return false;
137	}
138	if (WSTOPSIG(status) != SIGSTOP) {
139		ksft_print_msg("child did not stop with SIGSTOP\n");
140		return false;
141	}
142
143	if (!set_watchpoint(pid, wp_size, wp))
144		return false;
145
146	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
147		ksft_print_msg(
148			"ptrace(PTRACE_CONT) failed: %s\n",
149			strerror(errno));
150		return false;
151	}
152
153	alarm(3);
154	wpid = waitpid(pid, &status, __WALL);
155	if (wpid != pid) {
156		ksft_print_msg(
157			"waitpid() failed: %s\n", strerror(errno));
158		return false;
159	}
160	alarm(0);
161	if (WIFEXITED(status)) {
162		ksft_print_msg("child exited prematurely\n");
163		return false;
164	}
165	if (!WIFSTOPPED(status)) {
166		ksft_print_msg("child did not stop\n");
167		return false;
168	}
169	if (WSTOPSIG(status) != SIGTRAP) {
170		ksft_print_msg("child did not stop with SIGTRAP\n");
171		return false;
172	}
173	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) {
174		ksft_print_msg(
175			"ptrace(PTRACE_GETSIGINFO): %s\n",
176			strerror(errno));
177		return false;
178	}
179	if (siginfo.si_code != TRAP_HWBKPT) {
180		ksft_print_msg(
181			"Unexpected si_code %d\n", siginfo.si_code);
182		return false;
183	}
184
185	kill(pid, SIGKILL);
186	wpid = waitpid(pid, &status, 0);
187	if (wpid != pid) {
188		ksft_print_msg(
189			"waitpid() failed: %s\n", strerror(errno));
190		return false;
191	}
192	return true;
193}
194
195static void sigalrm(int sig)
196{
197}
198
199int main(int argc, char **argv)
200{
201	int opt;
202	bool succeeded = true;
203	struct sigaction act;
204	int wr, wp, size;
205	bool result;
206
207	ksft_print_header();
208	ksft_set_plan(213);
209
210	act.sa_handler = sigalrm;
211	sigemptyset(&act.sa_mask);
212	act.sa_flags = 0;
213	sigaction(SIGALRM, &act, NULL);
214	for (size = 1; size <= 32; size = size*2) {
215		for (wr = 0; wr <= 32; wr = wr + size) {
216			for (wp = wr - size; wp <= wr + size; wp = wp + size) {
 
217				result = run_test(size, MIN(size, 8), wr, wp);
218				if ((result && wr == wp) ||
219				    (!result && wr != wp))
220					ksft_test_result_pass(
221						"Test size = %d write offset = %d watchpoint offset = %d\n",
222						size, wr, wp);
223				else {
224					ksft_test_result_fail(
225						"Test size = %d write offset = %d watchpoint offset = %d\n",
226						size, wr, wp);
227					succeeded = false;
228				}
229			}
230		}
231	}
232
233	for (size = 1; size <= 32; size = size*2) {
234		if (run_test(size, 8, -size, -8))
235			ksft_test_result_pass(
236				"Test size = %d write offset = %d watchpoint offset = -8\n",
237				size, -size);
238		else {
239			ksft_test_result_fail(
240				"Test size = %d write offset = %d watchpoint offset = -8\n",
241				size, -size);
242			succeeded = false;
243		}
244	}
245
 
246	if (succeeded)
247		ksft_exit_pass();
248	else
249		ksft_exit_fail();
250}
v4.10.11
 
  1/*
  2 * Copyright (C) 2016 Google, Inc.
  3 *
  4 * This software is licensed under the terms of the GNU General Public
  5 * License version 2, as published by the Free Software Foundation, and
  6 * may be copied, distributed, and modified under those terms.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 * GNU General Public License for more details.
 12 *
 13 * Original Code by Pavel Labath <labath@google.com>
 14 *
 15 * Code modified by Pratyush Anand <panand@redhat.com>
 16 * for testing different byte select for each access size.
 17 *
 18 */
 19
 20#define _GNU_SOURCE
 21
 
 22#include <sys/types.h>
 23#include <sys/wait.h>
 24#include <sys/ptrace.h>
 25#include <sys/param.h>
 26#include <sys/uio.h>
 27#include <stdint.h>
 28#include <stdbool.h>
 29#include <stddef.h>
 30#include <string.h>
 31#include <stdio.h>
 32#include <unistd.h>
 33#include <elf.h>
 34#include <errno.h>
 35#include <signal.h>
 36
 37#include "../kselftest.h"
 38
 39static volatile uint8_t var[96] __attribute__((__aligned__(32)));
 40
 41static void child(int size, int wr)
 42{
 43	volatile uint8_t *addr = &var[32 + wr];
 44
 45	if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
 46		perror("ptrace(PTRACE_TRACEME) failed");
 
 
 47		_exit(1);
 48	}
 49
 50	if (raise(SIGSTOP) != 0) {
 51		perror("raise(SIGSTOP) failed");
 
 52		_exit(1);
 53	}
 54
 55	if ((uintptr_t) addr % size) {
 56		perror("Wrong address write for the given size\n");
 
 
 57		_exit(1);
 58	}
 
 59	switch (size) {
 60	case 1:
 61		*addr = 47;
 62		break;
 63	case 2:
 64		*(uint16_t *)addr = 47;
 65		break;
 66	case 4:
 67		*(uint32_t *)addr = 47;
 68		break;
 69	case 8:
 70		*(uint64_t *)addr = 47;
 71		break;
 72	case 16:
 73		__asm__ volatile ("stp x29, x30, %0" : "=m" (addr[0]));
 74		break;
 75	case 32:
 76		__asm__ volatile ("stp q29, q30, %0" : "=m" (addr[0]));
 77		break;
 78	}
 79
 80	_exit(0);
 81}
 82
 83static bool set_watchpoint(pid_t pid, int size, int wp)
 84{
 85	const volatile uint8_t *addr = &var[32 + wp];
 86	const int offset = (uintptr_t)addr % 8;
 87	const unsigned int byte_mask = ((1 << size) - 1) << offset;
 88	const unsigned int type = 2; /* Write */
 89	const unsigned int enable = 1;
 90	const unsigned int control = byte_mask << 5 | type << 3 | enable;
 91	struct user_hwdebug_state dreg_state;
 92	struct iovec iov;
 93
 94	memset(&dreg_state, 0, sizeof(dreg_state));
 95	dreg_state.dbg_regs[0].addr = (uintptr_t)(addr - offset);
 96	dreg_state.dbg_regs[0].ctrl = control;
 97	iov.iov_base = &dreg_state;
 98	iov.iov_len = offsetof(struct user_hwdebug_state, dbg_regs) +
 99				sizeof(dreg_state.dbg_regs[0]);
100	if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0)
101		return true;
102
103	if (errno == EIO) {
104		printf("ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) "
105			"not supported on this hardware\n");
106		ksft_exit_skip();
107	}
108	perror("ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed");
 
 
109	return false;
110}
111
112static bool run_test(int wr_size, int wp_size, int wr, int wp)
113{
114	int status;
115	siginfo_t siginfo;
116	pid_t pid = fork();
117	pid_t wpid;
118
119	if (pid < 0) {
120		perror("fork() failed");
 
121		return false;
122	}
123	if (pid == 0)
124		child(wr_size, wr);
125
126	wpid = waitpid(pid, &status, __WALL);
127	if (wpid != pid) {
128		perror("waitpid() failed");
 
129		return false;
130	}
131	if (!WIFSTOPPED(status)) {
132		printf("child did not stop\n");
 
133		return false;
134	}
135	if (WSTOPSIG(status) != SIGSTOP) {
136		printf("child did not stop with SIGSTOP\n");
137		return false;
138	}
139
140	if (!set_watchpoint(pid, wp_size, wp))
141		return false;
142
143	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
144		perror("ptrace(PTRACE_SINGLESTEP) failed");
 
 
145		return false;
146	}
147
148	alarm(3);
149	wpid = waitpid(pid, &status, __WALL);
150	if (wpid != pid) {
151		perror("waitpid() failed");
 
152		return false;
153	}
154	alarm(0);
155	if (WIFEXITED(status)) {
156		printf("child did not single-step\t");
157		return false;
158	}
159	if (!WIFSTOPPED(status)) {
160		printf("child did not stop\n");
161		return false;
162	}
163	if (WSTOPSIG(status) != SIGTRAP) {
164		printf("child did not stop with SIGTRAP\n");
165		return false;
166	}
167	if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) {
168		perror("ptrace(PTRACE_GETSIGINFO)");
 
 
169		return false;
170	}
171	if (siginfo.si_code != TRAP_HWBKPT) {
172		printf("Unexpected si_code %d\n", siginfo.si_code);
 
173		return false;
174	}
175
176	kill(pid, SIGKILL);
177	wpid = waitpid(pid, &status, 0);
178	if (wpid != pid) {
179		perror("waitpid() failed");
 
180		return false;
181	}
182	return true;
183}
184
185static void sigalrm(int sig)
186{
187}
188
189int main(int argc, char **argv)
190{
191	int opt;
192	bool succeeded = true;
193	struct sigaction act;
194	int wr, wp, size;
195	bool result;
196
 
 
 
197	act.sa_handler = sigalrm;
198	sigemptyset(&act.sa_mask);
199	act.sa_flags = 0;
200	sigaction(SIGALRM, &act, NULL);
201	for (size = 1; size <= 32; size = size*2) {
202		for (wr = 0; wr <= 32; wr = wr + size) {
203			for (wp = wr - size; wp <= wr + size; wp = wp + size) {
204				printf("Test size = %d write offset = %d watchpoint offset = %d\t", size, wr, wp);
205				result = run_test(size, MIN(size, 8), wr, wp);
206				if ((result && wr == wp) || (!result && wr != wp)) {
207					printf("[OK]\n");
208					ksft_inc_pass_cnt();
209				} else {
210					printf("[FAILED]\n");
211					ksft_inc_fail_cnt();
 
 
 
212					succeeded = false;
213				}
214			}
215		}
216	}
217
218	for (size = 1; size <= 32; size = size*2) {
219		printf("Test size = %d write offset = %d watchpoint offset = -8\t", size, -size);
220
221		if (run_test(size, 8, -size, -8)) {
222			printf("[OK]\n");
223			ksft_inc_pass_cnt();
224		} else {
225			printf("[FAILED]\n");
226			ksft_inc_fail_cnt();
227			succeeded = false;
228		}
229	}
230
231	ksft_print_cnts();
232	if (succeeded)
233		ksft_exit_pass();
234	else
235		ksft_exit_fail();
236}