162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2013-2015, Michael Ellerman, IBM Corp. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define _GNU_SOURCE /* For CPU_ZERO etc. */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <elf.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <inttypes.h> 1262306a36Sopenharmony_ci#include <limits.h> 1362306a36Sopenharmony_ci#include <link.h> 1462306a36Sopenharmony_ci#include <sched.h> 1562306a36Sopenharmony_ci#include <stdio.h> 1662306a36Sopenharmony_ci#include <stdlib.h> 1762306a36Sopenharmony_ci#include <string.h> 1862306a36Sopenharmony_ci#include <sys/ioctl.h> 1962306a36Sopenharmony_ci#include <sys/stat.h> 2062306a36Sopenharmony_ci#include <sys/sysinfo.h> 2162306a36Sopenharmony_ci#include <sys/types.h> 2262306a36Sopenharmony_ci#include <sys/utsname.h> 2362306a36Sopenharmony_ci#include <unistd.h> 2462306a36Sopenharmony_ci#include <asm/unistd.h> 2562306a36Sopenharmony_ci#include <linux/limits.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "utils.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic char auxv[4096]; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint read_file(const char *path, char *buf, size_t count, size_t *len) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci ssize_t rc; 3462306a36Sopenharmony_ci int fd; 3562306a36Sopenharmony_ci int err; 3662306a36Sopenharmony_ci char eof; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci fd = open(path, O_RDONLY); 3962306a36Sopenharmony_ci if (fd < 0) 4062306a36Sopenharmony_ci return -errno; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci rc = read(fd, buf, count); 4362306a36Sopenharmony_ci if (rc < 0) { 4462306a36Sopenharmony_ci err = -errno; 4562306a36Sopenharmony_ci goto out; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (len) 4962306a36Sopenharmony_ci *len = rc; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* Overflow if there are still more bytes after filling the buffer */ 5262306a36Sopenharmony_ci if (rc == count) { 5362306a36Sopenharmony_ci rc = read(fd, &eof, 1); 5462306a36Sopenharmony_ci if (rc != 0) { 5562306a36Sopenharmony_ci err = -EOVERFLOW; 5662306a36Sopenharmony_ci goto out; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci err = 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciout: 6362306a36Sopenharmony_ci close(fd); 6462306a36Sopenharmony_ci errno = -err; 6562306a36Sopenharmony_ci return err; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint read_file_alloc(const char *path, char **buf, size_t *len) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci size_t read_offset = 0; 7162306a36Sopenharmony_ci size_t buffer_len = 0; 7262306a36Sopenharmony_ci char *buffer = NULL; 7362306a36Sopenharmony_ci int err; 7462306a36Sopenharmony_ci int fd; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci fd = open(path, O_RDONLY); 7762306a36Sopenharmony_ci if (fd < 0) 7862306a36Sopenharmony_ci return -errno; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * We don't use stat & preallocate st_size because some non-files 8262306a36Sopenharmony_ci * report 0 file size. Instead just dynamically grow the buffer 8362306a36Sopenharmony_ci * as needed. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci while (1) { 8662306a36Sopenharmony_ci ssize_t rc; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (read_offset >= buffer_len / 2) { 8962306a36Sopenharmony_ci char *next_buffer; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci buffer_len = buffer_len ? buffer_len * 2 : 4096; 9262306a36Sopenharmony_ci next_buffer = realloc(buffer, buffer_len); 9362306a36Sopenharmony_ci if (!next_buffer) { 9462306a36Sopenharmony_ci err = -errno; 9562306a36Sopenharmony_ci goto out; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci buffer = next_buffer; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci rc = read(fd, buffer + read_offset, buffer_len - read_offset); 10162306a36Sopenharmony_ci if (rc < 0) { 10262306a36Sopenharmony_ci err = -errno; 10362306a36Sopenharmony_ci goto out; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (rc == 0) 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci read_offset += rc; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci *buf = buffer; 11362306a36Sopenharmony_ci if (len) 11462306a36Sopenharmony_ci *len = read_offset; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci err = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciout: 11962306a36Sopenharmony_ci close(fd); 12062306a36Sopenharmony_ci if (err) 12162306a36Sopenharmony_ci free(buffer); 12262306a36Sopenharmony_ci errno = -err; 12362306a36Sopenharmony_ci return err; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint write_file(const char *path, const char *buf, size_t count) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int fd; 12962306a36Sopenharmony_ci int err; 13062306a36Sopenharmony_ci ssize_t rc; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); 13362306a36Sopenharmony_ci if (fd < 0) 13462306a36Sopenharmony_ci return -errno; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci rc = write(fd, buf, count); 13762306a36Sopenharmony_ci if (rc < 0) { 13862306a36Sopenharmony_ci err = -errno; 13962306a36Sopenharmony_ci goto out; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (rc != count) { 14362306a36Sopenharmony_ci err = -EOVERFLOW; 14462306a36Sopenharmony_ci goto out; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci err = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciout: 15062306a36Sopenharmony_ci close(fd); 15162306a36Sopenharmony_ci errno = -err; 15262306a36Sopenharmony_ci return err; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciint read_auxv(char *buf, ssize_t buf_size) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int err; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci err = read_file("/proc/self/auxv", buf, buf_size, NULL); 16062306a36Sopenharmony_ci if (err) { 16162306a36Sopenharmony_ci perror("Error reading /proc/self/auxv"); 16262306a36Sopenharmony_ci return err; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciint read_debugfs_file(const char *subpath, char *buf, size_t count) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci char path[PATH_MAX] = "/sys/kernel/debug/"; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci strncat(path, subpath, sizeof(path) - strlen(path) - 1); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return read_file(path, buf, count, NULL); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciint write_debugfs_file(const char *subpath, const char *buf, size_t count) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci char path[PATH_MAX] = "/sys/kernel/debug/"; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci strncat(path, subpath, sizeof(path) - strlen(path) - 1); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return write_file(path, buf, count); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int validate_int_parse(const char *buffer, size_t count, char *end) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int err = 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Require at least one digit */ 19162306a36Sopenharmony_ci if (end == buffer) { 19262306a36Sopenharmony_ci err = -EINVAL; 19362306a36Sopenharmony_ci goto out; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Require all remaining characters be whitespace-ish */ 19762306a36Sopenharmony_ci for (; end < buffer + count; end++) { 19862306a36Sopenharmony_ci if (*end == '\0') 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (*end != ' ' && *end != '\n') { 20262306a36Sopenharmony_ci err = -EINVAL; 20362306a36Sopenharmony_ci goto out; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciout: 20862306a36Sopenharmony_ci errno = -err; 20962306a36Sopenharmony_ci return err; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int parse_bounded_int(const char *buffer, size_t count, intmax_t *result, 21362306a36Sopenharmony_ci int base, intmax_t min, intmax_t max) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci int err; 21662306a36Sopenharmony_ci char *end; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci errno = 0; 21962306a36Sopenharmony_ci *result = strtoimax(buffer, &end, base); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (errno) 22262306a36Sopenharmony_ci return -errno; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci err = validate_int_parse(buffer, count, end); 22562306a36Sopenharmony_ci if (err) 22662306a36Sopenharmony_ci goto out; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (*result < min || *result > max) 22962306a36Sopenharmony_ci err = -EOVERFLOW; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciout: 23262306a36Sopenharmony_ci errno = -err; 23362306a36Sopenharmony_ci return err; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result, 23762306a36Sopenharmony_ci int base, uintmax_t max) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int err = 0; 24062306a36Sopenharmony_ci char *end; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci errno = 0; 24362306a36Sopenharmony_ci *result = strtoumax(buffer, &end, base); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (errno) 24662306a36Sopenharmony_ci return -errno; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci err = validate_int_parse(buffer, count, end); 24962306a36Sopenharmony_ci if (err) 25062306a36Sopenharmony_ci goto out; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (*result > max) 25362306a36Sopenharmony_ci err = -EOVERFLOW; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ciout: 25662306a36Sopenharmony_ci errno = -err; 25762306a36Sopenharmony_ci return err; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciint parse_intmax(const char *buffer, size_t count, intmax_t *result, int base) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciint parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciint parse_int(const char *buffer, size_t count, int *result, int base) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci intmax_t parsed; 27362306a36Sopenharmony_ci int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci *result = parsed; 27662306a36Sopenharmony_ci return err; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint parse_uint(const char *buffer, size_t count, unsigned int *result, int base) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci uintmax_t parsed; 28262306a36Sopenharmony_ci int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci *result = parsed; 28562306a36Sopenharmony_ci return err; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciint parse_long(const char *buffer, size_t count, long *result, int base) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci intmax_t parsed; 29162306a36Sopenharmony_ci int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci *result = parsed; 29462306a36Sopenharmony_ci return err; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ciint parse_ulong(const char *buffer, size_t count, unsigned long *result, int base) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci uintmax_t parsed; 30062306a36Sopenharmony_ci int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci *result = parsed; 30362306a36Sopenharmony_ci return err; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ciint read_long(const char *path, long *result, int base) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci int err; 30962306a36Sopenharmony_ci char buffer[32] = {0}; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci return err; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return parse_long(buffer, sizeof(buffer), result, base); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciint read_ulong(const char *path, unsigned long *result, int base) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci int err; 32162306a36Sopenharmony_ci char buffer[32] = {0}; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci err = read_file(path, buffer, sizeof(buffer) - 1, NULL); 32462306a36Sopenharmony_ci if (err) 32562306a36Sopenharmony_ci return err; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return parse_ulong(buffer, sizeof(buffer), result, base); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ciint write_long(const char *path, long result, int base) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci int err; 33362306a36Sopenharmony_ci int len; 33462306a36Sopenharmony_ci char buffer[32]; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Decimal only for now: no format specifier for signed hex values */ 33762306a36Sopenharmony_ci if (base != 10) { 33862306a36Sopenharmony_ci err = -EINVAL; 33962306a36Sopenharmony_ci goto out; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), "%ld", result); 34362306a36Sopenharmony_ci if (len < 0 || len >= sizeof(buffer)) { 34462306a36Sopenharmony_ci err = -EOVERFLOW; 34562306a36Sopenharmony_ci goto out; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci err = write_file(path, buffer, len); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ciout: 35162306a36Sopenharmony_ci errno = -err; 35262306a36Sopenharmony_ci return err; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ciint write_ulong(const char *path, unsigned long result, int base) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci int err; 35862306a36Sopenharmony_ci int len; 35962306a36Sopenharmony_ci char buffer[32]; 36062306a36Sopenharmony_ci char *fmt; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci switch (base) { 36362306a36Sopenharmony_ci case 10: 36462306a36Sopenharmony_ci fmt = "%lu"; 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci case 16: 36762306a36Sopenharmony_ci fmt = "%lx"; 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci default: 37062306a36Sopenharmony_ci err = -EINVAL; 37162306a36Sopenharmony_ci goto out; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), fmt, result); 37562306a36Sopenharmony_ci if (len < 0 || len >= sizeof(buffer)) { 37662306a36Sopenharmony_ci err = -errno; 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci err = write_file(path, buffer, len); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciout: 38362306a36Sopenharmony_ci errno = -err; 38462306a36Sopenharmony_ci return err; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_civoid *find_auxv_entry(int type, char *auxv) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci ElfW(auxv_t) *p; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci p = (ElfW(auxv_t) *)auxv; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci while (p->a_type != AT_NULL) { 39462306a36Sopenharmony_ci if (p->a_type == type) 39562306a36Sopenharmony_ci return p; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci p++; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return NULL; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid *get_auxv_entry(int type) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci ElfW(auxv_t) *p; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (read_auxv(auxv, sizeof(auxv))) 40862306a36Sopenharmony_ci return NULL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci p = find_auxv_entry(type, auxv); 41162306a36Sopenharmony_ci if (p) 41262306a36Sopenharmony_ci return (void *)p->a_un.a_val; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return NULL; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint pick_online_cpu(void) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int ncpus, cpu = -1; 42062306a36Sopenharmony_ci cpu_set_t *mask; 42162306a36Sopenharmony_ci size_t size; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ncpus = get_nprocs_conf(); 42462306a36Sopenharmony_ci size = CPU_ALLOC_SIZE(ncpus); 42562306a36Sopenharmony_ci mask = CPU_ALLOC(ncpus); 42662306a36Sopenharmony_ci if (!mask) { 42762306a36Sopenharmony_ci perror("malloc"); 42862306a36Sopenharmony_ci return -1; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci CPU_ZERO_S(size, mask); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (sched_getaffinity(0, size, mask)) { 43462306a36Sopenharmony_ci perror("sched_getaffinity"); 43562306a36Sopenharmony_ci goto done; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* We prefer a primary thread, but skip 0 */ 43962306a36Sopenharmony_ci for (cpu = 8; cpu < ncpus; cpu += 8) 44062306a36Sopenharmony_ci if (CPU_ISSET_S(cpu, size, mask)) 44162306a36Sopenharmony_ci goto done; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Search for anything, but in reverse */ 44462306a36Sopenharmony_ci for (cpu = ncpus - 1; cpu >= 0; cpu--) 44562306a36Sopenharmony_ci if (CPU_ISSET_S(cpu, size, mask)) 44662306a36Sopenharmony_ci goto done; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci printf("No cpus in affinity mask?!\n"); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cidone: 45162306a36Sopenharmony_ci CPU_FREE(mask); 45262306a36Sopenharmony_ci return cpu; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciint bind_to_cpu(int cpu) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci cpu_set_t mask; 45862306a36Sopenharmony_ci int err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (cpu == BIND_CPU_ANY) { 46162306a36Sopenharmony_ci cpu = pick_online_cpu(); 46262306a36Sopenharmony_ci if (cpu < 0) 46362306a36Sopenharmony_ci return cpu; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci printf("Binding to cpu %d\n", cpu); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci CPU_ZERO(&mask); 46962306a36Sopenharmony_ci CPU_SET(cpu, &mask); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci err = sched_setaffinity(0, sizeof(mask), &mask); 47262306a36Sopenharmony_ci if (err) 47362306a36Sopenharmony_ci return err; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return cpu; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cibool is_ppc64le(void) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct utsname uts; 48162306a36Sopenharmony_ci int rc; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci errno = 0; 48462306a36Sopenharmony_ci rc = uname(&uts); 48562306a36Sopenharmony_ci if (rc) { 48662306a36Sopenharmony_ci perror("uname"); 48762306a36Sopenharmony_ci return false; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return strcmp(uts.machine, "ppc64le") == 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ciint read_sysfs_file(char *fpath, char *result, size_t result_size) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci char path[PATH_MAX] = "/sys/"; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci strncat(path, fpath, PATH_MAX - strlen(path) - 1); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return read_file(path, result, result_size, NULL); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciint read_debugfs_int(const char *debugfs_file, int *result) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int err; 50562306a36Sopenharmony_ci char value[16] = {0}; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); 50862306a36Sopenharmony_ci if (err) 50962306a36Sopenharmony_ci return err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return parse_int(value, sizeof(value), result, 10); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ciint write_debugfs_int(const char *debugfs_file, int result) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci char value[16]; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci snprintf(value, 16, "%d", result); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return write_debugfs_file(debugfs_file, value, strlen(value)); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 52462306a36Sopenharmony_ci int cpu, int group_fd, unsigned long flags) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci return syscall(__NR_perf_event_open, hw_event, pid, cpu, 52762306a36Sopenharmony_ci group_fd, flags); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void perf_event_attr_init(struct perf_event_attr *event_attr, 53162306a36Sopenharmony_ci unsigned int type, 53262306a36Sopenharmony_ci unsigned long config) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci memset(event_attr, 0, sizeof(*event_attr)); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci event_attr->type = type; 53762306a36Sopenharmony_ci event_attr->size = sizeof(struct perf_event_attr); 53862306a36Sopenharmony_ci event_attr->config = config; 53962306a36Sopenharmony_ci event_attr->read_format = PERF_FORMAT_GROUP; 54062306a36Sopenharmony_ci event_attr->disabled = 1; 54162306a36Sopenharmony_ci event_attr->exclude_kernel = 1; 54262306a36Sopenharmony_ci event_attr->exclude_hv = 1; 54362306a36Sopenharmony_ci event_attr->exclude_guest = 1; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciint perf_event_open_counter(unsigned int type, 54762306a36Sopenharmony_ci unsigned long config, int group_fd) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci int fd; 55062306a36Sopenharmony_ci struct perf_event_attr event_attr; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci perf_event_attr_init(&event_attr, type, config); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (fd < 0) 55762306a36Sopenharmony_ci perror("perf_event_open() failed"); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return fd; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ciint perf_event_enable(int fd) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { 56562306a36Sopenharmony_ci perror("error while enabling perf events"); 56662306a36Sopenharmony_ci return -1; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ciint perf_event_disable(int fd) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { 57562306a36Sopenharmony_ci perror("error disabling perf events"); 57662306a36Sopenharmony_ci return -1; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ciint perf_event_reset(int fd) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { 58562306a36Sopenharmony_ci perror("error resetting perf events"); 58662306a36Sopenharmony_ci return -1; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return 0; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciint using_hash_mmu(bool *using_hash) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci char line[128]; 59562306a36Sopenharmony_ci FILE *f; 59662306a36Sopenharmony_ci int rc; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci f = fopen("/proc/cpuinfo", "r"); 59962306a36Sopenharmony_ci FAIL_IF(!f); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci rc = 0; 60262306a36Sopenharmony_ci while (fgets(line, sizeof(line), f) != NULL) { 60362306a36Sopenharmony_ci if (!strcmp(line, "MMU : Hash\n") || 60462306a36Sopenharmony_ci !strcmp(line, "platform : Cell\n") || 60562306a36Sopenharmony_ci !strcmp(line, "platform : PowerMac\n")) { 60662306a36Sopenharmony_ci *using_hash = true; 60762306a36Sopenharmony_ci goto out; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (strcmp(line, "MMU : Radix\n") == 0) { 61162306a36Sopenharmony_ci *using_hash = false; 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci rc = -1; 61762306a36Sopenharmony_ciout: 61862306a36Sopenharmony_ci fclose(f); 61962306a36Sopenharmony_ci return rc; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistruct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *)) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct sigaction sa; 62562306a36Sopenharmony_ci struct sigaction old_handler; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci sa.sa_sigaction = fn; 62862306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 62962306a36Sopenharmony_ci sa.sa_flags = SA_SIGINFO; 63062306a36Sopenharmony_ci FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler), 63162306a36Sopenharmony_ci "failed to push signal handler"); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return old_handler; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistruct sigaction pop_signal_handler(int sig, struct sigaction old_handler) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct sigaction popped; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped), 64162306a36Sopenharmony_ci "failed to pop signal handler"); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return popped; 64462306a36Sopenharmony_ci} 645