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 459 printf("Binding to cpu %d\n", cpu); 460 461 CPU_ZERO(&mask); 462 CPU_SET(cpu, &mask); 463 464 return sched_setaffinity(0, sizeof(mask), &mask); 465 } 466 467 bool is_ppc64le(void) 468 { 469 struct utsname uts; 470 int rc; 471 472 errno = 0; 473 rc = uname(&uts); 474 if (rc) { 475 perror("uname"); 476 return false; 477 } 478 479 return strcmp(uts.machine, "ppc64le") == 0; 480 } 481 482 int read_sysfs_file(char *fpath, char *result, size_t result_size) 483 { 484 char path[PATH_MAX] = "/sys/"; 485 486 strncat(path, fpath, PATH_MAX - strlen(path) - 1); 487 488 return read_file(path, result, result_size, NULL); 489 } 490 491 int read_debugfs_int(const char *debugfs_file, int *result) 492 { 493 int err; 494 char value[16] = {0}; 495 496 err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); 497 if (err) 498 return err; 499 500 return parse_int(value, sizeof(value), result, 10); 501 } 502 503 int write_debugfs_int(const char *debugfs_file, int result) 504 { 505 char value[16]; 506 507 snprintf(value, 16, "%d", result); 508 509 return write_debugfs_file(debugfs_file, value, strlen(value)); 510 } 511 512 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 513 int cpu, int group_fd, unsigned long flags) 514 { 515 return syscall(__NR_perf_event_open, hw_event, pid, cpu, 516 group_fd, flags); 517 } 518 519 static void perf_event_attr_init(struct perf_event_attr *event_attr, 520 unsigned int type, 521 unsigned long config) 522 { 523 memset(event_attr, 0, sizeof(*event_attr)); 524 525 event_attr->type = type; 526 event_attr->size = sizeof(struct perf_event_attr); 527 event_attr->config = config; 528 event_attr->read_format = PERF_FORMAT_GROUP; 529 event_attr->disabled = 1; 530 event_attr->exclude_kernel = 1; 531 event_attr->exclude_hv = 1; 532 event_attr->exclude_guest = 1; 533 } 534 535 int perf_event_open_counter(unsigned int type, 536 unsigned long config, int group_fd) 537 { 538 int fd; 539 struct perf_event_attr event_attr; 540 541 perf_event_attr_init(&event_attr, type, config); 542 543 fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); 544 545 if (fd < 0) 546 perror("perf_event_open() failed"); 547 548 return fd; 549 } 550 551 int perf_event_enable(int fd) 552 { 553 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { 554 perror("error while enabling perf events"); 555 return -1; 556 } 557 558 return 0; 559 } 560 561 int perf_event_disable(int fd) 562 { 563 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { 564 perror("error disabling perf events"); 565 return -1; 566 } 567 568 return 0; 569 } 570 571 int perf_event_reset(int fd) 572 { 573 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { 574 perror("error resetting perf events"); 575 return -1; 576 } 577 578 return 0; 579 } 580 581 int using_hash_mmu(bool *using_hash) 582 { 583 char line[128]; 584 FILE *f; 585 int rc; 586 587 f = fopen("/proc/cpuinfo", "r"); 588 FAIL_IF(!f); 589 590 rc = 0; 591 while (fgets(line, sizeof(line), f) != NULL) { 592 if (!strcmp(line, "MMU : Hash\n") || 593 !strcmp(line, "platform : Cell\n") || 594 !strcmp(line, "platform : PowerMac\n")) { 595 *using_hash = true; 596 goto out; 597 } 598 599 if (strcmp(line, "MMU : Radix\n") == 0) { 600 *using_hash = false; 601 goto out; 602 } 603 } 604 605 rc = -1; 606 out: 607 fclose(f); 608 return rc; 609 } 610