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("/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 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, buffer, sizeof(buffer) - 1, NULL); 312 if (err) 313 return err; 314 315 return parse_long(buffer, 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, buffer, sizeof(buffer) - 1, NULL); 324 if (err) 325 return err; 326 327 return parse_ulong(buffer, 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, buffer, 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, buffer, 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(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 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, result, 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(debugfs_file, value, sizeof(value) - 1); 508 if (err) 509 return err; 510 511 return parse_int(value, sizeof(value), result, 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(debugfs_file, value, 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, type, config); 553 554 fd = perf_event_open(&event_attr, 0, -1, group_fd, 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