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