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 68*8d7253dcSBenjamin Gray int read_file_alloc(const char *path, char **buf, size_t *len) 69*8d7253dcSBenjamin Gray { 70*8d7253dcSBenjamin Gray size_t read_offset = 0; 71*8d7253dcSBenjamin Gray size_t buffer_len = 0; 72*8d7253dcSBenjamin Gray char *buffer = NULL; 73*8d7253dcSBenjamin Gray int err; 74*8d7253dcSBenjamin Gray int fd; 75*8d7253dcSBenjamin Gray 76*8d7253dcSBenjamin Gray fd = open(path, O_RDONLY); 77*8d7253dcSBenjamin Gray if (fd < 0) 78*8d7253dcSBenjamin Gray return -errno; 79*8d7253dcSBenjamin Gray 80*8d7253dcSBenjamin Gray /* 81*8d7253dcSBenjamin Gray * We don't use stat & preallocate st_size because some non-files 82*8d7253dcSBenjamin Gray * report 0 file size. Instead just dynamically grow the buffer 83*8d7253dcSBenjamin Gray * as needed. 84*8d7253dcSBenjamin Gray */ 85*8d7253dcSBenjamin Gray while (1) { 86*8d7253dcSBenjamin Gray ssize_t rc; 87*8d7253dcSBenjamin Gray 88*8d7253dcSBenjamin Gray if (read_offset >= buffer_len / 2) { 89*8d7253dcSBenjamin Gray char *next_buffer; 90*8d7253dcSBenjamin Gray 91*8d7253dcSBenjamin Gray buffer_len = buffer_len ? buffer_len * 2 : 4096; 92*8d7253dcSBenjamin Gray next_buffer = realloc(buffer, buffer_len); 93*8d7253dcSBenjamin Gray if (!next_buffer) { 94*8d7253dcSBenjamin Gray err = -errno; 95*8d7253dcSBenjamin Gray goto out; 96*8d7253dcSBenjamin Gray } 97*8d7253dcSBenjamin Gray buffer = next_buffer; 98*8d7253dcSBenjamin Gray } 99*8d7253dcSBenjamin Gray 100*8d7253dcSBenjamin Gray rc = read(fd, buffer + read_offset, buffer_len - read_offset); 101*8d7253dcSBenjamin Gray if (rc < 0) { 102*8d7253dcSBenjamin Gray err = -errno; 103*8d7253dcSBenjamin Gray goto out; 104*8d7253dcSBenjamin Gray } 105*8d7253dcSBenjamin Gray 106*8d7253dcSBenjamin Gray if (rc == 0) 107*8d7253dcSBenjamin Gray break; 108*8d7253dcSBenjamin Gray 109*8d7253dcSBenjamin Gray read_offset += rc; 110*8d7253dcSBenjamin Gray } 111*8d7253dcSBenjamin Gray 112*8d7253dcSBenjamin Gray *buf = buffer; 113*8d7253dcSBenjamin Gray if (len) 114*8d7253dcSBenjamin Gray *len = read_offset; 115*8d7253dcSBenjamin Gray 116*8d7253dcSBenjamin Gray err = 0; 117*8d7253dcSBenjamin Gray 118*8d7253dcSBenjamin Gray out: 119*8d7253dcSBenjamin Gray close(fd); 120*8d7253dcSBenjamin Gray if (err) 121*8d7253dcSBenjamin Gray free(buffer); 122*8d7253dcSBenjamin Gray errno = -err; 123*8d7253dcSBenjamin Gray return err; 124*8d7253dcSBenjamin Gray } 125*8d7253dcSBenjamin 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 45595f9b3afSMichael Ellerman bool is_ppc64le(void) 45695f9b3afSMichael Ellerman { 45795f9b3afSMichael Ellerman struct utsname uts; 45895f9b3afSMichael Ellerman int rc; 45995f9b3afSMichael Ellerman 46095f9b3afSMichael Ellerman errno = 0; 46195f9b3afSMichael Ellerman rc = uname(&uts); 46295f9b3afSMichael Ellerman if (rc) { 46395f9b3afSMichael Ellerman perror("uname"); 46495f9b3afSMichael Ellerman return false; 46595f9b3afSMichael Ellerman } 46695f9b3afSMichael Ellerman 46795f9b3afSMichael Ellerman return strcmp(uts.machine, "ppc64le") == 0; 46895f9b3afSMichael Ellerman } 469d2bf7932SNaveen N. Rao 470c790c3d2SMichael Ellerman int read_sysfs_file(char *fpath, char *result, size_t result_size) 471c790c3d2SMichael Ellerman { 472c790c3d2SMichael Ellerman char path[PATH_MAX] = "/sys/"; 473c790c3d2SMichael Ellerman 474c790c3d2SMichael Ellerman strncat(path, fpath, PATH_MAX - strlen(path) - 1); 475c790c3d2SMichael Ellerman 476a974f0c1SBenjamin Gray return read_file(path, result, result_size, NULL); 477c790c3d2SMichael Ellerman } 478c790c3d2SMichael Ellerman 479121d340bSBenjamin Gray int read_debugfs_int(const char *debugfs_file, int *result) 480d2bf7932SNaveen N. Rao { 481a974f0c1SBenjamin Gray int err; 482a974f0c1SBenjamin Gray char value[16] = {0}; 483d2bf7932SNaveen N. Rao 484121d340bSBenjamin Gray err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); 485a974f0c1SBenjamin Gray if (err) 486a974f0c1SBenjamin Gray return err; 487d2bf7932SNaveen N. Rao 488d1bc05b7SBenjamin Gray return parse_int(value, sizeof(value), result, 10); 489d2bf7932SNaveen N. Rao } 490d2bf7932SNaveen N. Rao 491121d340bSBenjamin Gray int write_debugfs_int(const char *debugfs_file, int result) 492d2bf7932SNaveen N. Rao { 493d2bf7932SNaveen N. Rao char value[16]; 494d2bf7932SNaveen N. Rao 495d2bf7932SNaveen N. Rao snprintf(value, 16, "%d", result); 496d2bf7932SNaveen N. Rao 497121d340bSBenjamin Gray return write_debugfs_file(debugfs_file, value, strlen(value)); 498d2bf7932SNaveen N. Rao } 499d2bf7932SNaveen N. Rao 500d2bf7932SNaveen N. Rao static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 501d2bf7932SNaveen N. Rao int cpu, int group_fd, unsigned long flags) 502d2bf7932SNaveen N. Rao { 503d2bf7932SNaveen N. Rao return syscall(__NR_perf_event_open, hw_event, pid, cpu, 504d2bf7932SNaveen N. Rao group_fd, flags); 505d2bf7932SNaveen N. Rao } 506d2bf7932SNaveen N. Rao 507d2bf7932SNaveen N. Rao static void perf_event_attr_init(struct perf_event_attr *event_attr, 508d2bf7932SNaveen N. Rao unsigned int type, 509d2bf7932SNaveen N. Rao unsigned long config) 510d2bf7932SNaveen N. Rao { 511d2bf7932SNaveen N. Rao memset(event_attr, 0, sizeof(*event_attr)); 512d2bf7932SNaveen N. Rao 513d2bf7932SNaveen N. Rao event_attr->type = type; 514d2bf7932SNaveen N. Rao event_attr->size = sizeof(struct perf_event_attr); 515d2bf7932SNaveen N. Rao event_attr->config = config; 516d2bf7932SNaveen N. Rao event_attr->read_format = PERF_FORMAT_GROUP; 517d2bf7932SNaveen N. Rao event_attr->disabled = 1; 518d2bf7932SNaveen N. Rao event_attr->exclude_kernel = 1; 519d2bf7932SNaveen N. Rao event_attr->exclude_hv = 1; 520d2bf7932SNaveen N. Rao event_attr->exclude_guest = 1; 521d2bf7932SNaveen N. Rao } 522d2bf7932SNaveen N. Rao 523d2bf7932SNaveen N. Rao int perf_event_open_counter(unsigned int type, 524d2bf7932SNaveen N. Rao unsigned long config, int group_fd) 525d2bf7932SNaveen N. Rao { 526d2bf7932SNaveen N. Rao int fd; 527d2bf7932SNaveen N. Rao struct perf_event_attr event_attr; 528d2bf7932SNaveen N. Rao 529d2bf7932SNaveen N. Rao perf_event_attr_init(&event_attr, type, config); 530d2bf7932SNaveen N. Rao 531d2bf7932SNaveen N. Rao fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); 532d2bf7932SNaveen N. Rao 533d2bf7932SNaveen N. Rao if (fd < 0) 534d2bf7932SNaveen N. Rao perror("perf_event_open() failed"); 535d2bf7932SNaveen N. Rao 536d2bf7932SNaveen N. Rao return fd; 537d2bf7932SNaveen N. Rao } 538d2bf7932SNaveen N. Rao 539d2bf7932SNaveen N. Rao int perf_event_enable(int fd) 540d2bf7932SNaveen N. Rao { 541d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { 542d2bf7932SNaveen N. Rao perror("error while enabling perf events"); 543d2bf7932SNaveen N. Rao return -1; 544d2bf7932SNaveen N. Rao } 545d2bf7932SNaveen N. Rao 546d2bf7932SNaveen N. Rao return 0; 547d2bf7932SNaveen N. Rao } 548d2bf7932SNaveen N. Rao 549d2bf7932SNaveen N. Rao int perf_event_disable(int fd) 550d2bf7932SNaveen N. Rao { 551d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { 552d2bf7932SNaveen N. Rao perror("error disabling perf events"); 553d2bf7932SNaveen N. Rao return -1; 554d2bf7932SNaveen N. Rao } 555d2bf7932SNaveen N. Rao 556d2bf7932SNaveen N. Rao return 0; 557d2bf7932SNaveen N. Rao } 558d2bf7932SNaveen N. Rao 559d2bf7932SNaveen N. Rao int perf_event_reset(int fd) 560d2bf7932SNaveen N. Rao { 561d2bf7932SNaveen N. Rao if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { 562d2bf7932SNaveen N. Rao perror("error resetting perf events"); 563d2bf7932SNaveen N. Rao return -1; 564d2bf7932SNaveen N. Rao } 565d2bf7932SNaveen N. Rao 566d2bf7932SNaveen N. Rao return 0; 567d2bf7932SNaveen N. Rao } 568d2bf7932SNaveen N. Rao 569c405b738SSandipan Das int using_hash_mmu(bool *using_hash) 570c405b738SSandipan Das { 571c405b738SSandipan Das char line[128]; 572c405b738SSandipan Das FILE *f; 573c405b738SSandipan Das int rc; 574c405b738SSandipan Das 575c405b738SSandipan Das f = fopen("/proc/cpuinfo", "r"); 576c405b738SSandipan Das FAIL_IF(!f); 577c405b738SSandipan Das 578c405b738SSandipan Das rc = 0; 579c405b738SSandipan Das while (fgets(line, sizeof(line), f) != NULL) { 58034c10334SMichael Ellerman if (!strcmp(line, "MMU : Hash\n") || 58134c10334SMichael Ellerman !strcmp(line, "platform : Cell\n") || 58234c10334SMichael Ellerman !strcmp(line, "platform : PowerMac\n")) { 583c405b738SSandipan Das *using_hash = true; 584c405b738SSandipan Das goto out; 585c405b738SSandipan Das } 586c405b738SSandipan Das 587c405b738SSandipan Das if (strcmp(line, "MMU : Radix\n") == 0) { 588c405b738SSandipan Das *using_hash = false; 589c405b738SSandipan Das goto out; 590c405b738SSandipan Das } 591c405b738SSandipan Das } 592c405b738SSandipan Das 593c405b738SSandipan Das rc = -1; 594c405b738SSandipan Das out: 595c405b738SSandipan Das fclose(f); 596c405b738SSandipan Das return rc; 597c405b738SSandipan Das } 598