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
29static char auxv[4096];
30
31int 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
62out:
63 close(fd);
64 errno = -err;
65 return err;
66}
67
68int 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
118out:
119 close(fd);
120 if (err)
121 free(buffer);
122 errno = -err;
123 return err;
124}
125
126int 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
149out:
150 close(fd);
151 errno = -err;
152 return err;
153}
154
155int read_auxv(char *buf, ssize_t buf_size)
156{
157 int err;
158
159 err = read_file(path: "/proc/self/auxv", buf, count: buf_size, NULL);
160 if (err) {
161 perror("Error reading /proc/self/auxv");
162 return err;
163 }
164
165 return 0;
166}
167
168int 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
177int 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
186static 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
207out:
208 errno = -err;
209 return err;
210}
211
212static 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
231out:
232 errno = -err;
233 return err;
234}
235
236static 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
255out:
256 errno = -err;
257 return err;
258}
259
260int 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
265int 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
270int 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
279int 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
288int 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
297int 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
306int read_long(const char *path, long *result, int base)
307{
308 int err;
309 char buffer[32] = {0};
310
311 err = read_file(path, buf: buffer, count: sizeof(buffer) - 1, NULL);
312 if (err)
313 return err;
314
315 return parse_long(buffer, count: sizeof(buffer), result, base);
316}
317
318int 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, buf: buffer, count: sizeof(buffer) - 1, NULL);
324 if (err)
325 return err;
326
327 return parse_ulong(buffer, count: sizeof(buffer), result, base);
328}
329
330int 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, buf: buffer, count: len);
349
350out:
351 errno = -err;
352 return err;
353}
354
355int 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, buf: buffer, count: len);
381
382out:
383 errno = -err;
384 return err;
385}
386
387void *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
403void *get_auxv_entry(int type)
404{
405 ElfW(auxv_t) *p;
406
407 if (read_auxv(buf: auxv, buf_size: 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
417int 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
450done:
451 CPU_FREE(mask);
452 return cpu;
453}
454
455int bind_to_cpu(int cpu)
456{
457 cpu_set_t mask;
458 int err;
459
460 if (cpu == BIND_CPU_ANY) {
461 cpu = pick_online_cpu();
462 if (cpu < 0)
463 return cpu;
464 }
465
466 printf("Binding to cpu %d\n", cpu);
467
468 CPU_ZERO(&mask);
469 CPU_SET(cpu, &mask);
470
471 err = sched_setaffinity(0, sizeof(mask), &mask);
472 if (err)
473 return err;
474
475 return cpu;
476}
477
478bool is_ppc64le(void)
479{
480 struct utsname uts;
481 int rc;
482
483 errno = 0;
484 rc = uname(&uts);
485 if (rc) {
486 perror("uname");
487 return false;
488 }
489
490 return strcmp(uts.machine, "ppc64le") == 0;
491}
492
493int read_sysfs_file(char *fpath, char *result, size_t result_size)
494{
495 char path[PATH_MAX] = "/sys/";
496
497 strncat(path, fpath, PATH_MAX - strlen(path) - 1);
498
499 return read_file(path, buf: result, count: result_size, NULL);
500}
501
502int read_debugfs_int(const char *debugfs_file, int *result)
503{
504 int err;
505 char value[16] = {0};
506
507 err = read_debugfs_file(subpath: debugfs_file, buf: value, count: sizeof(value) - 1);
508 if (err)
509 return err;
510
511 return parse_int(buffer: value, count: sizeof(value), result, base: 10);
512}
513
514int write_debugfs_int(const char *debugfs_file, int result)
515{
516 char value[16];
517
518 snprintf(value, 16, "%d", result);
519
520 return write_debugfs_file(subpath: debugfs_file, buf: value, count: strlen(value));
521}
522
523static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
524 int cpu, int group_fd, unsigned long flags)
525{
526 return syscall(__NR_perf_event_open, hw_event, pid, cpu,
527 group_fd, flags);
528}
529
530static void perf_event_attr_init(struct perf_event_attr *event_attr,
531 unsigned int type,
532 unsigned long config)
533{
534 memset(event_attr, 0, sizeof(*event_attr));
535
536 event_attr->type = type;
537 event_attr->size = sizeof(struct perf_event_attr);
538 event_attr->config = config;
539 event_attr->read_format = PERF_FORMAT_GROUP;
540 event_attr->disabled = 1;
541 event_attr->exclude_kernel = 1;
542 event_attr->exclude_hv = 1;
543 event_attr->exclude_guest = 1;
544}
545
546int perf_event_open_counter(unsigned int type,
547 unsigned long config, int group_fd)
548{
549 int fd;
550 struct perf_event_attr event_attr;
551
552 perf_event_attr_init(event_attr: &event_attr, type, config);
553
554 fd = perf_event_open(hw_event: &event_attr, pid: 0, cpu: -1, group_fd, flags: 0);
555
556 if (fd < 0)
557 perror("perf_event_open() failed");
558
559 return fd;
560}
561
562int perf_event_enable(int fd)
563{
564 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
565 perror("error while enabling perf events");
566 return -1;
567 }
568
569 return 0;
570}
571
572int perf_event_disable(int fd)
573{
574 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
575 perror("error disabling perf events");
576 return -1;
577 }
578
579 return 0;
580}
581
582int perf_event_reset(int fd)
583{
584 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
585 perror("error resetting perf events");
586 return -1;
587 }
588
589 return 0;
590}
591
592int using_hash_mmu(bool *using_hash)
593{
594 char line[128];
595 FILE *f;
596 int rc;
597
598 f = fopen("/proc/cpuinfo", "r");
599 FAIL_IF(!f);
600
601 rc = 0;
602 while (fgets(line, sizeof(line), f) != NULL) {
603 if (!strcmp(line, "MMU : Hash\n") ||
604 !strcmp(line, "platform : Cell\n") ||
605 !strcmp(line, "platform : PowerMac\n")) {
606 *using_hash = true;
607 goto out;
608 }
609
610 if (strcmp(line, "MMU : Radix\n") == 0) {
611 *using_hash = false;
612 goto out;
613 }
614 }
615
616 rc = -1;
617out:
618 fclose(f);
619 return rc;
620}
621
622struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *))
623{
624 struct sigaction sa;
625 struct sigaction old_handler;
626
627 sa.sa_sigaction = fn;
628 sigemptyset(&sa.sa_mask);
629 sa.sa_flags = SA_SIGINFO;
630 FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler),
631 "failed to push signal handler");
632
633 return old_handler;
634}
635
636struct sigaction pop_signal_handler(int sig, struct sigaction old_handler)
637{
638 struct sigaction popped;
639
640 FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped),
641 "failed to pop signal handler");
642
643 return popped;
644}
645

source code of linux/tools/testing/selftests/powerpc/utils.c