xref: /linux/tools/testing/selftests/powerpc/utils.c (revision 5c20de57888f0962e25a0eeec1a59c98056fc42e)
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 int read_long(const char *path, long *result, int base)
249 {
250 	int err;
251 	char buffer[32] = {0};
252 
253 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
254 	if (err)
255 		return err;
256 
257 	return parse_long(buffer, sizeof(buffer), result, base);
258 }
259 
260 int read_ulong(const char *path, unsigned long *result, int base)
261 {
262 	int err;
263 	char buffer[32] = {0};
264 
265 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
266 	if (err)
267 		return err;
268 
269 	return parse_ulong(buffer, sizeof(buffer), result, base);
270 }
271 
272 int write_long(const char *path, long result, int base)
273 {
274 	int err;
275 	int len;
276 	char buffer[32];
277 
278 	/* Decimal only for now: no format specifier for signed hex values */
279 	if (base != 10) {
280 		err = -EINVAL;
281 		goto out;
282 	}
283 
284 	len = snprintf(buffer, sizeof(buffer), "%ld", result);
285 	if (len < 0 || len >= sizeof(buffer)) {
286 		err = -EOVERFLOW;
287 		goto out;
288 	}
289 
290 	err = write_file(path, buffer, len);
291 
292 out:
293 	errno = -err;
294 	return err;
295 }
296 
297 int write_ulong(const char *path, unsigned long result, int base)
298 {
299 	int err;
300 	int len;
301 	char buffer[32];
302 	char *fmt;
303 
304 	switch (base) {
305 	case 10:
306 		fmt = "%lu";
307 		break;
308 	case 16:
309 		fmt = "%lx";
310 		break;
311 	default:
312 		err = -EINVAL;
313 		goto out;
314 	}
315 
316 	len = snprintf(buffer, sizeof(buffer), fmt, result);
317 	if (len < 0 || len >= sizeof(buffer)) {
318 		err = -errno;
319 		goto out;
320 	}
321 
322 	err = write_file(path, buffer, len);
323 
324 out:
325 	errno = -err;
326 	return err;
327 }
328 
329 void *find_auxv_entry(int type, char *auxv)
330 {
331 	ElfW(auxv_t) *p;
332 
333 	p = (ElfW(auxv_t) *)auxv;
334 
335 	while (p->a_type != AT_NULL) {
336 		if (p->a_type == type)
337 			return p;
338 
339 		p++;
340 	}
341 
342 	return NULL;
343 }
344 
345 void *get_auxv_entry(int type)
346 {
347 	ElfW(auxv_t) *p;
348 
349 	if (read_auxv(auxv, sizeof(auxv)))
350 		return NULL;
351 
352 	p = find_auxv_entry(type, auxv);
353 	if (p)
354 		return (void *)p->a_un.a_val;
355 
356 	return NULL;
357 }
358 
359 int pick_online_cpu(void)
360 {
361 	int ncpus, cpu = -1;
362 	cpu_set_t *mask;
363 	size_t size;
364 
365 	ncpus = get_nprocs_conf();
366 	size = CPU_ALLOC_SIZE(ncpus);
367 	mask = CPU_ALLOC(ncpus);
368 	if (!mask) {
369 		perror("malloc");
370 		return -1;
371 	}
372 
373 	CPU_ZERO_S(size, mask);
374 
375 	if (sched_getaffinity(0, size, mask)) {
376 		perror("sched_getaffinity");
377 		goto done;
378 	}
379 
380 	/* We prefer a primary thread, but skip 0 */
381 	for (cpu = 8; cpu < ncpus; cpu += 8)
382 		if (CPU_ISSET_S(cpu, size, mask))
383 			goto done;
384 
385 	/* Search for anything, but in reverse */
386 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
387 		if (CPU_ISSET_S(cpu, size, mask))
388 			goto done;
389 
390 	printf("No cpus in affinity mask?!\n");
391 
392 done:
393 	CPU_FREE(mask);
394 	return cpu;
395 }
396 
397 bool is_ppc64le(void)
398 {
399 	struct utsname uts;
400 	int rc;
401 
402 	errno = 0;
403 	rc = uname(&uts);
404 	if (rc) {
405 		perror("uname");
406 		return false;
407 	}
408 
409 	return strcmp(uts.machine, "ppc64le") == 0;
410 }
411 
412 int read_sysfs_file(char *fpath, char *result, size_t result_size)
413 {
414 	char path[PATH_MAX] = "/sys/";
415 
416 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
417 
418 	return read_file(path, result, result_size, NULL);
419 }
420 
421 int read_debugfs_int(const char *debugfs_file, int *result)
422 {
423 	int err;
424 	char value[16] = {0};
425 
426 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
427 	if (err)
428 		return err;
429 
430 	return parse_int(value, sizeof(value), result, 10);
431 }
432 
433 int write_debugfs_int(const char *debugfs_file, int result)
434 {
435 	char value[16];
436 
437 	snprintf(value, 16, "%d", result);
438 
439 	return write_debugfs_file(debugfs_file, value, strlen(value));
440 }
441 
442 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
443 		int cpu, int group_fd, unsigned long flags)
444 {
445 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
446 		      group_fd, flags);
447 }
448 
449 static void perf_event_attr_init(struct perf_event_attr *event_attr,
450 					unsigned int type,
451 					unsigned long config)
452 {
453 	memset(event_attr, 0, sizeof(*event_attr));
454 
455 	event_attr->type = type;
456 	event_attr->size = sizeof(struct perf_event_attr);
457 	event_attr->config = config;
458 	event_attr->read_format = PERF_FORMAT_GROUP;
459 	event_attr->disabled = 1;
460 	event_attr->exclude_kernel = 1;
461 	event_attr->exclude_hv = 1;
462 	event_attr->exclude_guest = 1;
463 }
464 
465 int perf_event_open_counter(unsigned int type,
466 			    unsigned long config, int group_fd)
467 {
468 	int fd;
469 	struct perf_event_attr event_attr;
470 
471 	perf_event_attr_init(&event_attr, type, config);
472 
473 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
474 
475 	if (fd < 0)
476 		perror("perf_event_open() failed");
477 
478 	return fd;
479 }
480 
481 int perf_event_enable(int fd)
482 {
483 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
484 		perror("error while enabling perf events");
485 		return -1;
486 	}
487 
488 	return 0;
489 }
490 
491 int perf_event_disable(int fd)
492 {
493 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
494 		perror("error disabling perf events");
495 		return -1;
496 	}
497 
498 	return 0;
499 }
500 
501 int perf_event_reset(int fd)
502 {
503 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
504 		perror("error resetting perf events");
505 		return -1;
506 	}
507 
508 	return 0;
509 }
510 
511 int using_hash_mmu(bool *using_hash)
512 {
513 	char line[128];
514 	FILE *f;
515 	int rc;
516 
517 	f = fopen("/proc/cpuinfo", "r");
518 	FAIL_IF(!f);
519 
520 	rc = 0;
521 	while (fgets(line, sizeof(line), f) != NULL) {
522 		if (!strcmp(line, "MMU		: Hash\n") ||
523 		    !strcmp(line, "platform	: Cell\n") ||
524 		    !strcmp(line, "platform	: PowerMac\n")) {
525 			*using_hash = true;
526 			goto out;
527 		}
528 
529 		if (strcmp(line, "MMU		: Radix\n") == 0) {
530 			*using_hash = false;
531 			goto out;
532 		}
533 	}
534 
535 	rc = -1;
536 out:
537 	fclose(f);
538 	return rc;
539 }
540