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 
read_file(const char * path,char * buf,size_t count,size_t * len)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 
read_file_alloc(const char * path,char ** buf,size_t * len)68 int read_file_alloc(const char *path, char **buf, size_t *len)
69 {
70 	size_t read_offset = 0;
71 	size_t buffer_len = 0;
72 	char *buffer = NULL;
73 	int err;
74 	int fd;
75 
76 	fd = open(path, O_RDONLY);
77 	if (fd < 0)
78 		return -errno;
79 
80 	/*
81 	 * We don't use stat & preallocate st_size because some non-files
82 	 * report 0 file size. Instead just dynamically grow the buffer
83 	 * as needed.
84 	 */
85 	while (1) {
86 		ssize_t rc;
87 
88 		if (read_offset >= buffer_len / 2) {
89 			char *next_buffer;
90 
91 			buffer_len = buffer_len ? buffer_len * 2 : 4096;
92 			next_buffer = realloc(buffer, buffer_len);
93 			if (!next_buffer) {
94 				err = -errno;
95 				goto out;
96 			}
97 			buffer = next_buffer;
98 		}
99 
100 		rc = read(fd, buffer + read_offset, buffer_len - read_offset);
101 		if (rc < 0) {
102 			err = -errno;
103 			goto out;
104 		}
105 
106 		if (rc == 0)
107 			break;
108 
109 		read_offset += rc;
110 	}
111 
112 	*buf = buffer;
113 	if (len)
114 		*len = read_offset;
115 
116 	err = 0;
117 
118 out:
119 	close(fd);
120 	if (err)
121 		free(buffer);
122 	errno = -err;
123 	return err;
124 }
125 
write_file(const char * path,const char * buf,size_t count)126 int write_file(const char *path, const char *buf, size_t count)
127 {
128 	int fd;
129 	int err;
130 	ssize_t rc;
131 
132 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
133 	if (fd < 0)
134 		return -errno;
135 
136 	rc = write(fd, buf, count);
137 	if (rc < 0) {
138 		err = -errno;
139 		goto out;
140 	}
141 
142 	if (rc != count) {
143 		err = -EOVERFLOW;
144 		goto out;
145 	}
146 
147 	err = 0;
148 
149 out:
150 	close(fd);
151 	errno = -err;
152 	return err;
153 }
154 
read_auxv(char * buf,ssize_t buf_size)155 int read_auxv(char *buf, ssize_t buf_size)
156 {
157 	int err;
158 
159 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);
160 	if (err) {
161 		perror("Error reading /proc/self/auxv");
162 		return err;
163 	}
164 
165 	return 0;
166 }
167 
read_debugfs_file(const char * subpath,char * buf,size_t count)168 int read_debugfs_file(const char *subpath, char *buf, size_t count)
169 {
170 	char path[PATH_MAX] = "/sys/kernel/debug/";
171 
172 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
173 
174 	return read_file(path, buf, count, NULL);
175 }
176 
write_debugfs_file(const char * subpath,const char * buf,size_t count)177 int write_debugfs_file(const char *subpath, const char *buf, size_t count)
178 {
179 	char path[PATH_MAX] = "/sys/kernel/debug/";
180 
181 	strncat(path, subpath, sizeof(path) - strlen(path) - 1);
182 
183 	return write_file(path, buf, count);
184 }
185 
validate_int_parse(const char * buffer,size_t count,char * end)186 static int validate_int_parse(const char *buffer, size_t count, char *end)
187 {
188 	int err = 0;
189 
190 	/* Require at least one digit */
191 	if (end == buffer) {
192 		err = -EINVAL;
193 		goto out;
194 	}
195 
196 	/* Require all remaining characters be whitespace-ish */
197 	for (; end < buffer + count; end++) {
198 		if (*end == '\0')
199 			break;
200 
201 		if (*end != ' ' && *end != '\n') {
202 			err = -EINVAL;
203 			goto out;
204 		}
205 	}
206 
207 out:
208 	errno = -err;
209 	return err;
210 }
211 
parse_bounded_int(const char * buffer,size_t count,intmax_t * result,int base,intmax_t min,intmax_t max)212 static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
213 			     int base, intmax_t min, intmax_t max)
214 {
215 	int err;
216 	char *end;
217 
218 	errno = 0;
219 	*result = strtoimax(buffer, &end, base);
220 
221 	if (errno)
222 		return -errno;
223 
224 	err = validate_int_parse(buffer, count, end);
225 	if (err)
226 		goto out;
227 
228 	if (*result < min || *result > max)
229 		err = -EOVERFLOW;
230 
231 out:
232 	errno = -err;
233 	return err;
234 }
235 
parse_bounded_uint(const char * buffer,size_t count,uintmax_t * result,int base,uintmax_t max)236 static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
237 			      int base, uintmax_t max)
238 {
239 	int err = 0;
240 	char *end;
241 
242 	errno = 0;
243 	*result = strtoumax(buffer, &end, base);
244 
245 	if (errno)
246 		return -errno;
247 
248 	err = validate_int_parse(buffer, count, end);
249 	if (err)
250 		goto out;
251 
252 	if (*result > max)
253 		err = -EOVERFLOW;
254 
255 out:
256 	errno = -err;
257 	return err;
258 }
259 
parse_intmax(const char * buffer,size_t count,intmax_t * result,int base)260 int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
261 {
262 	return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
263 }
264 
parse_uintmax(const char * buffer,size_t count,uintmax_t * result,int base)265 int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
266 {
267 	return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
268 }
269 
parse_int(const char * buffer,size_t count,int * result,int base)270 int parse_int(const char *buffer, size_t count, int *result, int base)
271 {
272 	intmax_t parsed;
273 	int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
274 
275 	*result = parsed;
276 	return err;
277 }
278 
parse_uint(const char * buffer,size_t count,unsigned int * result,int base)279 int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
280 {
281 	uintmax_t parsed;
282 	int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
283 
284 	*result = parsed;
285 	return err;
286 }
287 
parse_long(const char * buffer,size_t count,long * result,int base)288 int parse_long(const char *buffer, size_t count, long *result, int base)
289 {
290 	intmax_t parsed;
291 	int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
292 
293 	*result = parsed;
294 	return err;
295 }
296 
parse_ulong(const char * buffer,size_t count,unsigned long * result,int base)297 int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
298 {
299 	uintmax_t parsed;
300 	int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
301 
302 	*result = parsed;
303 	return err;
304 }
305 
read_long(const char * path,long * result,int base)306 int read_long(const char *path, long *result, int base)
307 {
308 	int err;
309 	char buffer[32] = {0};
310 
311 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
312 	if (err)
313 		return err;
314 
315 	return parse_long(buffer, sizeof(buffer), result, base);
316 }
317 
read_ulong(const char * path,unsigned long * result,int base)318 int read_ulong(const char *path, unsigned long *result, int base)
319 {
320 	int err;
321 	char buffer[32] = {0};
322 
323 	err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
324 	if (err)
325 		return err;
326 
327 	return parse_ulong(buffer, sizeof(buffer), result, base);
328 }
329 
write_long(const char * path,long result,int base)330 int write_long(const char *path, long result, int base)
331 {
332 	int err;
333 	int len;
334 	char buffer[32];
335 
336 	/* Decimal only for now: no format specifier for signed hex values */
337 	if (base != 10) {
338 		err = -EINVAL;
339 		goto out;
340 	}
341 
342 	len = snprintf(buffer, sizeof(buffer), "%ld", result);
343 	if (len < 0 || len >= sizeof(buffer)) {
344 		err = -EOVERFLOW;
345 		goto out;
346 	}
347 
348 	err = write_file(path, buffer, len);
349 
350 out:
351 	errno = -err;
352 	return err;
353 }
354 
write_ulong(const char * path,unsigned long result,int base)355 int write_ulong(const char *path, unsigned long result, int base)
356 {
357 	int err;
358 	int len;
359 	char buffer[32];
360 	char *fmt;
361 
362 	switch (base) {
363 	case 10:
364 		fmt = "%lu";
365 		break;
366 	case 16:
367 		fmt = "%lx";
368 		break;
369 	default:
370 		err = -EINVAL;
371 		goto out;
372 	}
373 
374 	len = snprintf(buffer, sizeof(buffer), fmt, result);
375 	if (len < 0 || len >= sizeof(buffer)) {
376 		err = -errno;
377 		goto out;
378 	}
379 
380 	err = write_file(path, buffer, len);
381 
382 out:
383 	errno = -err;
384 	return err;
385 }
386 
find_auxv_entry(int type,char * auxv)387 void *find_auxv_entry(int type, char *auxv)
388 {
389 	ElfW(auxv_t) *p;
390 
391 	p = (ElfW(auxv_t) *)auxv;
392 
393 	while (p->a_type != AT_NULL) {
394 		if (p->a_type == type)
395 			return p;
396 
397 		p++;
398 	}
399 
400 	return NULL;
401 }
402 
get_auxv_entry(int type)403 void *get_auxv_entry(int type)
404 {
405 	ElfW(auxv_t) *p;
406 
407 	if (read_auxv(auxv, sizeof(auxv)))
408 		return NULL;
409 
410 	p = find_auxv_entry(type, auxv);
411 	if (p)
412 		return (void *)p->a_un.a_val;
413 
414 	return NULL;
415 }
416 
pick_online_cpu(void)417 int pick_online_cpu(void)
418 {
419 	int ncpus, cpu = -1;
420 	cpu_set_t *mask;
421 	size_t size;
422 
423 	ncpus = get_nprocs_conf();
424 	size = CPU_ALLOC_SIZE(ncpus);
425 	mask = CPU_ALLOC(ncpus);
426 	if (!mask) {
427 		perror("malloc");
428 		return -1;
429 	}
430 
431 	CPU_ZERO_S(size, mask);
432 
433 	if (sched_getaffinity(0, size, mask)) {
434 		perror("sched_getaffinity");
435 		goto done;
436 	}
437 
438 	/* We prefer a primary thread, but skip 0 */
439 	for (cpu = 8; cpu < ncpus; cpu += 8)
440 		if (CPU_ISSET_S(cpu, size, mask))
441 			goto done;
442 
443 	/* Search for anything, but in reverse */
444 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
445 		if (CPU_ISSET_S(cpu, size, mask))
446 			goto done;
447 
448 	printf("No cpus in affinity mask?!\n");
449 
450 done:
451 	CPU_FREE(mask);
452 	return cpu;
453 }
454 
is_ppc64le(void)455 bool is_ppc64le(void)
456 {
457 	struct utsname uts;
458 	int rc;
459 
460 	errno = 0;
461 	rc = uname(&uts);
462 	if (rc) {
463 		perror("uname");
464 		return false;
465 	}
466 
467 	return strcmp(uts.machine, "ppc64le") == 0;
468 }
469 
read_sysfs_file(char * fpath,char * result,size_t result_size)470 int read_sysfs_file(char *fpath, char *result, size_t result_size)
471 {
472 	char path[PATH_MAX] = "/sys/";
473 
474 	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
475 
476 	return read_file(path, result, result_size, NULL);
477 }
478 
read_debugfs_int(const char * debugfs_file,int * result)479 int read_debugfs_int(const char *debugfs_file, int *result)
480 {
481 	int err;
482 	char value[16] = {0};
483 
484 	err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
485 	if (err)
486 		return err;
487 
488 	return parse_int(value, sizeof(value), result, 10);
489 }
490 
write_debugfs_int(const char * debugfs_file,int result)491 int write_debugfs_int(const char *debugfs_file, int result)
492 {
493 	char value[16];
494 
495 	snprintf(value, 16, "%d", result);
496 
497 	return write_debugfs_file(debugfs_file, value, strlen(value));
498 }
499 
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)500 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
501 		int cpu, int group_fd, unsigned long flags)
502 {
503 	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
504 		      group_fd, flags);
505 }
506 
perf_event_attr_init(struct perf_event_attr * event_attr,unsigned int type,unsigned long config)507 static void perf_event_attr_init(struct perf_event_attr *event_attr,
508 					unsigned int type,
509 					unsigned long config)
510 {
511 	memset(event_attr, 0, sizeof(*event_attr));
512 
513 	event_attr->type = type;
514 	event_attr->size = sizeof(struct perf_event_attr);
515 	event_attr->config = config;
516 	event_attr->read_format = PERF_FORMAT_GROUP;
517 	event_attr->disabled = 1;
518 	event_attr->exclude_kernel = 1;
519 	event_attr->exclude_hv = 1;
520 	event_attr->exclude_guest = 1;
521 }
522 
perf_event_open_counter(unsigned int type,unsigned long config,int group_fd)523 int perf_event_open_counter(unsigned int type,
524 			    unsigned long config, int group_fd)
525 {
526 	int fd;
527 	struct perf_event_attr event_attr;
528 
529 	perf_event_attr_init(&event_attr, type, config);
530 
531 	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
532 
533 	if (fd < 0)
534 		perror("perf_event_open() failed");
535 
536 	return fd;
537 }
538 
perf_event_enable(int fd)539 int perf_event_enable(int fd)
540 {
541 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
542 		perror("error while enabling perf events");
543 		return -1;
544 	}
545 
546 	return 0;
547 }
548 
perf_event_disable(int fd)549 int perf_event_disable(int fd)
550 {
551 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
552 		perror("error disabling perf events");
553 		return -1;
554 	}
555 
556 	return 0;
557 }
558 
perf_event_reset(int fd)559 int perf_event_reset(int fd)
560 {
561 	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
562 		perror("error resetting perf events");
563 		return -1;
564 	}
565 
566 	return 0;
567 }
568 
using_hash_mmu(bool * using_hash)569 int using_hash_mmu(bool *using_hash)
570 {
571 	char line[128];
572 	FILE *f;
573 	int rc;
574 
575 	f = fopen("/proc/cpuinfo", "r");
576 	FAIL_IF(!f);
577 
578 	rc = 0;
579 	while (fgets(line, sizeof(line), f) != NULL) {
580 		if (!strcmp(line, "MMU		: Hash\n") ||
581 		    !strcmp(line, "platform	: Cell\n") ||
582 		    !strcmp(line, "platform	: PowerMac\n")) {
583 			*using_hash = true;
584 			goto out;
585 		}
586 
587 		if (strcmp(line, "MMU		: Radix\n") == 0) {
588 			*using_hash = false;
589 			goto out;
590 		}
591 	}
592 
593 	rc = -1;
594 out:
595 	fclose(f);
596 	return rc;
597 }
598