xref: /openbmc/linux/tools/testing/selftests/powerpc/utils.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fcb45ec0SMichael Ellerman /*
3fcb45ec0SMichael Ellerman  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
4fcb45ec0SMichael Ellerman  */
5fcb45ec0SMichael Ellerman 
6d1301afdSMichael Ellerman #define _GNU_SOURCE	/* For CPU_ZERO etc. */
7d1301afdSMichael Ellerman 
8fcb45ec0SMichael Ellerman #include <elf.h>
9fcb45ec0SMichael Ellerman #include <errno.h>
10fcb45ec0SMichael Ellerman #include <fcntl.h>
11d1bc05b7SBenjamin Gray #include <inttypes.h>
12d1bc05b7SBenjamin Gray #include <limits.h>
13fcb45ec0SMichael Ellerman #include <link.h>
14d1301afdSMichael Ellerman #include <sched.h>
15fcb45ec0SMichael Ellerman #include <stdio.h>
16d2bf7932SNaveen N. Rao #include <stdlib.h>
1795f9b3afSMichael Ellerman #include <string.h>
18d2bf7932SNaveen N. Rao #include <sys/ioctl.h>
19fcb45ec0SMichael Ellerman #include <sys/stat.h>
20dfa03fffSSandipan Das #include <sys/sysinfo.h>
21fcb45ec0SMichael Ellerman #include <sys/types.h>
2295f9b3afSMichael Ellerman #include <sys/utsname.h>
23fcb45ec0SMichael Ellerman #include <unistd.h>
24d2bf7932SNaveen N. Rao #include <asm/unistd.h>
25d2bf7932SNaveen N. Rao #include <linux/limits.h>
26fcb45ec0SMichael Ellerman 
27fcb45ec0SMichael Ellerman #include "utils.h"
28fcb45ec0SMichael Ellerman 
29fcb45ec0SMichael Ellerman static char auxv[4096];
30fcb45ec0SMichael Ellerman 
read_file(const char * path,char * buf,size_t count,size_t * len)31a974f0c1SBenjamin Gray int read_file(const char *path, char *buf, size_t count, size_t *len)
32fcb45ec0SMichael Ellerman {
33a974f0c1SBenjamin Gray 	ssize_t rc;
34a974f0c1SBenjamin Gray 	int fd;
35a974f0c1SBenjamin Gray 	int err;
36a974f0c1SBenjamin Gray 	char eof;
37fcb45ec0SMichael Ellerman 
38a974f0c1SBenjamin Gray 	fd = open(path, O_RDONLY);
39a974f0c1SBenjamin Gray 	if (fd < 0)
40e3028437SMichael Ellerman 		return -errno;
41fcb45ec0SMichael Ellerman 
42a974f0c1SBenjamin Gray 	rc = read(fd, buf, count);
43a974f0c1SBenjamin Gray 	if (rc < 0) {
44a974f0c1SBenjamin Gray 		err = -errno;
45fcb45ec0SMichael Ellerman 		goto out;
46fcb45ec0SMichael Ellerman 	}
47fcb45ec0SMichael Ellerman 
48a974f0c1SBenjamin Gray 	if (len)
49a974f0c1SBenjamin Gray 		*len = rc;
50a974f0c1SBenjamin Gray 
51a974f0c1SBenjamin Gray 	/* Overflow if there are still more bytes after filling the buffer */
52a974f0c1SBenjamin Gray 	if (rc == count) {
53a974f0c1SBenjamin Gray 		rc = read(fd, &eof, 1);
54a974f0c1SBenjamin Gray 		if (rc != 0) {
55a974f0c1SBenjamin Gray 			err = -EOVERFLOW;
56fcb45ec0SMichael Ellerman 			goto out;
57fcb45ec0SMichael Ellerman 		}
58a974f0c1SBenjamin Gray 	}
59fcb45ec0SMichael Ellerman 
60a974f0c1SBenjamin Gray 	err = 0;
61a974f0c1SBenjamin Gray 
62e3028437SMichael Ellerman out:
63e3028437SMichael Ellerman 	close(fd);
64a974f0c1SBenjamin Gray 	errno = -err;
65a974f0c1SBenjamin Gray 	return err;
66a974f0c1SBenjamin Gray }
67a974f0c1SBenjamin Gray 
read_file_alloc(const char * path,char ** buf,size_t * len)688d7253dcSBenjamin Gray int read_file_alloc(const char *path, char **buf, size_t *len)
698d7253dcSBenjamin Gray {
708d7253dcSBenjamin Gray 	size_t read_offset = 0;
718d7253dcSBenjamin Gray 	size_t buffer_len = 0;
728d7253dcSBenjamin Gray 	char *buffer = NULL;
738d7253dcSBenjamin Gray 	int err;
748d7253dcSBenjamin Gray 	int fd;
758d7253dcSBenjamin Gray 
768d7253dcSBenjamin Gray 	fd = open(path, O_RDONLY);
778d7253dcSBenjamin Gray 	if (fd < 0)
788d7253dcSBenjamin Gray 		return -errno;
798d7253dcSBenjamin Gray 
808d7253dcSBenjamin Gray 	/*
818d7253dcSBenjamin Gray 	 * We don't use stat & preallocate st_size because some non-files
828d7253dcSBenjamin Gray 	 * report 0 file size. Instead just dynamically grow the buffer
838d7253dcSBenjamin Gray 	 * as needed.
848d7253dcSBenjamin Gray 	 */
858d7253dcSBenjamin Gray 	while (1) {
868d7253dcSBenjamin Gray 		ssize_t rc;
878d7253dcSBenjamin Gray 
888d7253dcSBenjamin Gray 		if (read_offset >= buffer_len / 2) {
898d7253dcSBenjamin Gray 			char *next_buffer;
908d7253dcSBenjamin Gray 
918d7253dcSBenjamin Gray 			buffer_len = buffer_len ? buffer_len * 2 : 4096;
928d7253dcSBenjamin Gray 			next_buffer = realloc(buffer, buffer_len);
938d7253dcSBenjamin Gray 			if (!next_buffer) {
948d7253dcSBenjamin Gray 				err = -errno;
958d7253dcSBenjamin Gray 				goto out;
968d7253dcSBenjamin Gray 			}
978d7253dcSBenjamin Gray 			buffer = next_buffer;
988d7253dcSBenjamin Gray 		}
998d7253dcSBenjamin Gray 
1008d7253dcSBenjamin Gray 		rc = read(fd, buffer + read_offset, buffer_len - read_offset);
1018d7253dcSBenjamin Gray 		if (rc < 0) {
1028d7253dcSBenjamin Gray 			err = -errno;
1038d7253dcSBenjamin Gray 			goto out;
1048d7253dcSBenjamin Gray 		}
1058d7253dcSBenjamin Gray 
1068d7253dcSBenjamin Gray 		if (rc == 0)
1078d7253dcSBenjamin Gray 			break;
1088d7253dcSBenjamin Gray 
1098d7253dcSBenjamin Gray 		read_offset += rc;
1108d7253dcSBenjamin Gray 	}
1118d7253dcSBenjamin Gray 
1128d7253dcSBenjamin Gray 	*buf = buffer;
1138d7253dcSBenjamin Gray 	if (len)
1148d7253dcSBenjamin Gray 		*len = read_offset;
1158d7253dcSBenjamin Gray 
1168d7253dcSBenjamin Gray 	err = 0;
1178d7253dcSBenjamin Gray 
1188d7253dcSBenjamin Gray out:
1198d7253dcSBenjamin Gray 	close(fd);
1208d7253dcSBenjamin Gray 	if (err)
1218d7253dcSBenjamin Gray 		free(buffer);
1228d7253dcSBenjamin Gray 	errno = -err;
1238d7253dcSBenjamin Gray 	return err;
1248d7253dcSBenjamin Gray }
1258d7253dcSBenjamin Gray 
write_file(const char * path,const char * buf,size_t count)126a974f0c1SBenjamin Gray int write_file(const char *path, const char *buf, size_t count)
127a974f0c1SBenjamin Gray {
128a974f0c1SBenjamin Gray 	int fd;
129a974f0c1SBenjamin Gray 	int err;
130a974f0c1SBenjamin Gray 	ssize_t rc;
131a974f0c1SBenjamin Gray 
132a974f0c1SBenjamin Gray 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
133a974f0c1SBenjamin Gray 	if (fd < 0)
134a974f0c1SBenjamin Gray 		return -errno;
135a974f0c1SBenjamin Gray 
136a974f0c1SBenjamin Gray 	rc = write(fd, buf, count);
137a974f0c1SBenjamin Gray 	if (rc < 0) {
138a974f0c1SBenjamin Gray 		err = -errno;
139a974f0c1SBenjamin Gray 		goto out;
140a974f0c1SBenjamin Gray 	}
141a974f0c1SBenjamin Gray 
142a974f0c1SBenjamin Gray 	if (rc != count) {
143a974f0c1SBenjamin Gray 		err = -EOVERFLOW;
144a974f0c1SBenjamin Gray 		goto out;
145a974f0c1SBenjamin Gray 	}
146a974f0c1SBenjamin Gray 
147a974f0c1SBenjamin Gray 	err = 0;
148a974f0c1SBenjamin Gray 
149a974f0c1SBenjamin Gray out:
150a974f0c1SBenjamin Gray 	close(fd);
151a974f0c1SBenjamin Gray 	errno = -err;
152a974f0c1SBenjamin Gray 	return err;
153a974f0c1SBenjamin Gray }
154a974f0c1SBenjamin Gray 
read_auxv(char * buf,ssize_t buf_size)155a974f0c1SBenjamin Gray int read_auxv(char *buf, ssize_t buf_size)
156a974f0c1SBenjamin Gray {
157a974f0c1SBenjamin Gray 	int err;
158a974f0c1SBenjamin Gray 
159a974f0c1SBenjamin Gray 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);
160a974f0c1SBenjamin Gray 	if (err) {
161a974f0c1SBenjamin Gray 		perror("Error reading /proc/self/auxv");
162a974f0c1SBenjamin Gray 		return err;
163a974f0c1SBenjamin Gray 	}
164a974f0c1SBenjamin Gray 
165a974f0c1SBenjamin Gray 	return 0;
166e3028437SMichael Ellerman }
167e3028437SMichael Ellerman 
read_debugfs_file(const char * subpath,char * buf,size_t count)168121d340bSBenjamin Gray int read_debugfs_file(const char *subpath, char *buf, size_t count)
169121d340bSBenjamin Gray {
170121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
171121d340bSBenjamin Gray 
172121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
173121d340bSBenjamin Gray 
174121d340bSBenjamin Gray 	return read_file(path, buf, count, NULL);
175121d340bSBenjamin Gray }
176121d340bSBenjamin Gray 
write_debugfs_file(const char * subpath,const char * buf,size_t count)177121d340bSBenjamin Gray int write_debugfs_file(const char *subpath, const char *buf, size_t count)
178121d340bSBenjamin Gray {
179121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
180121d340bSBenjamin Gray 
181121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
182121d340bSBenjamin Gray 
183121d340bSBenjamin Gray 	return write_file(path, buf, count);
184121d340bSBenjamin Gray }
185121d340bSBenjamin Gray 
validate_int_parse(const char * buffer,size_t count,char * end)186d1bc05b7SBenjamin Gray static int validate_int_parse(const char *buffer, size_t count, char *end)
187d1bc05b7SBenjamin Gray {
188d1bc05b7SBenjamin Gray 	int err = 0;
189d1bc05b7SBenjamin Gray 
190d1bc05b7SBenjamin Gray 	/* Require at least one digit */
191d1bc05b7SBenjamin Gray 	if (end == buffer) {
192d1bc05b7SBenjamin Gray 		err = -EINVAL;
193d1bc05b7SBenjamin Gray 		goto out;
194d1bc05b7SBenjamin Gray 	}
195d1bc05b7SBenjamin Gray 
196d1bc05b7SBenjamin Gray 	/* Require all remaining characters be whitespace-ish */
197d1bc05b7SBenjamin Gray 	for (; end < buffer + count; end++) {
198d1bc05b7SBenjamin Gray 		if (*end == '\0')
199d1bc05b7SBenjamin Gray 			break;
200d1bc05b7SBenjamin Gray 
201d1bc05b7SBenjamin Gray 		if (*end != ' ' && *end != '\n') {
202d1bc05b7SBenjamin Gray 			err = -EINVAL;
203d1bc05b7SBenjamin Gray 			goto out;
204d1bc05b7SBenjamin Gray 		}
205d1bc05b7SBenjamin Gray 	}
206d1bc05b7SBenjamin Gray 
207d1bc05b7SBenjamin Gray out:
208d1bc05b7SBenjamin Gray 	errno = -err;
209d1bc05b7SBenjamin Gray 	return err;
210d1bc05b7SBenjamin Gray }
211d1bc05b7SBenjamin Gray 
parse_bounded_int(const char * buffer,size_t count,intmax_t * result,int base,intmax_t min,intmax_t max)212d1bc05b7SBenjamin Gray static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
213d1bc05b7SBenjamin Gray 			     int base, intmax_t min, intmax_t max)
214d1bc05b7SBenjamin Gray {
215d1bc05b7SBenjamin Gray 	int err;
216d1bc05b7SBenjamin Gray 	char *end;
217d1bc05b7SBenjamin Gray 
218d1bc05b7SBenjamin Gray 	errno = 0;
219d1bc05b7SBenjamin Gray 	*result = strtoimax(buffer, &end, base);
220d1bc05b7SBenjamin Gray 
221d1bc05b7SBenjamin Gray 	if (errno)
222d1bc05b7SBenjamin Gray 		return -errno;
223d1bc05b7SBenjamin Gray 
224d1bc05b7SBenjamin Gray 	err = validate_int_parse(buffer, count, end);
225d1bc05b7SBenjamin Gray 	if (err)
226d1bc05b7SBenjamin Gray 		goto out;
227d1bc05b7SBenjamin Gray 
228d1bc05b7SBenjamin Gray 	if (*result < min || *result > max)
229d1bc05b7SBenjamin Gray 		err = -EOVERFLOW;
230d1bc05b7SBenjamin Gray 
231d1bc05b7SBenjamin Gray out:
232d1bc05b7SBenjamin Gray 	errno = -err;
233d1bc05b7SBenjamin Gray 	return err;
234d1bc05b7SBenjamin Gray }
235d1bc05b7SBenjamin Gray 
parse_bounded_uint(const char * buffer,size_t count,uintmax_t * result,int base,uintmax_t max)236d1bc05b7SBenjamin Gray static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
237d1bc05b7SBenjamin Gray 			      int base, uintmax_t max)
238d1bc05b7SBenjamin Gray {
239d1bc05b7SBenjamin Gray 	int err = 0;
240d1bc05b7SBenjamin Gray 	char *end;
241d1bc05b7SBenjamin Gray 
242d1bc05b7SBenjamin Gray 	errno = 0;
243d1bc05b7SBenjamin Gray 	*result = strtoumax(buffer, &end, base);
244d1bc05b7SBenjamin Gray 
245d1bc05b7SBenjamin Gray 	if (errno)
246d1bc05b7SBenjamin Gray 		return -errno;
247d1bc05b7SBenjamin Gray 
248d1bc05b7SBenjamin Gray 	err = validate_int_parse(buffer, count, end);
249d1bc05b7SBenjamin Gray 	if (err)
250d1bc05b7SBenjamin Gray 		goto out;
251d1bc05b7SBenjamin Gray 
252d1bc05b7SBenjamin Gray 	if (*result > max)
253d1bc05b7SBenjamin Gray 		err = -EOVERFLOW;
254d1bc05b7SBenjamin Gray 
255d1bc05b7SBenjamin Gray out:
256d1bc05b7SBenjamin Gray 	errno = -err;
257d1bc05b7SBenjamin Gray 	return err;
258d1bc05b7SBenjamin Gray }
259d1bc05b7SBenjamin Gray 
parse_intmax(const char * buffer,size_t count,intmax_t * result,int base)260d1bc05b7SBenjamin Gray int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
261d1bc05b7SBenjamin Gray {
262d1bc05b7SBenjamin Gray 	return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
263d1bc05b7SBenjamin Gray }
264d1bc05b7SBenjamin Gray 
parse_uintmax(const char * buffer,size_t count,uintmax_t * result,int base)265d1bc05b7SBenjamin Gray int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
266d1bc05b7SBenjamin Gray {
267d1bc05b7SBenjamin Gray 	return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
268d1bc05b7SBenjamin Gray }
269d1bc05b7SBenjamin Gray 
parse_int(const char * buffer,size_t count,int * result,int base)270d1bc05b7SBenjamin Gray int parse_int(const char *buffer, size_t count, int *result, int base)
271d1bc05b7SBenjamin Gray {
272d1bc05b7SBenjamin Gray 	intmax_t parsed;
273d1bc05b7SBenjamin Gray 	int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
274d1bc05b7SBenjamin Gray 
275d1bc05b7SBenjamin Gray 	*result = parsed;
276d1bc05b7SBenjamin Gray 	return err;
277d1bc05b7SBenjamin Gray }
278d1bc05b7SBenjamin Gray 
parse_uint(const char * buffer,size_t count,unsigned int * result,int base)279d1bc05b7SBenjamin Gray int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
280d1bc05b7SBenjamin Gray {
281d1bc05b7SBenjamin Gray 	uintmax_t parsed;
282d1bc05b7SBenjamin Gray 	int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
283d1bc05b7SBenjamin Gray 
284d1bc05b7SBenjamin Gray 	*result = parsed;
285d1bc05b7SBenjamin Gray 	return err;
286d1bc05b7SBenjamin Gray }
287d1bc05b7SBenjamin Gray 
parse_long(const char * buffer,size_t count,long * result,int base)288d1bc05b7SBenjamin Gray int parse_long(const char *buffer, size_t count, long *result, int base)
289d1bc05b7SBenjamin Gray {
290d1bc05b7SBenjamin Gray 	intmax_t parsed;
291d1bc05b7SBenjamin Gray 	int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
292d1bc05b7SBenjamin Gray 
293d1bc05b7SBenjamin Gray 	*result = parsed;
294d1bc05b7SBenjamin Gray 	return err;
295d1bc05b7SBenjamin Gray }
296d1bc05b7SBenjamin Gray 
parse_ulong(const char * buffer,size_t count,unsigned long * result,int base)297d1bc05b7SBenjamin Gray int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
298d1bc05b7SBenjamin Gray {
299d1bc05b7SBenjamin Gray 	uintmax_t parsed;
300d1bc05b7SBenjamin Gray 	int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
301d1bc05b7SBenjamin Gray 
302d1bc05b7SBenjamin Gray 	*result = parsed;
303d1bc05b7SBenjamin Gray 	return err;
304d1bc05b7SBenjamin Gray }
305d1bc05b7SBenjamin Gray 
read_long(const char * path,long * result,int base)3065c20de57SBenjamin Gray int read_long(const char *path, long *result, int base)
3075c20de57SBenjamin Gray {
3085c20de57SBenjamin Gray 	int err;
3095c20de57SBenjamin Gray 	char buffer[32] = {0};
3105c20de57SBenjamin Gray 
3115c20de57SBenjamin Gray 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
3125c20de57SBenjamin Gray 	if (err)
3135c20de57SBenjamin Gray 		return err;
3145c20de57SBenjamin Gray 
3155c20de57SBenjamin Gray 	return parse_long(buffer, sizeof(buffer), result, base);
3165c20de57SBenjamin Gray }
3175c20de57SBenjamin Gray 
read_ulong(const char * path,unsigned long * result,int base)3185c20de57SBenjamin Gray int read_ulong(const char *path, unsigned long *result, int base)
3195c20de57SBenjamin Gray {
3205c20de57SBenjamin Gray 	int err;
3215c20de57SBenjamin Gray 	char buffer[32] = {0};
3225c20de57SBenjamin Gray 
3235c20de57SBenjamin Gray 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
3245c20de57SBenjamin Gray 	if (err)
3255c20de57SBenjamin Gray 		return err;
3265c20de57SBenjamin Gray 
3275c20de57SBenjamin Gray 	return parse_ulong(buffer, sizeof(buffer), result, base);
3285c20de57SBenjamin Gray }
3295c20de57SBenjamin Gray 
write_long(const char * path,long result,int base)3305c20de57SBenjamin Gray int write_long(const char *path, long result, int base)
3315c20de57SBenjamin Gray {
3325c20de57SBenjamin Gray 	int err;
3335c20de57SBenjamin Gray 	int len;
3345c20de57SBenjamin Gray 	char buffer[32];
3355c20de57SBenjamin Gray 
3365c20de57SBenjamin Gray 	/* Decimal only for now: no format specifier for signed hex values */
3375c20de57SBenjamin Gray 	if (base != 10) {
3385c20de57SBenjamin Gray 		err = -EINVAL;
3395c20de57SBenjamin Gray 		goto out;
3405c20de57SBenjamin Gray 	}
3415c20de57SBenjamin Gray 
3425c20de57SBenjamin Gray 	len = snprintf(buffer, sizeof(buffer), "%ld", result);
3435c20de57SBenjamin Gray 	if (len < 0 || len >= sizeof(buffer)) {
3445c20de57SBenjamin Gray 		err = -EOVERFLOW;
3455c20de57SBenjamin Gray 		goto out;
3465c20de57SBenjamin Gray 	}
3475c20de57SBenjamin Gray 
3485c20de57SBenjamin Gray 	err = write_file(path, buffer, len);
3495c20de57SBenjamin Gray 
3505c20de57SBenjamin Gray out:
3515c20de57SBenjamin Gray 	errno = -err;
3525c20de57SBenjamin Gray 	return err;
3535c20de57SBenjamin Gray }
3545c20de57SBenjamin Gray 
write_ulong(const char * path,unsigned long result,int base)3555c20de57SBenjamin Gray int write_ulong(const char *path, unsigned long result, int base)
3565c20de57SBenjamin Gray {
3575c20de57SBenjamin Gray 	int err;
3585c20de57SBenjamin Gray 	int len;
3595c20de57SBenjamin Gray 	char buffer[32];
3605c20de57SBenjamin Gray 	char *fmt;
3615c20de57SBenjamin Gray 
3625c20de57SBenjamin Gray 	switch (base) {
3635c20de57SBenjamin Gray 	case 10:
3645c20de57SBenjamin Gray 		fmt = "%lu";
3655c20de57SBenjamin Gray 		break;
3665c20de57SBenjamin Gray 	case 16:
3675c20de57SBenjamin Gray 		fmt = "%lx";
3685c20de57SBenjamin Gray 		break;
3695c20de57SBenjamin Gray 	default:
3705c20de57SBenjamin Gray 		err = -EINVAL;
3715c20de57SBenjamin Gray 		goto out;
3725c20de57SBenjamin Gray 	}
3735c20de57SBenjamin Gray 
3745c20de57SBenjamin Gray 	len = snprintf(buffer, sizeof(buffer), fmt, result);
3755c20de57SBenjamin Gray 	if (len < 0 || len >= sizeof(buffer)) {
3765c20de57SBenjamin Gray 		err = -errno;
3775c20de57SBenjamin Gray 		goto out;
3785c20de57SBenjamin Gray 	}
3795c20de57SBenjamin Gray 
3805c20de57SBenjamin Gray 	err = write_file(path, buffer, len);
3815c20de57SBenjamin Gray 
3825c20de57SBenjamin Gray out:
3835c20de57SBenjamin Gray 	errno = -err;
3845c20de57SBenjamin Gray 	return err;
3855c20de57SBenjamin Gray }
3865c20de57SBenjamin Gray 
find_auxv_entry(int type,char * auxv)387e3028437SMichael Ellerman void *find_auxv_entry(int type, char *auxv)
388e3028437SMichael Ellerman {
389e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
390e3028437SMichael Ellerman 
391fcb45ec0SMichael Ellerman 	p = (ElfW(auxv_t) *)auxv;
392fcb45ec0SMichael Ellerman 
393fcb45ec0SMichael Ellerman 	while (p->a_type != AT_NULL) {
394e3028437SMichael Ellerman 		if (p->a_type == type)
395e3028437SMichael Ellerman 			return p;
396fcb45ec0SMichael Ellerman 
397fcb45ec0SMichael Ellerman 		p++;
398fcb45ec0SMichael Ellerman 	}
399e3028437SMichael Ellerman 
400e3028437SMichael Ellerman 	return NULL;
401e3028437SMichael Ellerman }
402e3028437SMichael Ellerman 
get_auxv_entry(int type)403e3028437SMichael Ellerman void *get_auxv_entry(int type)
404e3028437SMichael Ellerman {
405e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
406e3028437SMichael Ellerman 
407e3028437SMichael Ellerman 	if (read_auxv(auxv, sizeof(auxv)))
408e3028437SMichael Ellerman 		return NULL;
409e3028437SMichael Ellerman 
410e3028437SMichael Ellerman 	p = find_auxv_entry(type, auxv);
411e3028437SMichael Ellerman 	if (p)
412e3028437SMichael Ellerman 		return (void *)p->a_un.a_val;
413e3028437SMichael Ellerman 
414e3028437SMichael Ellerman 	return NULL;
415fcb45ec0SMichael Ellerman }
416d1301afdSMichael Ellerman 
pick_online_cpu(void)417d1301afdSMichael Ellerman int pick_online_cpu(void)
418d1301afdSMichael Ellerman {
419dfa03fffSSandipan Das 	int ncpus, cpu = -1;
420dfa03fffSSandipan Das 	cpu_set_t *mask;
421dfa03fffSSandipan Das 	size_t size;
422d1301afdSMichael Ellerman 
423dfa03fffSSandipan Das 	ncpus = get_nprocs_conf();
424dfa03fffSSandipan Das 	size = CPU_ALLOC_SIZE(ncpus);
425dfa03fffSSandipan Das 	mask = CPU_ALLOC(ncpus);
426dfa03fffSSandipan Das 	if (!mask) {
427dfa03fffSSandipan Das 		perror("malloc");
428d1301afdSMichael Ellerman 		return -1;
429d1301afdSMichael Ellerman 	}
430d1301afdSMichael Ellerman 
431dfa03fffSSandipan Das 	CPU_ZERO_S(size, mask);
432dfa03fffSSandipan Das 
433dfa03fffSSandipan Das 	if (sched_getaffinity(0, size, mask)) {
434dfa03fffSSandipan Das 		perror("sched_getaffinity");
435dfa03fffSSandipan Das 		goto done;
436dfa03fffSSandipan Das 	}
437dfa03fffSSandipan Das 
438d1301afdSMichael Ellerman 	/* We prefer a primary thread, but skip 0 */
439dfa03fffSSandipan Das 	for (cpu = 8; cpu < ncpus; cpu += 8)
440dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
441dfa03fffSSandipan Das 			goto done;
442d1301afdSMichael Ellerman 
443d1301afdSMichael Ellerman 	/* Search for anything, but in reverse */
444dfa03fffSSandipan Das 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
445dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
446dfa03fffSSandipan Das 			goto done;
447d1301afdSMichael Ellerman 
448d1301afdSMichael Ellerman 	printf("No cpus in affinity mask?!\n");
449dfa03fffSSandipan Das 
450dfa03fffSSandipan Das done:
451dfa03fffSSandipan Das 	CPU_FREE(mask);
452dfa03fffSSandipan Das 	return cpu;
453d1301afdSMichael Ellerman }
45495f9b3afSMichael Ellerman 
bind_to_cpu(int cpu)455c97b2fc6SBenjamin Gray int bind_to_cpu(int cpu)
456c97b2fc6SBenjamin Gray {
457c97b2fc6SBenjamin Gray 	cpu_set_t mask;
458*6ff4dc25SBenjamin Gray 	int err;
459*6ff4dc25SBenjamin Gray 
460*6ff4dc25SBenjamin Gray 	if (cpu == BIND_CPU_ANY) {
461*6ff4dc25SBenjamin Gray 		cpu = pick_online_cpu();
462*6ff4dc25SBenjamin Gray 		if (cpu < 0)
463*6ff4dc25SBenjamin Gray 			return cpu;
464*6ff4dc25SBenjamin Gray 	}
465c97b2fc6SBenjamin Gray 
466c97b2fc6SBenjamin Gray 	printf("Binding to cpu %d\n", cpu);
467c97b2fc6SBenjamin Gray 
468c97b2fc6SBenjamin Gray 	CPU_ZERO(&mask);
469c97b2fc6SBenjamin Gray 	CPU_SET(cpu, &mask);
470c97b2fc6SBenjamin Gray 
471*6ff4dc25SBenjamin Gray 	err = sched_setaffinity(0, sizeof(mask), &mask);
472*6ff4dc25SBenjamin Gray 	if (err)
473*6ff4dc25SBenjamin Gray 		return err;
474*6ff4dc25SBenjamin Gray 
475*6ff4dc25SBenjamin Gray 	return cpu;
476c97b2fc6SBenjamin Gray }
477c97b2fc6SBenjamin Gray 
is_ppc64le(void)47895f9b3afSMichael Ellerman bool is_ppc64le(void)
47995f9b3afSMichael Ellerman {
48095f9b3afSMichael Ellerman 	struct utsname uts;
48195f9b3afSMichael Ellerman 	int rc;
48295f9b3afSMichael Ellerman 
48395f9b3afSMichael Ellerman 	errno = 0;
48495f9b3afSMichael Ellerman 	rc = uname(&uts);
48595f9b3afSMichael Ellerman 	if (rc) {
48695f9b3afSMichael Ellerman 		perror("uname");
48795f9b3afSMichael Ellerman 		return false;
48895f9b3afSMichael Ellerman 	}
48995f9b3afSMichael Ellerman 
49095f9b3afSMichael Ellerman 	return strcmp(uts.machine, "ppc64le") == 0;
49195f9b3afSMichael Ellerman }
492d2bf7932SNaveen N. Rao 
read_sysfs_file(char * fpath,char * result,size_t result_size)493c790c3d2SMichael Ellerman int read_sysfs_file(char *fpath, char *result, size_t result_size)
494c790c3d2SMichael Ellerman {
495c790c3d2SMichael Ellerman 	char path[PATH_MAX] = "/sys/";
496c790c3d2SMichael Ellerman 
497c790c3d2SMichael Ellerman 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
498c790c3d2SMichael Ellerman 
499a974f0c1SBenjamin Gray 	return read_file(path, result, result_size, NULL);
500c790c3d2SMichael Ellerman }
501c790c3d2SMichael Ellerman 
read_debugfs_int(const char * debugfs_file,int * result)502121d340bSBenjamin Gray int read_debugfs_int(const char *debugfs_file, int *result)
503d2bf7932SNaveen N. Rao {
504a974f0c1SBenjamin Gray 	int err;
505a974f0c1SBenjamin Gray 	char value[16] = {0};
506d2bf7932SNaveen N. Rao 
507121d340bSBenjamin Gray 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
508a974f0c1SBenjamin Gray 	if (err)
509a974f0c1SBenjamin Gray 		return err;
510d2bf7932SNaveen N. Rao 
511d1bc05b7SBenjamin Gray 	return parse_int(value, sizeof(value), result, 10);
512d2bf7932SNaveen N. Rao }
513d2bf7932SNaveen N. Rao 
write_debugfs_int(const char * debugfs_file,int result)514121d340bSBenjamin Gray int write_debugfs_int(const char *debugfs_file, int result)
515d2bf7932SNaveen N. Rao {
516d2bf7932SNaveen N. Rao 	char value[16];
517d2bf7932SNaveen N. Rao 
518d2bf7932SNaveen N. Rao 	snprintf(value, 16, "%d", result);
519d2bf7932SNaveen N. Rao 
520121d340bSBenjamin Gray 	return write_debugfs_file(debugfs_file, value, strlen(value));
521d2bf7932SNaveen N. Rao }
522d2bf7932SNaveen N. Rao 
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)523d2bf7932SNaveen N. Rao static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
524d2bf7932SNaveen N. Rao 		int cpu, int group_fd, unsigned long flags)
525d2bf7932SNaveen N. Rao {
526d2bf7932SNaveen N. Rao 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
527d2bf7932SNaveen N. Rao 		      group_fd, flags);
528d2bf7932SNaveen N. Rao }
529d2bf7932SNaveen N. Rao 
perf_event_attr_init(struct perf_event_attr * event_attr,unsigned int type,unsigned long config)530d2bf7932SNaveen N. Rao static void perf_event_attr_init(struct perf_event_attr *event_attr,
531d2bf7932SNaveen N. Rao 					unsigned int type,
532d2bf7932SNaveen N. Rao 					unsigned long config)
533d2bf7932SNaveen N. Rao {
534d2bf7932SNaveen N. Rao 	memset(event_attr, 0, sizeof(*event_attr));
535d2bf7932SNaveen N. Rao 
536d2bf7932SNaveen N. Rao 	event_attr->type = type;
537d2bf7932SNaveen N. Rao 	event_attr->size = sizeof(struct perf_event_attr);
538d2bf7932SNaveen N. Rao 	event_attr->config = config;
539d2bf7932SNaveen N. Rao 	event_attr->read_format = PERF_FORMAT_GROUP;
540d2bf7932SNaveen N. Rao 	event_attr->disabled = 1;
541d2bf7932SNaveen N. Rao 	event_attr->exclude_kernel = 1;
542d2bf7932SNaveen N. Rao 	event_attr->exclude_hv = 1;
543d2bf7932SNaveen N. Rao 	event_attr->exclude_guest = 1;
544d2bf7932SNaveen N. Rao }
545d2bf7932SNaveen N. Rao 
perf_event_open_counter(unsigned int type,unsigned long config,int group_fd)546d2bf7932SNaveen N. Rao int perf_event_open_counter(unsigned int type,
547d2bf7932SNaveen N. Rao 			    unsigned long config, int group_fd)
548d2bf7932SNaveen N. Rao {
549d2bf7932SNaveen N. Rao 	int fd;
550d2bf7932SNaveen N. Rao 	struct perf_event_attr event_attr;
551d2bf7932SNaveen N. Rao 
552d2bf7932SNaveen N. Rao 	perf_event_attr_init(&event_attr, type, config);
553d2bf7932SNaveen N. Rao 
554d2bf7932SNaveen N. Rao 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
555d2bf7932SNaveen N. Rao 
556d2bf7932SNaveen N. Rao 	if (fd < 0)
557d2bf7932SNaveen N. Rao 		perror("perf_event_open() failed");
558d2bf7932SNaveen N. Rao 
559d2bf7932SNaveen N. Rao 	return fd;
560d2bf7932SNaveen N. Rao }
561d2bf7932SNaveen N. Rao 
perf_event_enable(int fd)562d2bf7932SNaveen N. Rao int perf_event_enable(int fd)
563d2bf7932SNaveen N. Rao {
564d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
565d2bf7932SNaveen N. Rao 		perror("error while enabling perf events");
566d2bf7932SNaveen N. Rao 		return -1;
567d2bf7932SNaveen N. Rao 	}
568d2bf7932SNaveen N. Rao 
569d2bf7932SNaveen N. Rao 	return 0;
570d2bf7932SNaveen N. Rao }
571d2bf7932SNaveen N. Rao 
perf_event_disable(int fd)572d2bf7932SNaveen N. Rao int perf_event_disable(int fd)
573d2bf7932SNaveen N. Rao {
574d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
575d2bf7932SNaveen N. Rao 		perror("error disabling perf events");
576d2bf7932SNaveen N. Rao 		return -1;
577d2bf7932SNaveen N. Rao 	}
578d2bf7932SNaveen N. Rao 
579d2bf7932SNaveen N. Rao 	return 0;
580d2bf7932SNaveen N. Rao }
581d2bf7932SNaveen N. Rao 
perf_event_reset(int fd)582d2bf7932SNaveen N. Rao int perf_event_reset(int fd)
583d2bf7932SNaveen N. Rao {
584d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
585d2bf7932SNaveen N. Rao 		perror("error resetting perf events");
586d2bf7932SNaveen N. Rao 		return -1;
587d2bf7932SNaveen N. Rao 	}
588d2bf7932SNaveen N. Rao 
589d2bf7932SNaveen N. Rao 	return 0;
590d2bf7932SNaveen N. Rao }
591d2bf7932SNaveen N. Rao 
using_hash_mmu(bool * using_hash)592c405b738SSandipan Das int using_hash_mmu(bool *using_hash)
593c405b738SSandipan Das {
594c405b738SSandipan Das 	char line[128];
595c405b738SSandipan Das 	FILE *f;
596c405b738SSandipan Das 	int rc;
597c405b738SSandipan Das 
598c405b738SSandipan Das 	f = fopen("/proc/cpuinfo", "r");
599c405b738SSandipan Das 	FAIL_IF(!f);
600c405b738SSandipan Das 
601c405b738SSandipan Das 	rc = 0;
602c405b738SSandipan Das 	while (fgets(line, sizeof(line), f) != NULL) {
60334c10334SMichael Ellerman 		if (!strcmp(line, "MMU		: Hash\n") ||
60434c10334SMichael Ellerman 		    !strcmp(line, "platform	: Cell\n") ||
60534c10334SMichael Ellerman 		    !strcmp(line, "platform	: PowerMac\n")) {
606c405b738SSandipan Das 			*using_hash = true;
607c405b738SSandipan Das 			goto out;
608c405b738SSandipan Das 		}
609c405b738SSandipan Das 
610c405b738SSandipan Das 		if (strcmp(line, "MMU		: Radix\n") == 0) {
611c405b738SSandipan Das 			*using_hash = false;
612c405b738SSandipan Das 			goto out;
613c405b738SSandipan Das 		}
614c405b738SSandipan Das 	}
615c405b738SSandipan Das 
616c405b738SSandipan Das 	rc = -1;
617c405b738SSandipan Das out:
618c405b738SSandipan Das 	fclose(f);
619c405b738SSandipan Das 	return rc;
620c405b738SSandipan Das }
621 
push_signal_handler(int sig,void (* fn)(int,siginfo_t *,void *))622 struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *))
623 {
624 	struct sigaction sa;
625 	struct sigaction old_handler;
626 
627 	sa.sa_sigaction = fn;
628 	sigemptyset(&sa.sa_mask);
629 	sa.sa_flags = SA_SIGINFO;
630 	FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler),
631 			 "failed to push signal handler");
632 
633 	return old_handler;
634 }
635 
pop_signal_handler(int sig,struct sigaction old_handler)636 struct sigaction pop_signal_handler(int sig, struct sigaction old_handler)
637 {
638 	struct sigaction popped;
639 
640 	FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped),
641 			 "failed to pop signal handler");
642 
643 	return popped;
644 }
645