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
read_file(const char * path,char * buf,size_t count,size_t * len)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
read_file_alloc(const char * path,char ** buf,size_t * len)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
write_file(const char * path,const char * buf,size_t count)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
read_auxv(char * buf,ssize_t buf_size)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
read_debugfs_file(const char * subpath,char * buf,size_t count)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
write_debugfs_file(const char * subpath,const char * buf,size_t count)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
validate_int_parse(const char * buffer,size_t count,char * end)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
parse_bounded_int(const char * buffer,size_t count,intmax_t * result,int base,intmax_t min,intmax_t max)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
parse_bounded_uint(const char * buffer,size_t count,uintmax_t * result,int base,uintmax_t max)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
parse_intmax(const char * buffer,size_t count,intmax_t * result,int base)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
parse_uintmax(const char * buffer,size_t count,uintmax_t * result,int base)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
parse_int(const char * buffer,size_t count,int * result,int base)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
parse_uint(const char * buffer,size_t count,unsigned int * result,int base)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
parse_long(const char * buffer,size_t count,long * result,int base)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
parse_ulong(const char * buffer,size_t count,unsigned long * result,int base)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
read_long(const char * path,long * result,int base)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
read_ulong(const char * path,unsigned long * result,int base)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
write_long(const char * path,long result,int base)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
write_ulong(const char * path,unsigned long result,int base)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
find_auxv_entry(int type,char * auxv)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
get_auxv_entry(int type)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
pick_online_cpu(void)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
bind_to_cpu(int cpu)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
is_ppc64le(void)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
read_sysfs_file(char * fpath,char * result,size_t result_size)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
read_debugfs_int(const char * debugfs_file,int * result)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
write_debugfs_int(const char * debugfs_file,int result)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
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)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
perf_event_attr_init(struct perf_event_attr * event_attr,unsigned int type,unsigned long config)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
perf_event_open_counter(unsigned int type,unsigned long config,int group_fd)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
perf_event_enable(int fd)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
perf_event_disable(int fd)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
perf_event_reset(int fd)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
using_hash_mmu(bool * using_hash)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
push_signal_handler(int sig,void (* fn)(int,siginfo_t *,void *))622 struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *))
623 {
624 struct sigaction sa;
625 struct sigaction old_handler;
626
627 sa.sa_sigaction = fn;
628 sigemptyset(&sa.sa_mask);
629 sa.sa_flags = SA_SIGINFO;
630 FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler),
631 "failed to push signal handler");
632
633 return old_handler;
634 }
635
pop_signal_handler(int sig,struct sigaction old_handler)636 struct sigaction pop_signal_handler(int sig, struct sigaction old_handler)
637 {
638 struct sigaction popped;
639
640 FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped),
641 "failed to pop signal handler");
642
643 return popped;
644 }
645