Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645// SPDX-License-Identifier: GPL-2.0-only/* * Copyright 2013-2015, Michael Ellerman, IBM Corp. */
#define _GNU_SOURCE /* For CPU_ZERO etc. */
#include <elf.h>#include <errno.h>#include <fcntl.h>#include <inttypes.h>#include <limits.h>#include <link.h>#include <sched.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/sysinfo.h>#include <sys/types.h>#include <sys/utsname.h>#include <unistd.h>#include <asm/unistd.h>#include <linux/limits.h>
#include "utils.h"
static char auxv[4096];
int read_file(const char *path, char *buf, size_t count, size_t *len){ ssize_t rc; int fd; int err; char eof;
fd = open(path, O_RDONLY); if (fd < 0) return -errno;
rc = read(fd, buf, count); if (rc < 0) { err = -errno; goto out; }
if (len) *len = rc;
/* Overflow if there are still more bytes after filling the buffer */ if (rc == count) { rc = read(fd, &eof, 1); if (rc != 0) { err = -EOVERFLOW; goto out; } }
err = 0;
out: close(fd); errno = -err; return err;}
int read_file_alloc(const char *path, char **buf, size_t *len){ size_t read_offset = 0; size_t buffer_len = 0; char *buffer = NULL; int err; int fd;
fd = open(path, O_RDONLY); if (fd < 0) return -errno;
/* * We don't use stat & preallocate st_size because some non-files * report 0 file size. Instead just dynamically grow the buffer * as needed. */ while (1) { ssize_t rc;
if (read_offset >= buffer_len / 2) { char *next_buffer;
buffer_len = buffer_len ? buffer_len * 2 : 4096; next_buffer = realloc(buffer, buffer_len); if (!next_buffer) { err = -errno; goto out; } buffer = next_buffer; }
rc = read(fd, buffer + read_offset, buffer_len - read_offset); if (rc < 0) { err = -errno; goto out; }
if (rc == 0) break;
read_offset += rc; }
*buf = buffer; if (len) *len = read_offset;
err = 0;
out: close(fd); if (err) free(buffer); errno = -err; return err;}
int write_file(const char *path, const char *buf, size_t count){ int fd; int err; ssize_t rc;
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) return -errno;
rc = write(fd, buf, count); if (rc < 0) { err = -errno; goto out; }
if (rc != count) { err = -EOVERFLOW; goto out; }
err = 0;
out: close(fd); errno = -err; return err;}
int read_auxv(char *buf, ssize_t buf_size){ int err;
err = read_file("/proc/self/auxv", buf, buf_size, NULL); if (err) { perror("Error reading /proc/self/auxv"); return err; }
return 0;}
int read_debugfs_file(const char *subpath, char *buf, size_t count){ char path[PATH_MAX] = "/sys/kernel/debug/";
strncat(path, subpath, sizeof(path) - strlen(path) - 1);
return read_file(path, buf, count, NULL);}
int write_debugfs_file(const char *subpath, const char *buf, size_t count){ char path[PATH_MAX] = "/sys/kernel/debug/";
strncat(path, subpath, sizeof(path) - strlen(path) - 1);
return write_file(path, buf, count);}
static int validate_int_parse(const char *buffer, size_t count, char *end){ int err = 0;
/* Require at least one digit */ if (end == buffer) { err = -EINVAL; goto out; }
/* Require all remaining characters be whitespace-ish */ for (; end < buffer + count; end++) { if (*end == '\0') break;
if (*end != ' ' && *end != '\n') { err = -EINVAL; goto out; } }
out: errno = -err; return err;}
static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result, int base, intmax_t min, intmax_t max){ int err; char *end;
errno = 0; *result = strtoimax(buffer, &end, base);
if (errno) return -errno;
err = validate_int_parse(buffer, count, end); if (err) goto out;
if (*result < min || *result > max) err = -EOVERFLOW;
out: errno = -err; return err;}
static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result, int base, uintmax_t max){ int err = 0; char *end;
errno = 0; *result = strtoumax(buffer, &end, base);
if (errno) return -errno;
err = validate_int_parse(buffer, count, end); if (err) goto out;
if (*result > max) err = -EOVERFLOW;
out: errno = -err; return err;}
int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base){ return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);}
int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base){ return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);}
int parse_int(const char *buffer, size_t count, int *result, int base){ intmax_t parsed; int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
*result = parsed; return err;}
int parse_uint(const char *buffer, size_t count, unsigned int *result, int base){ uintmax_t parsed; int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
*result = parsed; return err;}
int parse_long(const char *buffer, size_t count, long *result, int base){ intmax_t parsed; int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
*result = parsed; return err;}
int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base){ uintmax_t parsed; int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
*result = parsed; return err;}
int read_long(const char *path, long *result, int base){ int err; char buffer[32] = {0};
err = read_file(path, buffer, sizeof(buffer) - 1, NULL); if (err) return err;
return parse_long(buffer, sizeof(buffer), result, base);}
int read_ulong(const char *path, unsigned long *result, int base){ int err; char buffer[32] = {0};
err = read_file(path, buffer, sizeof(buffer) - 1, NULL); if (err) return err;
return parse_ulong(buffer, sizeof(buffer), result, base);}
int write_long(const char *path, long result, int base){ int err; int len; char buffer[32];
/* Decimal only for now: no format specifier for signed hex values */ if (base != 10) { err = -EINVAL; goto out; }
len = snprintf(buffer, sizeof(buffer), "%ld", result); if (len < 0 || len >= sizeof(buffer)) { err = -EOVERFLOW; goto out; }
err = write_file(path, buffer, len);
out: errno = -err; return err;}
int write_ulong(const char *path, unsigned long result, int base){ int err; int len; char buffer[32]; char *fmt;
switch (base) { case 10: fmt = "%lu"; break; case 16: fmt = "%lx"; break; default: err = -EINVAL; goto out; }
len = snprintf(buffer, sizeof(buffer), fmt, result); if (len < 0 || len >= sizeof(buffer)) { err = -errno; goto out; }
err = write_file(path, buffer, len);
out: errno = -err; return err;}
void *find_auxv_entry(int type, char *auxv){ ElfW(auxv_t) *p;
p = (ElfW(auxv_t) *)auxv;
while (p->a_type != AT_NULL) { if (p->a_type == type) return p;
p++; }
return NULL;}
void *get_auxv_entry(int type){ ElfW(auxv_t) *p;
if (read_auxv(auxv, sizeof(auxv))) return NULL;
p = find_auxv_entry(type, auxv); if (p) return (void *)p->a_un.a_val;
return NULL;}
int pick_online_cpu(void){ int ncpus, cpu = -1; cpu_set_t *mask; size_t size;
ncpus = get_nprocs_conf(); size = CPU_ALLOC_SIZE(ncpus); mask = CPU_ALLOC(ncpus); if (!mask) { perror("malloc"); return -1; }
CPU_ZERO_S(size, mask);
if (sched_getaffinity(0, size, mask)) { perror("sched_getaffinity"); goto done; }
/* We prefer a primary thread, but skip 0 */ for (cpu = 8; cpu < ncpus; cpu += 8) if (CPU_ISSET_S(cpu, size, mask)) goto done;
/* Search for anything, but in reverse */ for (cpu = ncpus - 1; cpu >= 0; cpu--) if (CPU_ISSET_S(cpu, size, mask)) goto done;
printf("No cpus in affinity mask?!\n");
done: CPU_FREE(mask); return cpu;}
int bind_to_cpu(int cpu){ cpu_set_t mask; int err;
if (cpu == BIND_CPU_ANY) { cpu = pick_online_cpu(); if (cpu < 0) return cpu; }
printf("Binding to cpu %d\n", cpu);
CPU_ZERO(&mask); CPU_SET(cpu, &mask);
err = sched_setaffinity(0, sizeof(mask), &mask); if (err) return err;
return cpu;}
bool is_ppc64le(void){ struct utsname uts; int rc;
errno = 0; rc = uname(&uts); if (rc) { perror("uname"); return false; }
return strcmp(uts.machine, "ppc64le") == 0;}
int read_sysfs_file(char *fpath, char *result, size_t result_size){ char path[PATH_MAX] = "/sys/";
strncat(path, fpath, PATH_MAX - strlen(path) - 1);
return read_file(path, result, result_size, NULL);}
int read_debugfs_int(const char *debugfs_file, int *result){ int err; char value[16] = {0};
err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1); if (err) return err;
return parse_int(value, sizeof(value), result, 10);}
int write_debugfs_int(const char *debugfs_file, int result){ char value[16];
snprintf(value, 16, "%d", result);
return write_debugfs_file(debugfs_file, value, strlen(value));}
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags){ return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);}
static void perf_event_attr_init(struct perf_event_attr *event_attr, unsigned int type, unsigned long config){ memset(event_attr, 0, sizeof(*event_attr));
event_attr->type = type; event_attr->size = sizeof(struct perf_event_attr); event_attr->config = config; event_attr->read_format = PERF_FORMAT_GROUP; event_attr->disabled = 1; event_attr->exclude_kernel = 1; event_attr->exclude_hv = 1; event_attr->exclude_guest = 1;}
int perf_event_open_counter(unsigned int type, unsigned long config, int group_fd){ int fd; struct perf_event_attr event_attr;
perf_event_attr_init(&event_attr, type, config);
fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
if (fd < 0) perror("perf_event_open() failed");
return fd;}
int perf_event_enable(int fd){ if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { perror("error while enabling perf events"); return -1; }
return 0;}
int perf_event_disable(int fd){ if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { perror("error disabling perf events"); return -1; }
return 0;}
int perf_event_reset(int fd){ if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { perror("error resetting perf events"); return -1; }
return 0;}
int using_hash_mmu(bool *using_hash){ char line[128]; FILE *f; int rc;
f = fopen("/proc/cpuinfo", "r"); FAIL_IF(!f);
rc = 0; while (fgets(line, sizeof(line), f) != NULL) { if (!strcmp(line, "MMU : Hash\n") || !strcmp(line, "platform : Cell\n") || !strcmp(line, "platform : PowerMac\n")) { *using_hash = true; goto out; }
if (strcmp(line, "MMU : Radix\n") == 0) { *using_hash = false; goto out; } }
rc = -1;out: fclose(f); return rc;}
struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *)){ struct sigaction sa; struct sigaction old_handler;
sa.sa_sigaction = fn; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler), "failed to push signal handler");
return old_handler;}
struct sigaction pop_signal_handler(int sig, struct sigaction old_handler){ struct sigaction popped;
FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped), "failed to pop signal handler");
return popped;}