GNU Linux-libre 4.14.290-gnu1
[releases.git] / tools / testing / selftests / powerpc / utils.c
1 /*
2  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
3  * Licensed under GPLv2.
4  */
5
6 #define _GNU_SOURCE     /* For CPU_ZERO etc. */
7
8 #include <elf.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <link.h>
12 #include <sched.h>
13 #include <stdio.h>
14 #include <sys/stat.h>
15 #include <sys/sysinfo.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include "utils.h"
20
21 static char auxv[4096];
22
23 int read_auxv(char *buf, ssize_t buf_size)
24 {
25         ssize_t num;
26         int rc, fd;
27
28         fd = open("/proc/self/auxv", O_RDONLY);
29         if (fd == -1) {
30                 perror("open");
31                 return -errno;
32         }
33
34         num = read(fd, buf, buf_size);
35         if (num < 0) {
36                 perror("read");
37                 rc = -EIO;
38                 goto out;
39         }
40
41         if (num > buf_size) {
42                 printf("overflowed auxv buffer\n");
43                 rc = -EOVERFLOW;
44                 goto out;
45         }
46
47         rc = 0;
48 out:
49         close(fd);
50         return rc;
51 }
52
53 void *find_auxv_entry(int type, char *auxv)
54 {
55         ElfW(auxv_t) *p;
56
57         p = (ElfW(auxv_t) *)auxv;
58
59         while (p->a_type != AT_NULL) {
60                 if (p->a_type == type)
61                         return p;
62
63                 p++;
64         }
65
66         return NULL;
67 }
68
69 void *get_auxv_entry(int type)
70 {
71         ElfW(auxv_t) *p;
72
73         if (read_auxv(auxv, sizeof(auxv)))
74                 return NULL;
75
76         p = find_auxv_entry(type, auxv);
77         if (p)
78                 return (void *)p->a_un.a_val;
79
80         return NULL;
81 }
82
83 int pick_online_cpu(void)
84 {
85         int ncpus, cpu = -1;
86         cpu_set_t *mask;
87         size_t size;
88
89         ncpus = get_nprocs_conf();
90         size = CPU_ALLOC_SIZE(ncpus);
91         mask = CPU_ALLOC(ncpus);
92         if (!mask) {
93                 perror("malloc");
94                 return -1;
95         }
96
97         CPU_ZERO_S(size, mask);
98
99         if (sched_getaffinity(0, size, mask)) {
100                 perror("sched_getaffinity");
101                 goto done;
102         }
103
104         /* We prefer a primary thread, but skip 0 */
105         for (cpu = 8; cpu < ncpus; cpu += 8)
106                 if (CPU_ISSET_S(cpu, size, mask))
107                         goto done;
108
109         /* Search for anything, but in reverse */
110         for (cpu = ncpus - 1; cpu >= 0; cpu--)
111                 if (CPU_ISSET_S(cpu, size, mask))
112                         goto done;
113
114         printf("No cpus in affinity mask?!\n");
115
116 done:
117         CPU_FREE(mask);
118         return cpu;
119 }