1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2013-2015, Michael Ellerman, IBM Corp.
6 #define _GNU_SOURCE /* For CPU_ZERO etc. */
18 #include <sys/ioctl.h>
20 #include <sys/sysinfo.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
24 #include <asm/unistd.h>
25 #include <linux/limits.h>
29 static char auxv
[4096];
31 int read_file(const char *path
, char *buf
, size_t count
, size_t *len
)
38 fd
= open(path
, O_RDONLY
);
42 rc
= read(fd
, buf
, count
);
51 /* Overflow if there are still more bytes after filling the buffer */
53 rc
= read(fd
, &eof
, 1);
68 int read_file_alloc(const char *path
, char **buf
, size_t *len
)
70 size_t read_offset
= 0;
71 size_t buffer_len
= 0;
76 fd
= open(path
, O_RDONLY
);
81 * We don't use stat & preallocate st_size because some non-files
82 * report 0 file size. Instead just dynamically grow the buffer
88 if (read_offset
>= buffer_len
/ 2) {
91 buffer_len
= buffer_len
? buffer_len
* 2 : 4096;
92 next_buffer
= realloc(buffer
, buffer_len
);
100 rc
= read(fd
, buffer
+ read_offset
, buffer_len
- read_offset
);
126 int write_file(const char *path
, const char *buf
, size_t count
)
132 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
136 rc
= write(fd
, buf
, count
);
155 int read_auxv(char *buf
, ssize_t buf_size
)
159 err
= read_file("/proc/self/auxv", buf
, buf_size
, NULL
);
161 perror("Error reading /proc/self/auxv");
168 int read_debugfs_file(const char *subpath
, char *buf
, size_t count
)
170 char path
[PATH_MAX
] = "/sys/kernel/debug/";
172 strncat(path
, subpath
, sizeof(path
) - strlen(path
) - 1);
174 return read_file(path
, buf
, count
, NULL
);
177 int write_debugfs_file(const char *subpath
, const char *buf
, size_t count
)
179 char path
[PATH_MAX
] = "/sys/kernel/debug/";
181 strncat(path
, subpath
, sizeof(path
) - strlen(path
) - 1);
183 return write_file(path
, buf
, count
);
186 static int validate_int_parse(const char *buffer
, size_t count
, char *end
)
190 /* Require at least one digit */
196 /* Require all remaining characters be whitespace-ish */
197 for (; end
< buffer
+ count
; end
++) {
201 if (*end
!= ' ' && *end
!= '\n') {
212 static int parse_bounded_int(const char *buffer
, size_t count
, intmax_t *result
,
213 int base
, intmax_t min
, intmax_t max
)
219 *result
= strtoimax(buffer
, &end
, base
);
224 err
= validate_int_parse(buffer
, count
, end
);
228 if (*result
< min
|| *result
> max
)
236 static int parse_bounded_uint(const char *buffer
, size_t count
, uintmax_t *result
,
237 int base
, uintmax_t max
)
243 *result
= strtoumax(buffer
, &end
, base
);
248 err
= validate_int_parse(buffer
, count
, end
);
260 int parse_intmax(const char *buffer
, size_t count
, intmax_t *result
, int base
)
262 return parse_bounded_int(buffer
, count
, result
, base
, INTMAX_MIN
, INTMAX_MAX
);
265 int parse_uintmax(const char *buffer
, size_t count
, uintmax_t *result
, int base
)
267 return parse_bounded_uint(buffer
, count
, result
, base
, UINTMAX_MAX
);
270 int parse_int(const char *buffer
, size_t count
, int *result
, int base
)
273 int err
= parse_bounded_int(buffer
, count
, &parsed
, base
, INT_MIN
, INT_MAX
);
279 int parse_uint(const char *buffer
, size_t count
, unsigned int *result
, int base
)
282 int err
= parse_bounded_uint(buffer
, count
, &parsed
, base
, UINT_MAX
);
288 int parse_long(const char *buffer
, size_t count
, long *result
, int base
)
291 int err
= parse_bounded_int(buffer
, count
, &parsed
, base
, LONG_MIN
, LONG_MAX
);
297 int parse_ulong(const char *buffer
, size_t count
, unsigned long *result
, int base
)
300 int err
= parse_bounded_uint(buffer
, count
, &parsed
, base
, ULONG_MAX
);
306 int read_long(const char *path
, long *result
, int base
)
309 char buffer
[32] = {0};
311 err
= read_file(path
, buffer
, sizeof(buffer
) - 1, NULL
);
315 return parse_long(buffer
, sizeof(buffer
), result
, base
);
318 int read_ulong(const char *path
, unsigned long *result
, int base
)
321 char buffer
[32] = {0};
323 err
= read_file(path
, buffer
, sizeof(buffer
) - 1, NULL
);
327 return parse_ulong(buffer
, sizeof(buffer
), result
, base
);
330 int write_long(const char *path
, long result
, int base
)
336 /* Decimal only for now: no format specifier for signed hex values */
342 len
= snprintf(buffer
, sizeof(buffer
), "%ld", result
);
343 if (len
< 0 || len
>= sizeof(buffer
)) {
348 err
= write_file(path
, buffer
, len
);
355 int write_ulong(const char *path
, unsigned long result
, int base
)
374 len
= snprintf(buffer
, sizeof(buffer
), fmt
, result
);
375 if (len
< 0 || len
>= sizeof(buffer
)) {
380 err
= write_file(path
, buffer
, len
);
387 void *find_auxv_entry(int type
, char *auxv
)
391 p
= (ElfW(auxv_t
) *)auxv
;
393 while (p
->a_type
!= AT_NULL
) {
394 if (p
->a_type
== type
)
403 void *get_auxv_entry(int type
)
407 if (read_auxv(auxv
, sizeof(auxv
)))
410 p
= find_auxv_entry(type
, auxv
);
412 return (void *)p
->a_un
.a_val
;
417 int pick_online_cpu(void)
423 ncpus
= get_nprocs_conf();
424 size
= CPU_ALLOC_SIZE(ncpus
);
425 mask
= CPU_ALLOC(ncpus
);
431 CPU_ZERO_S(size
, mask
);
433 if (sched_getaffinity(0, size
, mask
)) {
434 perror("sched_getaffinity");
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
))
443 /* Search for anything, but in reverse */
444 for (cpu
= ncpus
- 1; cpu
>= 0; cpu
--)
445 if (CPU_ISSET_S(cpu
, size
, mask
))
448 printf("No cpus in affinity mask?!\n");
455 int bind_to_cpu(int cpu
)
460 if (cpu
== BIND_CPU_ANY
) {
461 cpu
= pick_online_cpu();
466 printf("Binding to cpu %d\n", cpu
);
471 err
= sched_setaffinity(0, sizeof(mask
), &mask
);
478 bool is_ppc64le(void)
490 return strcmp(uts
.machine
, "ppc64le") == 0;
493 int read_sysfs_file(char *fpath
, char *result
, size_t result_size
)
495 char path
[PATH_MAX
] = "/sys/";
497 strncat(path
, fpath
, PATH_MAX
- strlen(path
) - 1);
499 return read_file(path
, result
, result_size
, NULL
);
502 int read_debugfs_int(const char *debugfs_file
, int *result
)
505 char value
[16] = {0};
507 err
= read_debugfs_file(debugfs_file
, value
, sizeof(value
) - 1);
511 return parse_int(value
, sizeof(value
), result
, 10);
514 int write_debugfs_int(const char *debugfs_file
, int result
)
518 snprintf(value
, 16, "%d", result
);
520 return write_debugfs_file(debugfs_file
, value
, strlen(value
));
523 static long perf_event_open(struct perf_event_attr
*hw_event
, pid_t pid
,
524 int cpu
, int group_fd
, unsigned long flags
)
526 return syscall(__NR_perf_event_open
, hw_event
, pid
, cpu
,
530 static void perf_event_attr_init(struct perf_event_attr
*event_attr
,
532 unsigned long config
)
534 memset(event_attr
, 0, sizeof(*event_attr
));
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;
546 int perf_event_open_counter(unsigned int type
,
547 unsigned long config
, int group_fd
)
550 struct perf_event_attr event_attr
;
552 perf_event_attr_init(&event_attr
, type
, config
);
554 fd
= perf_event_open(&event_attr
, 0, -1, group_fd
, 0);
557 perror("perf_event_open() failed");
562 int perf_event_enable(int fd
)
564 if (ioctl(fd
, PERF_EVENT_IOC_ENABLE
, PERF_IOC_FLAG_GROUP
) == -1) {
565 perror("error while enabling perf events");
572 int perf_event_disable(int fd
)
574 if (ioctl(fd
, PERF_EVENT_IOC_DISABLE
, PERF_IOC_FLAG_GROUP
) == -1) {
575 perror("error disabling perf events");
582 int perf_event_reset(int fd
)
584 if (ioctl(fd
, PERF_EVENT_IOC_RESET
, PERF_IOC_FLAG_GROUP
) == -1) {
585 perror("error resetting perf events");
592 int using_hash_mmu(bool *using_hash
)
598 f
= fopen("/proc/cpuinfo", "r");
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")) {
610 if (strcmp(line
, "MMU : Radix\n") == 0) {
622 struct sigaction
push_signal_handler(int sig
, void (*fn
)(int, siginfo_t
*, void *))
625 struct sigaction old_handler
;
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");
636 struct sigaction
pop_signal_handler(int sig
, struct sigaction old_handler
)
638 struct sigaction popped
;
640 FAIL_IF_EXIT_MSG(sigaction(sig
, &old_handler
, &popped
),
641 "failed to pop signal handler");