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 write_file(const char *path, const char *buf, size_t count) 69 { 70 int fd; 71 int err; 72 ssize_t rc; 73 74 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); 75 if (fd < 0) 76 return -errno; 77 78 rc = write(fd, buf, count); 79 if (rc < 0) { 80 err = -errno; 81 goto out; 82 } 83 84 if (rc != count) { 85 err = -EOVERFLOW; 86 goto out; 87 } 88 89 err = 0; 90 91 out: 92 close(fd); 93 errno = -err; 94 return err; 95 } 96 97 int read_auxv(char *buf, ssize_t buf_size) 98 { 99 int err; 100 101 err = read_file("/proc/self/auxv", buf, buf_size, NULL); 102 if (err) { 103 perror("Error reading /proc/self/auxv"); 104 return err; 105 } 106 107 return 0; 108 } 109 110 int read_debugfs_file(const char *subpath, char *buf, size_t count) 111 { 112 char path[PATH_MAX] = "/sys/kernel/debug/"; 113 114 strncat(path, subpath, sizeof(path) - strlen(path) - 1); 115 116 return read_file(path, buf, count, NULL); 117 } 118 119 int write_debugfs_file(const char *subpath, const char *buf, size_t count) 120 { 121 char path[PATH_MAX] = "/sys/kernel/debug/"; 122 123 strncat(path, subpath, sizeof(path) - strlen(path) - 1); 124 125 return write_file(path, buf, count); 126 } 127 128 static int validate_int_parse(const char *buffer, size_t count, char *end) 129 { 130 int err = 0; 131 132 /* Require at least one digit */ 133 if (end == buffer) { 134 err = -EINVAL; 135 goto out; 136 } 137 138 /* Require all remaining characters be whitespace-ish */ 139 for (; end < buffer + count; end++) { 140 if (*end == '\0') 141 break; 142 143 if (*end != ' ' && *end != '\n') { 144 err = -EINVAL; 145 goto out; 146 } 147 } 148 149 out: 150 errno = -err; 151 return err; 152 } 153 154 static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result, 155 int base, intmax_t min, intmax_t max) 156 { 157 int err; 158 char *end; 159 160 errno = 0; 161 *result = strtoimax(buffer, &end, base); 162 163 if (errno) 164 return -errno; 165 166 err = validate_int_parse(buffer, count, end); 167 if (err) 168 goto out; 169 170 if (*result < min || *result > max) 171 err = -EOVERFLOW; 172 173 out: 174 errno = -err; 175 return err; 176 } 177 178 static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result, 179 int base, uintmax_t max) 180 { 181 int err = 0; 182 char *end; 183 184 errno = 0; 185 *result = strtoumax(buffer, &end, base); 186 187 if (errno) 188 return -errno; 189 190 err = validate_int_parse(buffer, count, end); 191 if (err) 192 goto out; 193 194 if (*result > max) 195 err = -EOVERFLOW; 196 197 out: 198 errno = -err; 199 return err; 200 } 201 202 int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base) 203 { 204 return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX); 205 } 206 207 int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base) 208 { 209 return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX); 210 } 211 212 int parse_int(const char *buffer, size_t count, int *result, int base) 213 { 214 intmax_t parsed; 215 int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX); 216 217 *result = parsed; 218 return err; 219 } 220 221 int parse_uint(const char *buffer, size_t count, unsigned int *result, int base) 222 { 223 uintmax_t parsed; 224 int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX); 225 226 *result = parsed; 227 return err; 228 } 229 230 int parse_long(const char *buffer, size_t count, long *result, int base) 231 { 232 intmax_t parsed; 233 int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX); 234 235 *result = parsed; 236 return err; 237 } 238 239 int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base) 240 { 241 uintmax_t parsed; 242 int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX); 243 244 *result = parsed; 245 return err; 246 } 247 248 int read_long(const char *path, long *result, int base) 249 { 250 int err; 251 char buffer[32] = {0}; 252 253 err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 254 if (err) 255 return err; 256 257 return parse_long(buffer, sizeof(buffer), result, base); 258 } 259 260 int read_ulong(const char *path, unsigned long *result, int base) 261 { 262 int err; 263 char buffer[32] = {0}; 264 265 err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 266 if (err) 267 return err; 268 269 return parse_ulong(buffer, sizeof(buffer), result, base); 270 } 271 272 int write_long(const char *path, long result, int base) 273 { 274 int err; 275 int len; 276 char buffer[32]; 277 278 /* Decimal only for now: no format specifier for signed hex values */ 279 if (base != 10) { 280 err = -EINVAL; 281 goto out; 282 } 283 284 len = snprintf(buffer, sizeof(buffer), "%ld", result); 285 if (len < 0 || len >= sizeof(buffer)) { 286 err = -EOVERFLOW; 287 goto out; 288 } 289 290 err = write_file(path, buffer, len); 291 292 out: 293 errno = -err; 294 return err; 295 } 296 297 int write_ulong(const char *path, unsigned long result, int base) 298 { 299 int err; 300 int len; 301 char buffer[32]; 302 char *fmt; 303 304 switch (base) { 305 case 10: 306 fmt = "%lu"; 307 break; 308 case 16: 309 fmt = "%lx"; 310 break; 311 default: 312 err = -EINVAL; 313 goto out; 314 } 315 316 len = snprintf(buffer, sizeof(buffer), fmt, result); 317 if (len < 0 || len >= sizeof(buffer)) { 318 err = -errno; 319 goto out; 320 } 321 322 err = write_file(path, buffer, len); 323 324 out: 325 errno = -err; 326 return err; 327 } 328 329 void *find_auxv_entry(int type, char *auxv) 330 { 331 ElfW(auxv_t) *p; 332 333 p = (ElfW(auxv_t) *)auxv; 334 335 while (p->a_type != AT_NULL) { 336 if (p->a_type == type) 337 return p; 338 339 p++; 340 } 341 342 return NULL; 343 } 344 345 void *get_auxv_entry(int type) 346 { 347 ElfW(auxv_t) *p; 348 349 if (read_auxv(auxv, sizeof(auxv))) 350 return NULL; 351 352 p = find_auxv_entry(type, auxv); 353 if (p) 354 return (void *)p->a_un.a_val; 355 356 return NULL; 357 } 358 359 int pick_online_cpu(void) 360 { 361 int ncpus, cpu = -1; 362 cpu_set_t *mask; 363 size_t size; 364 365 ncpus = get_nprocs_conf(); 366 size = CPU_ALLOC_SIZE(ncpus); 367 mask = CPU_ALLOC(ncpus); 368 if (!mask) { 369 perror("malloc"); 370 return -1; 371 } 372 373 CPU_ZERO_S(size, mask); 374 375 if (sched_getaffinity(0, size, mask)) { 376 perror("sched_getaffinity"); 377 goto done; 378 } 379 380 /* We prefer a primary thread, but skip 0 */ 381 for (cpu = 8; cpu < ncpus; cpu += 8) 382 if (CPU_ISSET_S(cpu, size, mask)) 383 goto done; 384 385 /* Search for anything, but in reverse */ 386 for (cpu = ncpus - 1; cpu >= 0; cpu--) 387 if (CPU_ISSET_S(cpu, size, mask)) 388 goto done; 389 390 printf("No cpus in affinity mask?!\n"); 391 392 done: 393 CPU_FREE(mask); 394 return cpu; 395 } 396 397 bool is_ppc64le(void) 398 { 399 struct utsname uts; 400 int rc; 401 402 errno = 0; 403 rc = uname(&uts); 404 if (rc) { 405 perror("uname"); 406 return false; 407 } 408 409 return strcmp(uts.machine, "ppc64le") == 0; 410 } 411 412 int read_sysfs_file(char *fpath, char *result, size_t result_size) 413 { 414 char path[PATH_MAX] = "/sys/"; 415 416 strncat(path, fpath, PATH_MAX - strlen(path) - 1); 417 418 return read_file(path, result, result_size, NULL); 419 } 420 421 int read_debugfs_int(const char *debugfs_file, int *result) 422 { 423 int err; 424 char value[16] = {0}; 425 426 err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); 427 if (err) 428 return err; 429 430 return parse_int(value, sizeof(value), result, 10); 431 } 432 433 int write_debugfs_int(const char *debugfs_file, int result) 434 { 435 char value[16]; 436 437 snprintf(value, 16, "%d", result); 438 439 return write_debugfs_file(debugfs_file, value, strlen(value)); 440 } 441 442 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 443 int cpu, int group_fd, unsigned long flags) 444 { 445 return syscall(__NR_perf_event_open, hw_event, pid, cpu, 446 group_fd, flags); 447 } 448 449 static void perf_event_attr_init(struct perf_event_attr *event_attr, 450 unsigned int type, 451 unsigned long config) 452 { 453 memset(event_attr, 0, sizeof(*event_attr)); 454 455 event_attr->type = type; 456 event_attr->size = sizeof(struct perf_event_attr); 457 event_attr->config = config; 458 event_attr->read_format = PERF_FORMAT_GROUP; 459 event_attr->disabled = 1; 460 event_attr->exclude_kernel = 1; 461 event_attr->exclude_hv = 1; 462 event_attr->exclude_guest = 1; 463 } 464 465 int perf_event_open_counter(unsigned int type, 466 unsigned long config, int group_fd) 467 { 468 int fd; 469 struct perf_event_attr event_attr; 470 471 perf_event_attr_init(&event_attr, type, config); 472 473 fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); 474 475 if (fd < 0) 476 perror("perf_event_open() failed"); 477 478 return fd; 479 } 480 481 int perf_event_enable(int fd) 482 { 483 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { 484 perror("error while enabling perf events"); 485 return -1; 486 } 487 488 return 0; 489 } 490 491 int perf_event_disable(int fd) 492 { 493 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { 494 perror("error disabling perf events"); 495 return -1; 496 } 497 498 return 0; 499 } 500 501 int perf_event_reset(int fd) 502 { 503 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { 504 perror("error resetting perf events"); 505 return -1; 506 } 507 508 return 0; 509 } 510 511 int using_hash_mmu(bool *using_hash) 512 { 513 char line[128]; 514 FILE *f; 515 int rc; 516 517 f = fopen("/proc/cpuinfo", "r"); 518 FAIL_IF(!f); 519 520 rc = 0; 521 while (fgets(line, sizeof(line), f) != NULL) { 522 if (!strcmp(line, "MMU : Hash\n") || 523 !strcmp(line, "platform : Cell\n") || 524 !strcmp(line, "platform : PowerMac\n")) { 525 *using_hash = true; 526 goto out; 527 } 528 529 if (strcmp(line, "MMU : Radix\n") == 0) { 530 *using_hash = false; 531 goto out; 532 } 533 } 534 535 rc = -1; 536 out: 537 fclose(f); 538 return rc; 539 } 540