1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2fcb45ec0SMichael Ellerman /* 3fcb45ec0SMichael Ellerman * Copyright 2013-2015, Michael Ellerman, IBM Corp. 4fcb45ec0SMichael Ellerman */ 5fcb45ec0SMichael Ellerman 6d1301afdSMichael Ellerman #define _GNU_SOURCE /* For CPU_ZERO etc. */ 7d1301afdSMichael Ellerman 8fcb45ec0SMichael Ellerman #include <elf.h> 9fcb45ec0SMichael Ellerman #include <errno.h> 10fcb45ec0SMichael Ellerman #include <fcntl.h> 11d1bc05b7SBenjamin Gray #include <inttypes.h> 12d1bc05b7SBenjamin Gray #include <limits.h> 13fcb45ec0SMichael Ellerman #include <link.h> 14d1301afdSMichael Ellerman #include <sched.h> 15fcb45ec0SMichael Ellerman #include <stdio.h> 16d2bf7932SNaveen N. Rao #include <stdlib.h> 1795f9b3afSMichael Ellerman #include <string.h> 18d2bf7932SNaveen N. Rao #include <sys/ioctl.h> 19fcb45ec0SMichael Ellerman #include <sys/stat.h> 20dfa03fffSSandipan Das #include <sys/sysinfo.h> 21fcb45ec0SMichael Ellerman #include <sys/types.h> 2295f9b3afSMichael Ellerman #include <sys/utsname.h> 23fcb45ec0SMichael Ellerman #include <unistd.h> 24d2bf7932SNaveen N. Rao #include <asm/unistd.h> 25d2bf7932SNaveen N. Rao #include <linux/limits.h> 26fcb45ec0SMichael Ellerman 27fcb45ec0SMichael Ellerman #include "utils.h" 28fcb45ec0SMichael Ellerman 29fcb45ec0SMichael Ellerman static char auxv[4096]; 30fcb45ec0SMichael Ellerman 31a974f0c1SBenjamin Gray int read_file(const char *path, char *buf, size_t count, size_t *len) 32fcb45ec0SMichael Ellerman { 33a974f0c1SBenjamin Gray ssize_t rc; 34a974f0c1SBenjamin Gray int fd; 35a974f0c1SBenjamin Gray int err; 36a974f0c1SBenjamin Gray char eof; 37fcb45ec0SMichael Ellerman 38a974f0c1SBenjamin Gray fd = open(path, O_RDONLY); 39a974f0c1SBenjamin Gray if (fd < 0) 40e3028437SMichael Ellerman return -errno; 41fcb45ec0SMichael Ellerman 42a974f0c1SBenjamin Gray rc = read(fd, buf, count); 43a974f0c1SBenjamin Gray if (rc < 0) { 44a974f0c1SBenjamin Gray err = -errno; 45fcb45ec0SMichael Ellerman goto out; 46fcb45ec0SMichael Ellerman } 47fcb45ec0SMichael Ellerman 48a974f0c1SBenjamin Gray if (len) 49a974f0c1SBenjamin Gray *len = rc; 50a974f0c1SBenjamin Gray 51a974f0c1SBenjamin Gray /* Overflow if there are still more bytes after filling the buffer */ 52a974f0c1SBenjamin Gray if (rc == count) { 53a974f0c1SBenjamin Gray rc = read(fd, &eof, 1); 54a974f0c1SBenjamin Gray if (rc != 0) { 55a974f0c1SBenjamin Gray err = -EOVERFLOW; 56fcb45ec0SMichael Ellerman goto out; 57fcb45ec0SMichael Ellerman } 58a974f0c1SBenjamin Gray } 59fcb45ec0SMichael Ellerman 60a974f0c1SBenjamin Gray err = 0; 61a974f0c1SBenjamin Gray 62e3028437SMichael Ellerman out: 63e3028437SMichael Ellerman close(fd); 64a974f0c1SBenjamin Gray errno = -err; 65a974f0c1SBenjamin Gray return err; 66a974f0c1SBenjamin Gray } 67a974f0c1SBenjamin Gray 688d7253dcSBenjamin Gray int read_file_alloc(const char *path, char **buf, size_t *len) 698d7253dcSBenjamin Gray { 708d7253dcSBenjamin Gray size_t read_offset = 0; 718d7253dcSBenjamin Gray size_t buffer_len = 0; 728d7253dcSBenjamin Gray char *buffer = NULL; 738d7253dcSBenjamin Gray int err; 748d7253dcSBenjamin Gray int fd; 758d7253dcSBenjamin Gray 768d7253dcSBenjamin Gray fd = open(path, O_RDONLY); 778d7253dcSBenjamin Gray if (fd < 0) 788d7253dcSBenjamin Gray return -errno; 798d7253dcSBenjamin Gray 808d7253dcSBenjamin Gray /* 818d7253dcSBenjamin Gray * We don't use stat & preallocate st_size because some non-files 828d7253dcSBenjamin Gray * report 0 file size. Instead just dynamically grow the buffer 838d7253dcSBenjamin Gray * as needed. 848d7253dcSBenjamin Gray */ 858d7253dcSBenjamin Gray while (1) { 868d7253dcSBenjamin Gray ssize_t rc; 878d7253dcSBenjamin Gray 888d7253dcSBenjamin Gray if (read_offset >= buffer_len / 2) { 898d7253dcSBenjamin Gray char *next_buffer; 908d7253dcSBenjamin Gray 918d7253dcSBenjamin Gray buffer_len = buffer_len ? buffer_len * 2 : 4096; 928d7253dcSBenjamin Gray next_buffer = realloc(buffer, buffer_len); 938d7253dcSBenjamin Gray if (!next_buffer) { 948d7253dcSBenjamin Gray err = -errno; 958d7253dcSBenjamin Gray goto out; 968d7253dcSBenjamin Gray } 978d7253dcSBenjamin Gray buffer = next_buffer; 988d7253dcSBenjamin Gray } 998d7253dcSBenjamin Gray 1008d7253dcSBenjamin Gray rc = read(fd, buffer + read_offset, buffer_len - read_offset); 1018d7253dcSBenjamin Gray if (rc < 0) { 1028d7253dcSBenjamin Gray err = -errno; 1038d7253dcSBenjamin Gray goto out; 1048d7253dcSBenjamin Gray } 1058d7253dcSBenjamin Gray 1068d7253dcSBenjamin Gray if (rc == 0) 1078d7253dcSBenjamin Gray break; 1088d7253dcSBenjamin Gray 1098d7253dcSBenjamin Gray read_offset += rc; 1108d7253dcSBenjamin Gray } 1118d7253dcSBenjamin Gray 1128d7253dcSBenjamin Gray *buf = buffer; 1138d7253dcSBenjamin Gray if (len) 1148d7253dcSBenjamin Gray *len = read_offset; 1158d7253dcSBenjamin Gray 1168d7253dcSBenjamin Gray err = 0; 1178d7253dcSBenjamin Gray 1188d7253dcSBenjamin Gray out: 1198d7253dcSBenjamin Gray close(fd); 1208d7253dcSBenjamin Gray if (err) 1218d7253dcSBenjamin Gray free(buffer); 1228d7253dcSBenjamin Gray errno = -err; 1238d7253dcSBenjamin Gray return err; 1248d7253dcSBenjamin Gray } 1258d7253dcSBenjamin Gray 126a974f0c1SBenjamin Gray int write_file(const char *path, const char *buf, size_t count) 127a974f0c1SBenjamin Gray { 128a974f0c1SBenjamin Gray int fd; 129a974f0c1SBenjamin Gray int err; 130a974f0c1SBenjamin Gray ssize_t rc; 131a974f0c1SBenjamin Gray 132a974f0c1SBenjamin Gray fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); 133a974f0c1SBenjamin Gray if (fd < 0) 134a974f0c1SBenjamin Gray return -errno; 135a974f0c1SBenjamin Gray 136a974f0c1SBenjamin Gray rc = write(fd, buf, count); 137a974f0c1SBenjamin Gray if (rc < 0) { 138a974f0c1SBenjamin Gray err = -errno; 139a974f0c1SBenjamin Gray goto out; 140a974f0c1SBenjamin Gray } 141a974f0c1SBenjamin Gray 142a974f0c1SBenjamin Gray if (rc != count) { 143a974f0c1SBenjamin Gray err = -EOVERFLOW; 144a974f0c1SBenjamin Gray goto out; 145a974f0c1SBenjamin Gray } 146a974f0c1SBenjamin Gray 147a974f0c1SBenjamin Gray err = 0; 148a974f0c1SBenjamin Gray 149a974f0c1SBenjamin Gray out: 150a974f0c1SBenjamin Gray close(fd); 151a974f0c1SBenjamin Gray errno = -err; 152a974f0c1SBenjamin Gray return err; 153a974f0c1SBenjamin Gray } 154a974f0c1SBenjamin Gray 155a974f0c1SBenjamin Gray int read_auxv(char *buf, ssize_t buf_size) 156a974f0c1SBenjamin Gray { 157a974f0c1SBenjamin Gray int err; 158a974f0c1SBenjamin Gray 159a974f0c1SBenjamin Gray err = read_file("/proc/self/auxv", buf, buf_size, NULL); 160a974f0c1SBenjamin Gray if (err) { 161a974f0c1SBenjamin Gray perror("Error reading /proc/self/auxv"); 162a974f0c1SBenjamin Gray return err; 163a974f0c1SBenjamin Gray } 164a974f0c1SBenjamin Gray 165a974f0c1SBenjamin Gray return 0; 166e3028437SMichael Ellerman } 167e3028437SMichael Ellerman 168121d340bSBenjamin Gray int read_debugfs_file(const char *subpath, char *buf, size_t count) 169121d340bSBenjamin Gray { 170121d340bSBenjamin Gray char path[PATH_MAX] = "/sys/kernel/debug/"; 171121d340bSBenjamin Gray 172121d340bSBenjamin Gray strncat(path, subpath, sizeof(path) - strlen(path) - 1); 173121d340bSBenjamin Gray 174121d340bSBenjamin Gray return read_file(path, buf, count, NULL); 175121d340bSBenjamin Gray } 176121d340bSBenjamin Gray 177121d340bSBenjamin Gray int write_debugfs_file(const char *subpath, const char *buf, size_t count) 178121d340bSBenjamin Gray { 179121d340bSBenjamin Gray char path[PATH_MAX] = "/sys/kernel/debug/"; 180121d340bSBenjamin Gray 181121d340bSBenjamin Gray strncat(path, subpath, sizeof(path) - strlen(path) - 1); 182121d340bSBenjamin Gray 183121d340bSBenjamin Gray return write_file(path, buf, count); 184121d340bSBenjamin Gray } 185121d340bSBenjamin Gray 186d1bc05b7SBenjamin Gray static int validate_int_parse(const char *buffer, size_t count, char *end) 187d1bc05b7SBenjamin Gray { 188d1bc05b7SBenjamin Gray int err = 0; 189d1bc05b7SBenjamin Gray 190d1bc05b7SBenjamin Gray /* Require at least one digit */ 191d1bc05b7SBenjamin Gray if (end == buffer) { 192d1bc05b7SBenjamin Gray err = -EINVAL; 193d1bc05b7SBenjamin Gray goto out; 194d1bc05b7SBenjamin Gray } 195d1bc05b7SBenjamin Gray 196d1bc05b7SBenjamin Gray /* Require all remaining characters be whitespace-ish */ 197d1bc05b7SBenjamin Gray for (; end < buffer + count; end++) { 198d1bc05b7SBenjamin Gray if (*end == '\0') 199d1bc05b7SBenjamin Gray break; 200d1bc05b7SBenjamin Gray 201d1bc05b7SBenjamin Gray if (*end != ' ' && *end != '\n') { 202d1bc05b7SBenjamin Gray err = -EINVAL; 203d1bc05b7SBenjamin Gray goto out; 204d1bc05b7SBenjamin Gray } 205d1bc05b7SBenjamin Gray } 206d1bc05b7SBenjamin Gray 207d1bc05b7SBenjamin Gray out: 208d1bc05b7SBenjamin Gray errno = -err; 209d1bc05b7SBenjamin Gray return err; 210d1bc05b7SBenjamin Gray } 211d1bc05b7SBenjamin Gray 212d1bc05b7SBenjamin Gray static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result, 213d1bc05b7SBenjamin Gray int base, intmax_t min, intmax_t max) 214d1bc05b7SBenjamin Gray { 215d1bc05b7SBenjamin Gray int err; 216d1bc05b7SBenjamin Gray char *end; 217d1bc05b7SBenjamin Gray 218d1bc05b7SBenjamin Gray errno = 0; 219d1bc05b7SBenjamin Gray *result = strtoimax(buffer, &end, base); 220d1bc05b7SBenjamin Gray 221d1bc05b7SBenjamin Gray if (errno) 222d1bc05b7SBenjamin Gray return -errno; 223d1bc05b7SBenjamin Gray 224d1bc05b7SBenjamin Gray err = validate_int_parse(buffer, count, end); 225d1bc05b7SBenjamin Gray if (err) 226d1bc05b7SBenjamin Gray goto out; 227d1bc05b7SBenjamin Gray 228d1bc05b7SBenjamin Gray if (*result < min || *result > max) 229d1bc05b7SBenjamin Gray err = -EOVERFLOW; 230d1bc05b7SBenjamin Gray 231d1bc05b7SBenjamin Gray out: 232d1bc05b7SBenjamin Gray errno = -err; 233d1bc05b7SBenjamin Gray return err; 234d1bc05b7SBenjamin Gray } 235d1bc05b7SBenjamin Gray 236d1bc05b7SBenjamin Gray static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result, 237d1bc05b7SBenjamin Gray int base, uintmax_t max) 238d1bc05b7SBenjamin Gray { 239d1bc05b7SBenjamin Gray int err = 0; 240d1bc05b7SBenjamin Gray char *end; 241d1bc05b7SBenjamin Gray 242d1bc05b7SBenjamin Gray errno = 0; 243d1bc05b7SBenjamin Gray *result = strtoumax(buffer, &end, base); 244d1bc05b7SBenjamin Gray 245d1bc05b7SBenjamin Gray if (errno) 246d1bc05b7SBenjamin Gray return -errno; 247d1bc05b7SBenjamin Gray 248d1bc05b7SBenjamin Gray err = validate_int_parse(buffer, count, end); 249d1bc05b7SBenjamin Gray if (err) 250d1bc05b7SBenjamin Gray goto out; 251d1bc05b7SBenjamin Gray 252d1bc05b7SBenjamin Gray if (*result > max) 253d1bc05b7SBenjamin Gray err = -EOVERFLOW; 254d1bc05b7SBenjamin Gray 255d1bc05b7SBenjamin Gray out: 256d1bc05b7SBenjamin Gray errno = -err; 257d1bc05b7SBenjamin Gray return err; 258d1bc05b7SBenjamin Gray } 259d1bc05b7SBenjamin Gray 260d1bc05b7SBenjamin Gray int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base) 261d1bc05b7SBenjamin Gray { 262d1bc05b7SBenjamin Gray return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX); 263d1bc05b7SBenjamin Gray } 264d1bc05b7SBenjamin Gray 265d1bc05b7SBenjamin Gray int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base) 266d1bc05b7SBenjamin Gray { 267d1bc05b7SBenjamin Gray return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX); 268d1bc05b7SBenjamin Gray } 269d1bc05b7SBenjamin Gray 270d1bc05b7SBenjamin Gray int parse_int(const char *buffer, size_t count, int *result, int base) 271d1bc05b7SBenjamin Gray { 272d1bc05b7SBenjamin Gray intmax_t parsed; 273d1bc05b7SBenjamin Gray int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX); 274d1bc05b7SBenjamin Gray 275d1bc05b7SBenjamin Gray *result = parsed; 276d1bc05b7SBenjamin Gray return err; 277d1bc05b7SBenjamin Gray } 278d1bc05b7SBenjamin Gray 279d1bc05b7SBenjamin Gray int parse_uint(const char *buffer, size_t count, unsigned int *result, int base) 280d1bc05b7SBenjamin Gray { 281d1bc05b7SBenjamin Gray uintmax_t parsed; 282d1bc05b7SBenjamin Gray int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX); 283d1bc05b7SBenjamin Gray 284d1bc05b7SBenjamin Gray *result = parsed; 285d1bc05b7SBenjamin Gray return err; 286d1bc05b7SBenjamin Gray } 287d1bc05b7SBenjamin Gray 288d1bc05b7SBenjamin Gray int parse_long(const char *buffer, size_t count, long *result, int base) 289d1bc05b7SBenjamin Gray { 290d1bc05b7SBenjamin Gray intmax_t parsed; 291d1bc05b7SBenjamin Gray int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX); 292d1bc05b7SBenjamin Gray 293d1bc05b7SBenjamin Gray *result = parsed; 294d1bc05b7SBenjamin Gray return err; 295d1bc05b7SBenjamin Gray } 296d1bc05b7SBenjamin Gray 297d1bc05b7SBenjamin Gray int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base) 298d1bc05b7SBenjamin Gray { 299d1bc05b7SBenjamin Gray uintmax_t parsed; 300d1bc05b7SBenjamin Gray int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX); 301d1bc05b7SBenjamin Gray 302d1bc05b7SBenjamin Gray *result = parsed; 303d1bc05b7SBenjamin Gray return err; 304d1bc05b7SBenjamin Gray } 305d1bc05b7SBenjamin Gray 3065c20de57SBenjamin Gray int read_long(const char *path, long *result, int base) 3075c20de57SBenjamin Gray { 3085c20de57SBenjamin Gray int err; 3095c20de57SBenjamin Gray char buffer[32] = {0}; 3105c20de57SBenjamin Gray 3115c20de57SBenjamin Gray err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 3125c20de57SBenjamin Gray if (err) 3135c20de57SBenjamin Gray return err; 3145c20de57SBenjamin Gray 3155c20de57SBenjamin Gray return parse_long(buffer, sizeof(buffer), result, base); 3165c20de57SBenjamin Gray } 3175c20de57SBenjamin Gray 3185c20de57SBenjamin Gray int read_ulong(const char *path, unsigned long *result, int base) 3195c20de57SBenjamin Gray { 3205c20de57SBenjamin Gray int err; 3215c20de57SBenjamin Gray char buffer[32] = {0}; 3225c20de57SBenjamin Gray 3235c20de57SBenjamin Gray err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 3245c20de57SBenjamin Gray if (err) 3255c20de57SBenjamin Gray return err; 3265c20de57SBenjamin Gray 3275c20de57SBenjamin Gray return parse_ulong(buffer, sizeof(buffer), result, base); 3285c20de57SBenjamin Gray } 3295c20de57SBenjamin Gray 3305c20de57SBenjamin Gray int write_long(const char *path, long result, int base) 3315c20de57SBenjamin Gray { 3325c20de57SBenjamin Gray int err; 3335c20de57SBenjamin Gray int len; 3345c20de57SBenjamin Gray char buffer[32]; 3355c20de57SBenjamin Gray 3365c20de57SBenjamin Gray /* Decimal only for now: no format specifier for signed hex values */ 3375c20de57SBenjamin Gray if (base != 10) { 3385c20de57SBenjamin Gray err = -EINVAL; 3395c20de57SBenjamin Gray goto out; 3405c20de57SBenjamin Gray } 3415c20de57SBenjamin Gray 3425c20de57SBenjamin Gray len = snprintf(buffer, sizeof(buffer), "%ld", result); 3435c20de57SBenjamin Gray if (len < 0 || len >= sizeof(buffer)) { 3445c20de57SBenjamin Gray err = -EOVERFLOW; 3455c20de57SBenjamin Gray goto out; 3465c20de57SBenjamin Gray } 3475c20de57SBenjamin Gray 3485c20de57SBenjamin Gray err = write_file(path, buffer, len); 3495c20de57SBenjamin Gray 3505c20de57SBenjamin Gray out: 3515c20de57SBenjamin Gray errno = -err; 3525c20de57SBenjamin Gray return err; 3535c20de57SBenjamin Gray } 3545c20de57SBenjamin Gray 3555c20de57SBenjamin Gray int write_ulong(const char *path, unsigned long result, int base) 3565c20de57SBenjamin Gray { 3575c20de57SBenjamin Gray int err; 3585c20de57SBenjamin Gray int len; 3595c20de57SBenjamin Gray char buffer[32]; 3605c20de57SBenjamin Gray char *fmt; 3615c20de57SBenjamin Gray 3625c20de57SBenjamin Gray switch (base) { 3635c20de57SBenjamin Gray case 10: 3645c20de57SBenjamin Gray fmt = "%lu"; 3655c20de57SBenjamin Gray break; 3665c20de57SBenjamin Gray case 16: 3675c20de57SBenjamin Gray fmt = "%lx"; 3685c20de57SBenjamin Gray break; 3695c20de57SBenjamin Gray default: 3705c20de57SBenjamin Gray err = -EINVAL; 3715c20de57SBenjamin Gray goto out; 3725c20de57SBenjamin Gray } 3735c20de57SBenjamin Gray 3745c20de57SBenjamin Gray len = snprintf(buffer, sizeof(buffer), fmt, result); 3755c20de57SBenjamin Gray if (len < 0 || len >= sizeof(buffer)) { 3765c20de57SBenjamin Gray err = -errno; 3775c20de57SBenjamin Gray goto out; 3785c20de57SBenjamin Gray } 3795c20de57SBenjamin Gray 3805c20de57SBenjamin Gray err = write_file(path, buffer, len); 3815c20de57SBenjamin Gray 3825c20de57SBenjamin Gray out: 3835c20de57SBenjamin Gray errno = -err; 3845c20de57SBenjamin Gray return err; 3855c20de57SBenjamin Gray } 3865c20de57SBenjamin Gray 387e3028437SMichael Ellerman void *find_auxv_entry(int type, char *auxv) 388e3028437SMichael Ellerman { 389e3028437SMichael Ellerman ElfW(auxv_t) *p; 390e3028437SMichael Ellerman 391fcb45ec0SMichael Ellerman p = (ElfW(auxv_t) *)auxv; 392fcb45ec0SMichael Ellerman 393fcb45ec0SMichael Ellerman while (p->a_type != AT_NULL) { 394e3028437SMichael Ellerman if (p->a_type == type) 395e3028437SMichael Ellerman return p; 396fcb45ec0SMichael Ellerman 397fcb45ec0SMichael Ellerman p++; 398fcb45ec0SMichael Ellerman } 399e3028437SMichael Ellerman 400e3028437SMichael Ellerman return NULL; 401e3028437SMichael Ellerman } 402e3028437SMichael Ellerman 403e3028437SMichael Ellerman void *get_auxv_entry(int type) 404e3028437SMichael Ellerman { 405e3028437SMichael Ellerman ElfW(auxv_t) *p; 406e3028437SMichael Ellerman 407e3028437SMichael Ellerman if (read_auxv(auxv, sizeof(auxv))) 408e3028437SMichael Ellerman return NULL; 409e3028437SMichael Ellerman 410e3028437SMichael Ellerman p = find_auxv_entry(type, auxv); 411e3028437SMichael Ellerman if (p) 412e3028437SMichael Ellerman return (void *)p->a_un.a_val; 413e3028437SMichael Ellerman 414e3028437SMichael Ellerman return NULL; 415fcb45ec0SMichael Ellerman } 416d1301afdSMichael Ellerman 417d1301afdSMichael Ellerman int pick_online_cpu(void) 418d1301afdSMichael Ellerman { 419dfa03fffSSandipan Das int ncpus, cpu = -1; 420dfa03fffSSandipan Das cpu_set_t *mask; 421dfa03fffSSandipan Das size_t size; 422d1301afdSMichael Ellerman 423dfa03fffSSandipan Das ncpus = get_nprocs_conf(); 424dfa03fffSSandipan Das size = CPU_ALLOC_SIZE(ncpus); 425dfa03fffSSandipan Das mask = CPU_ALLOC(ncpus); 426dfa03fffSSandipan Das if (!mask) { 427dfa03fffSSandipan Das perror("malloc"); 428d1301afdSMichael Ellerman return -1; 429d1301afdSMichael Ellerman } 430d1301afdSMichael Ellerman 431dfa03fffSSandipan Das CPU_ZERO_S(size, mask); 432dfa03fffSSandipan Das 433dfa03fffSSandipan Das if (sched_getaffinity(0, size, mask)) { 434dfa03fffSSandipan Das perror("sched_getaffinity"); 435dfa03fffSSandipan Das goto done; 436dfa03fffSSandipan Das } 437dfa03fffSSandipan Das 438d1301afdSMichael Ellerman /* We prefer a primary thread, but skip 0 */ 439dfa03fffSSandipan Das for (cpu = 8; cpu < ncpus; cpu += 8) 440dfa03fffSSandipan Das if (CPU_ISSET_S(cpu, size, mask)) 441dfa03fffSSandipan Das goto done; 442d1301afdSMichael Ellerman 443d1301afdSMichael Ellerman /* Search for anything, but in reverse */ 444dfa03fffSSandipan Das for (cpu = ncpus - 1; cpu >= 0; cpu--) 445dfa03fffSSandipan Das if (CPU_ISSET_S(cpu, size, mask)) 446dfa03fffSSandipan Das goto done; 447d1301afdSMichael Ellerman 448d1301afdSMichael Ellerman printf("No cpus in affinity mask?!\n"); 449dfa03fffSSandipan Das 450dfa03fffSSandipan Das done: 451dfa03fffSSandipan Das CPU_FREE(mask); 452dfa03fffSSandipan Das return cpu; 453d1301afdSMichael Ellerman } 45495f9b3afSMichael Ellerman 455c97b2fc6SBenjamin Gray int bind_to_cpu(int cpu) 456c97b2fc6SBenjamin Gray { 457c97b2fc6SBenjamin Gray cpu_set_t mask; 458*6ff4dc25SBenjamin Gray int err; 459*6ff4dc25SBenjamin Gray 460*6ff4dc25SBenjamin Gray if (cpu == BIND_CPU_ANY) { 461*6ff4dc25SBenjamin Gray cpu = pick_online_cpu(); 462*6ff4dc25SBenjamin Gray if (cpu < 0) 463*6ff4dc25SBenjamin Gray return cpu; 464*6ff4dc25SBenjamin Gray } 465c97b2fc6SBenjamin Gray 466c97b2fc6SBenjamin Gray printf("Binding to cpu %d\n", cpu); 467c97b2fc6SBenjamin Gray 468c97b2fc6SBenjamin Gray CPU_ZERO(&mask); 469c97b2fc6SBenjamin Gray CPU_SET(cpu, &mask); 470c97b2fc6SBenjamin Gray 471*6ff4dc25SBenjamin Gray err = sched_setaffinity(0, sizeof(mask), &mask); 472*6ff4dc25SBenjamin Gray if (err) 473*6ff4dc25SBenjamin Gray return err; 474*6ff4dc25SBenjamin Gray 475*6ff4dc25SBenjamin Gray return cpu; 476c97b2fc6SBenjamin Gray } 477c97b2fc6SBenjamin Gray 47895f9b3afSMichael Ellerman bool is_ppc64le(void) 47995f9b3afSMichael Ellerman { 48095f9b3afSMichael Ellerman struct utsname uts; 48195f9b3afSMichael Ellerman int rc; 48295f9b3afSMichael Ellerman 48395f9b3afSMichael Ellerman errno = 0; 48495f9b3afSMichael Ellerman rc = uname(&uts); 48595f9b3afSMichael Ellerman if (rc) { 48695f9b3afSMichael Ellerman perror("uname"); 48795f9b3afSMichael Ellerman return false; 48895f9b3afSMichael Ellerman } 48995f9b3afSMichael Ellerman 49095f9b3afSMichael Ellerman return strcmp(uts.machine, "ppc64le") == 0; 49195f9b3afSMichael Ellerman } 492d2bf7932SNaveen N. Rao 493c790c3d2SMichael Ellerman int read_sysfs_file(char *fpath, char *result, size_t result_size) 494c790c3d2SMichael Ellerman { 495c790c3d2SMichael Ellerman char path[PATH_MAX] = "/sys/"; 496c790c3d2SMichael Ellerman 497c790c3d2SMichael Ellerman strncat(path, fpath, PATH_MAX - strlen(path) - 1); 498c790c3d2SMichael Ellerman 499a974f0c1SBenjamin Gray return read_file(path, result, result_size, NULL); 500c790c3d2SMichael Ellerman } 501c790c3d2SMichael Ellerman 502121d340bSBenjamin Gray int read_debugfs_int(const char *debugfs_file, int *result) 503d2bf7932SNaveen N. Rao { 504a974f0c1SBenjamin Gray int err; 505a974f0c1SBenjamin Gray char value[16] = {0}; 506d2bf7932SNaveen N. Rao 507121d340bSBenjamin Gray err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); 508a974f0c1SBenjamin Gray if (err) 509a974f0c1SBenjamin Gray return err; 510d2bf7932SNaveen N. Rao 511d1bc05b7SBenjamin Gray return parse_int(value, sizeof(value), result, 10); 512d2bf7932SNaveen N. Rao } 513d2bf7932SNaveen N. Rao 514121d340bSBenjamin Gray int write_debugfs_int(const char *debugfs_file, int result) 515d2bf7932SNaveen N. Rao { 516d2bf7932SNaveen N. Rao char value[16]; 517d2bf7932SNaveen N. Rao 518d2bf7932SNaveen N. Rao snprintf(value, 16, "%d", result); 519d2bf7932SNaveen N. Rao 520121d340bSBenjamin Gray return write_debugfs_file(debugfs_file, value, strlen(value)); 521d2bf7932SNaveen N. Rao } 522d2bf7932SNaveen N. Rao 523d2bf7932SNaveen N. Rao static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 524d2bf7932SNaveen N. Rao int cpu, int group_fd, unsigned long flags) 525d2bf7932SNaveen N. Rao { 526d2bf7932SNaveen N. Rao return syscall(__NR_perf_event_open, hw_event, pid, cpu, 527d2bf7932SNaveen N. Rao group_fd, flags); 528d2bf7932SNaveen N. Rao } 529d2bf7932SNaveen N. Rao 530d2bf7932SNaveen N. Rao static void perf_event_attr_init(struct perf_event_attr *event_attr, 531d2bf7932SNaveen N. Rao unsigned int type, 532d2bf7932SNaveen N. Rao unsigned long config) 533d2bf7932SNaveen N. Rao { 534d2bf7932SNaveen N. Rao memset(event_attr, 0, sizeof(*event_attr)); 535d2bf7932SNaveen N. Rao 536d2bf7932SNaveen N. Rao event_attr->type = type; 537d2bf7932SNaveen N. Rao event_attr->size = sizeof(struct perf_event_attr); 538d2bf7932SNaveen N. Rao event_attr->config = config; 539d2bf7932SNaveen N. Rao event_attr->read_format = PERF_FORMAT_GROUP; 540d2bf7932SNaveen N. Rao event_attr->disabled = 1; 541d2bf7932SNaveen N. Rao event_attr->exclude_kernel = 1; 542d2bf7932SNaveen N. Rao event_attr->exclude_hv = 1; 543d2bf7932SNaveen N. Rao event_attr->exclude_guest = 1; 544d2bf7932SNaveen N. Rao } 545d2bf7932SNaveen N. Rao 546d2bf7932SNaveen N. Rao int perf_event_open_counter(unsigned int type, 547d2bf7932SNaveen N. Rao unsigned long config, int group_fd) 548d2bf7932SNaveen N. Rao { 549d2bf7932SNaveen N. Rao int fd; 550d2bf7932SNaveen N. Rao struct perf_event_attr event_attr; 551d2bf7932SNaveen N. Rao 552d2bf7932SNaveen N. Rao perf_event_attr_init(&event_attr, type, config); 553d2bf7932SNaveen N. Rao 554d2bf7932SNaveen N. Rao fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); 555d2bf7932SNaveen N. Rao 556d2bf7932SNaveen N. Rao if (fd < 0) 557d2bf7932SNaveen N. Rao perror("perf_event_open() failed"); 558d2bf7932SNaveen N. Rao 559d2bf7932SNaveen N. Rao return fd; 560d2bf7932SNaveen N. Rao } 561d2bf7932SNaveen N. Rao 562d2bf7932SNaveen N. Rao int perf_event_enable(int fd) 563d2bf7932SNaveen N. Rao { 564d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { 565d2bf7932SNaveen N. Rao perror("error while enabling perf events"); 566d2bf7932SNaveen N. Rao return -1; 567d2bf7932SNaveen N. Rao } 568d2bf7932SNaveen N. Rao 569d2bf7932SNaveen N. Rao return 0; 570d2bf7932SNaveen N. Rao } 571d2bf7932SNaveen N. Rao 572d2bf7932SNaveen N. Rao int perf_event_disable(int fd) 573d2bf7932SNaveen N. Rao { 574d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { 575d2bf7932SNaveen N. Rao perror("error disabling perf events"); 576d2bf7932SNaveen N. Rao return -1; 577d2bf7932SNaveen N. Rao } 578d2bf7932SNaveen N. Rao 579d2bf7932SNaveen N. Rao return 0; 580d2bf7932SNaveen N. Rao } 581d2bf7932SNaveen N. Rao 582d2bf7932SNaveen N. Rao int perf_event_reset(int fd) 583d2bf7932SNaveen N. Rao { 584d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { 585d2bf7932SNaveen N. Rao perror("error resetting perf events"); 586d2bf7932SNaveen N. Rao return -1; 587d2bf7932SNaveen N. Rao } 588d2bf7932SNaveen N. Rao 589d2bf7932SNaveen N. Rao return 0; 590d2bf7932SNaveen N. Rao } 591d2bf7932SNaveen N. Rao 592c405b738SSandipan Das int using_hash_mmu(bool *using_hash) 593c405b738SSandipan Das { 594c405b738SSandipan Das char line[128]; 595c405b738SSandipan Das FILE *f; 596c405b738SSandipan Das int rc; 597c405b738SSandipan Das 598c405b738SSandipan Das f = fopen("/proc/cpuinfo", "r"); 599c405b738SSandipan Das FAIL_IF(!f); 600c405b738SSandipan Das 601c405b738SSandipan Das rc = 0; 602c405b738SSandipan Das while (fgets(line, sizeof(line), f) != NULL) { 60334c10334SMichael Ellerman if (!strcmp(line, "MMU : Hash\n") || 60434c10334SMichael Ellerman !strcmp(line, "platform : Cell\n") || 60534c10334SMichael Ellerman !strcmp(line, "platform : PowerMac\n")) { 606c405b738SSandipan Das *using_hash = true; 607c405b738SSandipan Das goto out; 608c405b738SSandipan Das } 609c405b738SSandipan Das 610c405b738SSandipan Das if (strcmp(line, "MMU : Radix\n") == 0) { 611c405b738SSandipan Das *using_hash = false; 612c405b738SSandipan Das goto out; 613c405b738SSandipan Das } 614c405b738SSandipan Das } 615c405b738SSandipan Das 616c405b738SSandipan Das rc = -1; 617c405b738SSandipan Das out: 618c405b738SSandipan Das fclose(f); 619c405b738SSandipan Das return rc; 620c405b738SSandipan Das } 621