xref: /linux/tools/testing/selftests/powerpc/utils.c (revision d1bc05b7bf02f8635fe6c445f67d78f85234cbb7)
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 <inttypes.h>
12 #include <limits.h>
13 #include <link.h>
14 #include <sched.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <sys/sysinfo.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
23 #include <unistd.h>
24 #include <asm/unistd.h>
25 #include <linux/limits.h>
26 
27 #include "utils.h"
28 
29 static char auxv[4096];
30 
31 int read_file(const char *path, char *buf, size_t count, size_t *len)
32 {
33 	ssize_t rc;
34 	int fd;
35 	int err;
36 	char eof;
37 
38 	fd = open(path, O_RDONLY);
39 	if (fd < 0)
40 		return -errno;
41 
42 	rc = read(fd, buf, count);
43 	if (rc < 0) {
44 		err = -errno;
45 		goto out;
46 	}
47 
48 	if (len)
49 		*len = rc;
50 
51 	/* Overflow if there are still more bytes after filling the buffer */
52 	if (rc == count) {
53 		rc = read(fd, &eof, 1);
54 		if (rc != 0) {
55 			err = -EOVERFLOW;
56 			goto out;
57 		}
58 	}
59 
60 	err = 0;
61 
62 out:
63 	close(fd);
64 	errno = -err;
65 	return err;
66 }
67 
68 int write_file(const char *path, const char *buf, size_t count)
69 {
70 	int fd;
71 	int err;
72 	ssize_t rc;
73 
74 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
75 	if (fd < 0)
76 		return -errno;
77 
78 	rc = write(fd, buf, count);
79 	if (rc < 0) {
80 		err = -errno;
81 		goto out;
82 	}
83 
84 	if (rc != count) {
85 		err = -EOVERFLOW;
86 		goto out;
87 	}
88 
89 	err = 0;
90 
91 out:
92 	close(fd);
93 	errno = -err;
94 	return err;
95 }
96 
97 int read_auxv(char *buf, ssize_t buf_size)
98 {
99 	int err;
100 
101 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);
102 	if (err) {
103 		perror("Error reading /proc/self/auxv");
104 		return err;
105 	}
106 
107 	return 0;
108 }
109 
110 int read_debugfs_file(const char *subpath, char *buf, size_t count)
111 {
112 	char path[PATH_MAX] = "/sys/kernel/debug/";
113 
114 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
115 
116 	return read_file(path, buf, count, NULL);
117 }
118 
119 int write_debugfs_file(const char *subpath, const char *buf, size_t count)
120 {
121 	char path[PATH_MAX] = "/sys/kernel/debug/";
122 
123 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
124 
125 	return write_file(path, buf, count);
126 }
127 
128 static int validate_int_parse(const char *buffer, size_t count, char *end)
129 {
130 	int err = 0;
131 
132 	/* Require at least one digit */
133 	if (end == buffer) {
134 		err = -EINVAL;
135 		goto out;
136 	}
137 
138 	/* Require all remaining characters be whitespace-ish */
139 	for (; end < buffer + count; end++) {
140 		if (*end == '\0')
141 			break;
142 
143 		if (*end != ' ' && *end != '\n') {
144 			err = -EINVAL;
145 			goto out;
146 		}
147 	}
148 
149 out:
150 	errno = -err;
151 	return err;
152 }
153 
154 static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
155 			     int base, intmax_t min, intmax_t max)
156 {
157 	int err;
158 	char *end;
159 
160 	errno = 0;
161 	*result = strtoimax(buffer, &end, base);
162 
163 	if (errno)
164 		return -errno;
165 
166 	err = validate_int_parse(buffer, count, end);
167 	if (err)
168 		goto out;
169 
170 	if (*result < min || *result > max)
171 		err = -EOVERFLOW;
172 
173 out:
174 	errno = -err;
175 	return err;
176 }
177 
178 static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
179 			      int base, uintmax_t max)
180 {
181 	int err = 0;
182 	char *end;
183 
184 	errno = 0;
185 	*result = strtoumax(buffer, &end, base);
186 
187 	if (errno)
188 		return -errno;
189 
190 	err = validate_int_parse(buffer, count, end);
191 	if (err)
192 		goto out;
193 
194 	if (*result > max)
195 		err = -EOVERFLOW;
196 
197 out:
198 	errno = -err;
199 	return err;
200 }
201 
202 int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
203 {
204 	return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
205 }
206 
207 int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
208 {
209 	return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
210 }
211 
212 int parse_int(const char *buffer, size_t count, int *result, int base)
213 {
214 	intmax_t parsed;
215 	int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
216 
217 	*result = parsed;
218 	return err;
219 }
220 
221 int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
222 {
223 	uintmax_t parsed;
224 	int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
225 
226 	*result = parsed;
227 	return err;
228 }
229 
230 int parse_long(const char *buffer, size_t count, long *result, int base)
231 {
232 	intmax_t parsed;
233 	int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
234 
235 	*result = parsed;
236 	return err;
237 }
238 
239 int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
240 {
241 	uintmax_t parsed;
242 	int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
243 
244 	*result = parsed;
245 	return err;
246 }
247 
248 void *find_auxv_entry(int type, char *auxv)
249 {
250 	ElfW(auxv_t) *p;
251 
252 	p = (ElfW(auxv_t) *)auxv;
253 
254 	while (p->a_type != AT_NULL) {
255 		if (p->a_type == type)
256 			return p;
257 
258 		p++;
259 	}
260 
261 	return NULL;
262 }
263 
264 void *get_auxv_entry(int type)
265 {
266 	ElfW(auxv_t) *p;
267 
268 	if (read_auxv(auxv, sizeof(auxv)))
269 		return NULL;
270 
271 	p = find_auxv_entry(type, auxv);
272 	if (p)
273 		return (void *)p->a_un.a_val;
274 
275 	return NULL;
276 }
277 
278 int pick_online_cpu(void)
279 {
280 	int ncpus, cpu = -1;
281 	cpu_set_t *mask;
282 	size_t size;
283 
284 	ncpus = get_nprocs_conf();
285 	size = CPU_ALLOC_SIZE(ncpus);
286 	mask = CPU_ALLOC(ncpus);
287 	if (!mask) {
288 		perror("malloc");
289 		return -1;
290 	}
291 
292 	CPU_ZERO_S(size, mask);
293 
294 	if (sched_getaffinity(0, size, mask)) {
295 		perror("sched_getaffinity");
296 		goto done;
297 	}
298 
299 	/* We prefer a primary thread, but skip 0 */
300 	for (cpu = 8; cpu < ncpus; cpu += 8)
301 		if (CPU_ISSET_S(cpu, size, mask))
302 			goto done;
303 
304 	/* Search for anything, but in reverse */
305 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
306 		if (CPU_ISSET_S(cpu, size, mask))
307 			goto done;
308 
309 	printf("No cpus in affinity mask?!\n");
310 
311 done:
312 	CPU_FREE(mask);
313 	return cpu;
314 }
315 
316 bool is_ppc64le(void)
317 {
318 	struct utsname uts;
319 	int rc;
320 
321 	errno = 0;
322 	rc = uname(&uts);
323 	if (rc) {
324 		perror("uname");
325 		return false;
326 	}
327 
328 	return strcmp(uts.machine, "ppc64le") == 0;
329 }
330 
331 int read_sysfs_file(char *fpath, char *result, size_t result_size)
332 {
333 	char path[PATH_MAX] = "/sys/";
334 
335 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
336 
337 	return read_file(path, result, result_size, NULL);
338 }
339 
340 int read_debugfs_int(const char *debugfs_file, int *result)
341 {
342 	int err;
343 	char value[16] = {0};
344 
345 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
346 	if (err)
347 		return err;
348 
349 	return parse_int(value, sizeof(value), result, 10);
350 }
351 
352 int write_debugfs_int(const char *debugfs_file, int result)
353 {
354 	char value[16];
355 
356 	snprintf(value, 16, "%d", result);
357 
358 	return write_debugfs_file(debugfs_file, value, strlen(value));
359 }
360 
361 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
362 		int cpu, int group_fd, unsigned long flags)
363 {
364 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
365 		      group_fd, flags);
366 }
367 
368 static void perf_event_attr_init(struct perf_event_attr *event_attr,
369 					unsigned int type,
370 					unsigned long config)
371 {
372 	memset(event_attr, 0, sizeof(*event_attr));
373 
374 	event_attr->type = type;
375 	event_attr->size = sizeof(struct perf_event_attr);
376 	event_attr->config = config;
377 	event_attr->read_format = PERF_FORMAT_GROUP;
378 	event_attr->disabled = 1;
379 	event_attr->exclude_kernel = 1;
380 	event_attr->exclude_hv = 1;
381 	event_attr->exclude_guest = 1;
382 }
383 
384 int perf_event_open_counter(unsigned int type,
385 			    unsigned long config, int group_fd)
386 {
387 	int fd;
388 	struct perf_event_attr event_attr;
389 
390 	perf_event_attr_init(&event_attr, type, config);
391 
392 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
393 
394 	if (fd < 0)
395 		perror("perf_event_open() failed");
396 
397 	return fd;
398 }
399 
400 int perf_event_enable(int fd)
401 {
402 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
403 		perror("error while enabling perf events");
404 		return -1;
405 	}
406 
407 	return 0;
408 }
409 
410 int perf_event_disable(int fd)
411 {
412 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
413 		perror("error disabling perf events");
414 		return -1;
415 	}
416 
417 	return 0;
418 }
419 
420 int perf_event_reset(int fd)
421 {
422 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
423 		perror("error resetting perf events");
424 		return -1;
425 	}
426 
427 	return 0;
428 }
429 
430 int using_hash_mmu(bool *using_hash)
431 {
432 	char line[128];
433 	FILE *f;
434 	int rc;
435 
436 	f = fopen("/proc/cpuinfo", "r");
437 	FAIL_IF(!f);
438 
439 	rc = 0;
440 	while (fgets(line, sizeof(line), f) != NULL) {
441 		if (!strcmp(line, "MMU		: Hash\n") ||
442 		    !strcmp(line, "platform	: Cell\n") ||
443 		    !strcmp(line, "platform	: PowerMac\n")) {
444 			*using_hash = true;
445 			goto out;
446 		}
447 
448 		if (strcmp(line, "MMU		: Radix\n") == 0) {
449 			*using_hash = false;
450 			goto out;
451 		}
452 	}
453 
454 	rc = -1;
455 out:
456 	fclose(f);
457 	return rc;
458 }
459