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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 455 int 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 478 bool 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 493 int 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 502 int 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 514 int 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 523 static 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 530 static 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 546 int 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 562 int 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 572 int 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 582 int 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 592 int 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; 617 out: 618 fclose(f); 619 return rc; 620 } 621