xref: /openbmc/linux/tools/testing/selftests/powerpc/utils.c (revision 121d340be9a17ed89d523c56203908c01e09a306)
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>
11fcb45ec0SMichael Ellerman #include <link.h>
12d1301afdSMichael Ellerman #include <sched.h>
13fcb45ec0SMichael Ellerman #include <stdio.h>
14d2bf7932SNaveen N. Rao #include <stdlib.h>
1595f9b3afSMichael Ellerman #include <string.h>
16d2bf7932SNaveen N. Rao #include <sys/ioctl.h>
17fcb45ec0SMichael Ellerman #include <sys/stat.h>
18dfa03fffSSandipan Das #include <sys/sysinfo.h>
19fcb45ec0SMichael Ellerman #include <sys/types.h>
2095f9b3afSMichael Ellerman #include <sys/utsname.h>
21fcb45ec0SMichael Ellerman #include <unistd.h>
22d2bf7932SNaveen N. Rao #include <asm/unistd.h>
23d2bf7932SNaveen N. Rao #include <linux/limits.h>
24fcb45ec0SMichael Ellerman 
25fcb45ec0SMichael Ellerman #include "utils.h"
26fcb45ec0SMichael Ellerman 
27fcb45ec0SMichael Ellerman static char auxv[4096];
28fcb45ec0SMichael Ellerman 
29a974f0c1SBenjamin Gray int read_file(const char *path, char *buf, size_t count, size_t *len)
30fcb45ec0SMichael Ellerman {
31a974f0c1SBenjamin Gray 	ssize_t rc;
32a974f0c1SBenjamin Gray 	int fd;
33a974f0c1SBenjamin Gray 	int err;
34a974f0c1SBenjamin Gray 	char eof;
35fcb45ec0SMichael Ellerman 
36a974f0c1SBenjamin Gray 	fd = open(path, O_RDONLY);
37a974f0c1SBenjamin Gray 	if (fd < 0)
38e3028437SMichael Ellerman 		return -errno;
39fcb45ec0SMichael Ellerman 
40a974f0c1SBenjamin Gray 	rc = read(fd, buf, count);
41a974f0c1SBenjamin Gray 	if (rc < 0) {
42a974f0c1SBenjamin Gray 		err = -errno;
43fcb45ec0SMichael Ellerman 		goto out;
44fcb45ec0SMichael Ellerman 	}
45fcb45ec0SMichael Ellerman 
46a974f0c1SBenjamin Gray 	if (len)
47a974f0c1SBenjamin Gray 		*len = rc;
48a974f0c1SBenjamin Gray 
49a974f0c1SBenjamin Gray 	/* Overflow if there are still more bytes after filling the buffer */
50a974f0c1SBenjamin Gray 	if (rc == count) {
51a974f0c1SBenjamin Gray 		rc = read(fd, &eof, 1);
52a974f0c1SBenjamin Gray 		if (rc != 0) {
53a974f0c1SBenjamin Gray 			err = -EOVERFLOW;
54fcb45ec0SMichael Ellerman 			goto out;
55fcb45ec0SMichael Ellerman 		}
56a974f0c1SBenjamin Gray 	}
57fcb45ec0SMichael Ellerman 
58a974f0c1SBenjamin Gray 	err = 0;
59a974f0c1SBenjamin Gray 
60e3028437SMichael Ellerman out:
61e3028437SMichael Ellerman 	close(fd);
62a974f0c1SBenjamin Gray 	errno = -err;
63a974f0c1SBenjamin Gray 	return err;
64a974f0c1SBenjamin Gray }
65a974f0c1SBenjamin Gray 
66a974f0c1SBenjamin Gray int write_file(const char *path, const char *buf, size_t count)
67a974f0c1SBenjamin Gray {
68a974f0c1SBenjamin Gray 	int fd;
69a974f0c1SBenjamin Gray 	int err;
70a974f0c1SBenjamin Gray 	ssize_t rc;
71a974f0c1SBenjamin Gray 
72a974f0c1SBenjamin Gray 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
73a974f0c1SBenjamin Gray 	if (fd < 0)
74a974f0c1SBenjamin Gray 		return -errno;
75a974f0c1SBenjamin Gray 
76a974f0c1SBenjamin Gray 	rc = write(fd, buf, count);
77a974f0c1SBenjamin Gray 	if (rc < 0) {
78a974f0c1SBenjamin Gray 		err = -errno;
79a974f0c1SBenjamin Gray 		goto out;
80a974f0c1SBenjamin Gray 	}
81a974f0c1SBenjamin Gray 
82a974f0c1SBenjamin Gray 	if (rc != count) {
83a974f0c1SBenjamin Gray 		err = -EOVERFLOW;
84a974f0c1SBenjamin Gray 		goto out;
85a974f0c1SBenjamin Gray 	}
86a974f0c1SBenjamin Gray 
87a974f0c1SBenjamin Gray 	err = 0;
88a974f0c1SBenjamin Gray 
89a974f0c1SBenjamin Gray out:
90a974f0c1SBenjamin Gray 	close(fd);
91a974f0c1SBenjamin Gray 	errno = -err;
92a974f0c1SBenjamin Gray 	return err;
93a974f0c1SBenjamin Gray }
94a974f0c1SBenjamin Gray 
95a974f0c1SBenjamin Gray int read_auxv(char *buf, ssize_t buf_size)
96a974f0c1SBenjamin Gray {
97a974f0c1SBenjamin Gray 	int err;
98a974f0c1SBenjamin Gray 
99a974f0c1SBenjamin Gray 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);
100a974f0c1SBenjamin Gray 	if (err) {
101a974f0c1SBenjamin Gray 		perror("Error reading /proc/self/auxv");
102a974f0c1SBenjamin Gray 		return err;
103a974f0c1SBenjamin Gray 	}
104a974f0c1SBenjamin Gray 
105a974f0c1SBenjamin Gray 	return 0;
106e3028437SMichael Ellerman }
107e3028437SMichael Ellerman 
108*121d340bSBenjamin Gray int read_debugfs_file(const char *subpath, char *buf, size_t count)
109*121d340bSBenjamin Gray {
110*121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
111*121d340bSBenjamin Gray 
112*121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
113*121d340bSBenjamin Gray 
114*121d340bSBenjamin Gray 	return read_file(path, buf, count, NULL);
115*121d340bSBenjamin Gray }
116*121d340bSBenjamin Gray 
117*121d340bSBenjamin Gray int write_debugfs_file(const char *subpath, const char *buf, size_t count)
118*121d340bSBenjamin Gray {
119*121d340bSBenjamin Gray 	char path[PATH_MAX] = "/sys/kernel/debug/";
120*121d340bSBenjamin Gray 
121*121d340bSBenjamin Gray 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
122*121d340bSBenjamin Gray 
123*121d340bSBenjamin Gray 	return write_file(path, buf, count);
124*121d340bSBenjamin Gray }
125*121d340bSBenjamin Gray 
126e3028437SMichael Ellerman void *find_auxv_entry(int type, char *auxv)
127e3028437SMichael Ellerman {
128e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
129e3028437SMichael Ellerman 
130fcb45ec0SMichael Ellerman 	p = (ElfW(auxv_t) *)auxv;
131fcb45ec0SMichael Ellerman 
132fcb45ec0SMichael Ellerman 	while (p->a_type != AT_NULL) {
133e3028437SMichael Ellerman 		if (p->a_type == type)
134e3028437SMichael Ellerman 			return p;
135fcb45ec0SMichael Ellerman 
136fcb45ec0SMichael Ellerman 		p++;
137fcb45ec0SMichael Ellerman 	}
138e3028437SMichael Ellerman 
139e3028437SMichael Ellerman 	return NULL;
140e3028437SMichael Ellerman }
141e3028437SMichael Ellerman 
142e3028437SMichael Ellerman void *get_auxv_entry(int type)
143e3028437SMichael Ellerman {
144e3028437SMichael Ellerman 	ElfW(auxv_t) *p;
145e3028437SMichael Ellerman 
146e3028437SMichael Ellerman 	if (read_auxv(auxv, sizeof(auxv)))
147e3028437SMichael Ellerman 		return NULL;
148e3028437SMichael Ellerman 
149e3028437SMichael Ellerman 	p = find_auxv_entry(type, auxv);
150e3028437SMichael Ellerman 	if (p)
151e3028437SMichael Ellerman 		return (void *)p->a_un.a_val;
152e3028437SMichael Ellerman 
153e3028437SMichael Ellerman 	return NULL;
154fcb45ec0SMichael Ellerman }
155d1301afdSMichael Ellerman 
156d1301afdSMichael Ellerman int pick_online_cpu(void)
157d1301afdSMichael Ellerman {
158dfa03fffSSandipan Das 	int ncpus, cpu = -1;
159dfa03fffSSandipan Das 	cpu_set_t *mask;
160dfa03fffSSandipan Das 	size_t size;
161d1301afdSMichael Ellerman 
162dfa03fffSSandipan Das 	ncpus = get_nprocs_conf();
163dfa03fffSSandipan Das 	size = CPU_ALLOC_SIZE(ncpus);
164dfa03fffSSandipan Das 	mask = CPU_ALLOC(ncpus);
165dfa03fffSSandipan Das 	if (!mask) {
166dfa03fffSSandipan Das 		perror("malloc");
167d1301afdSMichael Ellerman 		return -1;
168d1301afdSMichael Ellerman 	}
169d1301afdSMichael Ellerman 
170dfa03fffSSandipan Das 	CPU_ZERO_S(size, mask);
171dfa03fffSSandipan Das 
172dfa03fffSSandipan Das 	if (sched_getaffinity(0, size, mask)) {
173dfa03fffSSandipan Das 		perror("sched_getaffinity");
174dfa03fffSSandipan Das 		goto done;
175dfa03fffSSandipan Das 	}
176dfa03fffSSandipan Das 
177d1301afdSMichael Ellerman 	/* We prefer a primary thread, but skip 0 */
178dfa03fffSSandipan Das 	for (cpu = 8; cpu < ncpus; cpu += 8)
179dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
180dfa03fffSSandipan Das 			goto done;
181d1301afdSMichael Ellerman 
182d1301afdSMichael Ellerman 	/* Search for anything, but in reverse */
183dfa03fffSSandipan Das 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
184dfa03fffSSandipan Das 		if (CPU_ISSET_S(cpu, size, mask))
185dfa03fffSSandipan Das 			goto done;
186d1301afdSMichael Ellerman 
187d1301afdSMichael Ellerman 	printf("No cpus in affinity mask?!\n");
188dfa03fffSSandipan Das 
189dfa03fffSSandipan Das done:
190dfa03fffSSandipan Das 	CPU_FREE(mask);
191dfa03fffSSandipan Das 	return cpu;
192d1301afdSMichael Ellerman }
19395f9b3afSMichael Ellerman 
19495f9b3afSMichael Ellerman bool is_ppc64le(void)
19595f9b3afSMichael Ellerman {
19695f9b3afSMichael Ellerman 	struct utsname uts;
19795f9b3afSMichael Ellerman 	int rc;
19895f9b3afSMichael Ellerman 
19995f9b3afSMichael Ellerman 	errno = 0;
20095f9b3afSMichael Ellerman 	rc = uname(&uts);
20195f9b3afSMichael Ellerman 	if (rc) {
20295f9b3afSMichael Ellerman 		perror("uname");
20395f9b3afSMichael Ellerman 		return false;
20495f9b3afSMichael Ellerman 	}
20595f9b3afSMichael Ellerman 
20695f9b3afSMichael Ellerman 	return strcmp(uts.machine, "ppc64le") == 0;
20795f9b3afSMichael Ellerman }
208d2bf7932SNaveen N. Rao 
209c790c3d2SMichael Ellerman int read_sysfs_file(char *fpath, char *result, size_t result_size)
210c790c3d2SMichael Ellerman {
211c790c3d2SMichael Ellerman 	char path[PATH_MAX] = "/sys/";
212c790c3d2SMichael Ellerman 
213c790c3d2SMichael Ellerman 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
214c790c3d2SMichael Ellerman 
215a974f0c1SBenjamin Gray 	return read_file(path, result, result_size, NULL);
216c790c3d2SMichael Ellerman }
217c790c3d2SMichael Ellerman 
218*121d340bSBenjamin Gray int read_debugfs_int(const char *debugfs_file, int *result)
219d2bf7932SNaveen N. Rao {
220a974f0c1SBenjamin Gray 	int err;
221a974f0c1SBenjamin Gray 	char value[16] = {0};
222d2bf7932SNaveen N. Rao 
223*121d340bSBenjamin Gray 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
224a974f0c1SBenjamin Gray 	if (err)
225a974f0c1SBenjamin Gray 		return err;
226d2bf7932SNaveen N. Rao 
227d2bf7932SNaveen N. Rao 	*result = atoi(value);
228d2bf7932SNaveen N. Rao 
229d2bf7932SNaveen N. Rao 	return 0;
230d2bf7932SNaveen N. Rao }
231d2bf7932SNaveen N. Rao 
232*121d340bSBenjamin Gray int write_debugfs_int(const char *debugfs_file, int result)
233d2bf7932SNaveen N. Rao {
234d2bf7932SNaveen N. Rao 	char value[16];
235d2bf7932SNaveen N. Rao 
236d2bf7932SNaveen N. Rao 	snprintf(value, 16, "%d", result);
237d2bf7932SNaveen N. Rao 
238*121d340bSBenjamin Gray 	return write_debugfs_file(debugfs_file, value, strlen(value));
239d2bf7932SNaveen N. Rao }
240d2bf7932SNaveen N. Rao 
241d2bf7932SNaveen N. Rao static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
242d2bf7932SNaveen N. Rao 		int cpu, int group_fd, unsigned long flags)
243d2bf7932SNaveen N. Rao {
244d2bf7932SNaveen N. Rao 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
245d2bf7932SNaveen N. Rao 		      group_fd, flags);
246d2bf7932SNaveen N. Rao }
247d2bf7932SNaveen N. Rao 
248d2bf7932SNaveen N. Rao static void perf_event_attr_init(struct perf_event_attr *event_attr,
249d2bf7932SNaveen N. Rao 					unsigned int type,
250d2bf7932SNaveen N. Rao 					unsigned long config)
251d2bf7932SNaveen N. Rao {
252d2bf7932SNaveen N. Rao 	memset(event_attr, 0, sizeof(*event_attr));
253d2bf7932SNaveen N. Rao 
254d2bf7932SNaveen N. Rao 	event_attr->type = type;
255d2bf7932SNaveen N. Rao 	event_attr->size = sizeof(struct perf_event_attr);
256d2bf7932SNaveen N. Rao 	event_attr->config = config;
257d2bf7932SNaveen N. Rao 	event_attr->read_format = PERF_FORMAT_GROUP;
258d2bf7932SNaveen N. Rao 	event_attr->disabled = 1;
259d2bf7932SNaveen N. Rao 	event_attr->exclude_kernel = 1;
260d2bf7932SNaveen N. Rao 	event_attr->exclude_hv = 1;
261d2bf7932SNaveen N. Rao 	event_attr->exclude_guest = 1;
262d2bf7932SNaveen N. Rao }
263d2bf7932SNaveen N. Rao 
264d2bf7932SNaveen N. Rao int perf_event_open_counter(unsigned int type,
265d2bf7932SNaveen N. Rao 			    unsigned long config, int group_fd)
266d2bf7932SNaveen N. Rao {
267d2bf7932SNaveen N. Rao 	int fd;
268d2bf7932SNaveen N. Rao 	struct perf_event_attr event_attr;
269d2bf7932SNaveen N. Rao 
270d2bf7932SNaveen N. Rao 	perf_event_attr_init(&event_attr, type, config);
271d2bf7932SNaveen N. Rao 
272d2bf7932SNaveen N. Rao 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
273d2bf7932SNaveen N. Rao 
274d2bf7932SNaveen N. Rao 	if (fd < 0)
275d2bf7932SNaveen N. Rao 		perror("perf_event_open() failed");
276d2bf7932SNaveen N. Rao 
277d2bf7932SNaveen N. Rao 	return fd;
278d2bf7932SNaveen N. Rao }
279d2bf7932SNaveen N. Rao 
280d2bf7932SNaveen N. Rao int perf_event_enable(int fd)
281d2bf7932SNaveen N. Rao {
282d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
283d2bf7932SNaveen N. Rao 		perror("error while enabling perf events");
284d2bf7932SNaveen N. Rao 		return -1;
285d2bf7932SNaveen N. Rao 	}
286d2bf7932SNaveen N. Rao 
287d2bf7932SNaveen N. Rao 	return 0;
288d2bf7932SNaveen N. Rao }
289d2bf7932SNaveen N. Rao 
290d2bf7932SNaveen N. Rao int perf_event_disable(int fd)
291d2bf7932SNaveen N. Rao {
292d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
293d2bf7932SNaveen N. Rao 		perror("error disabling perf events");
294d2bf7932SNaveen N. Rao 		return -1;
295d2bf7932SNaveen N. Rao 	}
296d2bf7932SNaveen N. Rao 
297d2bf7932SNaveen N. Rao 	return 0;
298d2bf7932SNaveen N. Rao }
299d2bf7932SNaveen N. Rao 
300d2bf7932SNaveen N. Rao int perf_event_reset(int fd)
301d2bf7932SNaveen N. Rao {
302d2bf7932SNaveen N. Rao 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
303d2bf7932SNaveen N. Rao 		perror("error resetting perf events");
304d2bf7932SNaveen N. Rao 		return -1;
305d2bf7932SNaveen N. Rao 	}
306d2bf7932SNaveen N. Rao 
307d2bf7932SNaveen N. Rao 	return 0;
308d2bf7932SNaveen N. Rao }
309d2bf7932SNaveen N. Rao 
310c405b738SSandipan Das int using_hash_mmu(bool *using_hash)
311c405b738SSandipan Das {
312c405b738SSandipan Das 	char line[128];
313c405b738SSandipan Das 	FILE *f;
314c405b738SSandipan Das 	int rc;
315c405b738SSandipan Das 
316c405b738SSandipan Das 	f = fopen("/proc/cpuinfo", "r");
317c405b738SSandipan Das 	FAIL_IF(!f);
318c405b738SSandipan Das 
319c405b738SSandipan Das 	rc = 0;
320c405b738SSandipan Das 	while (fgets(line, sizeof(line), f) != NULL) {
32134c10334SMichael Ellerman 		if (!strcmp(line, "MMU		: Hash\n") ||
32234c10334SMichael Ellerman 		    !strcmp(line, "platform	: Cell\n") ||
32334c10334SMichael Ellerman 		    !strcmp(line, "platform	: PowerMac\n")) {
324c405b738SSandipan Das 			*using_hash = true;
325c405b738SSandipan Das 			goto out;
326c405b738SSandipan Das 		}
327c405b738SSandipan Das 
328c405b738SSandipan Das 		if (strcmp(line, "MMU		: Radix\n") == 0) {
329c405b738SSandipan Das 			*using_hash = false;
330c405b738SSandipan Das 			goto out;
331c405b738SSandipan Das 		}
332c405b738SSandipan Das 	}
333c405b738SSandipan Das 
334c405b738SSandipan Das 	rc = -1;
335c405b738SSandipan Das out:
336c405b738SSandipan Das 	fclose(f);
337c405b738SSandipan Das 	return rc;
338c405b738SSandipan Das }
339