GNU Linux-libre 4.19.264-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 <string.h>
15 #include <sys/stat.h>
16 #include <sys/sysinfo.h>
17 #include <sys/types.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20
21 #include "utils.h"
22
23 static char auxv[4096];
24
25 int read_auxv(char *buf, ssize_t buf_size)
26 {
27         ssize_t num;
28         int rc, fd;
29
30         fd = open("/proc/self/auxv", O_RDONLY);
31         if (fd == -1) {
32                 perror("open");
33                 return -errno;
34         }
35
36         num = read(fd, buf, buf_size);
37         if (num < 0) {
38                 perror("read");
39                 rc = -EIO;
40                 goto out;
41         }
42
43         if (num > buf_size) {
44                 printf("overflowed auxv buffer\n");
45                 rc = -EOVERFLOW;
46                 goto out;
47         }
48
49         rc = 0;
50 out:
51         close(fd);
52         return rc;
53 }
54
55 void *find_auxv_entry(int type, char *auxv)
56 {
57         ElfW(auxv_t) *p;
58
59         p = (ElfW(auxv_t) *)auxv;
60
61         while (p->a_type != AT_NULL) {
62                 if (p->a_type == type)
63                         return p;
64
65                 p++;
66         }
67
68         return NULL;
69 }
70
71 void *get_auxv_entry(int type)
72 {
73         ElfW(auxv_t) *p;
74
75         if (read_auxv(auxv, sizeof(auxv)))
76                 return NULL;
77
78         p = find_auxv_entry(type, auxv);
79         if (p)
80                 return (void *)p->a_un.a_val;
81
82         return NULL;
83 }
84
85 int pick_online_cpu(void)
86 {
87         int ncpus, cpu = -1;
88         cpu_set_t *mask;
89         size_t size;
90
91         ncpus = get_nprocs_conf();
92         size = CPU_ALLOC_SIZE(ncpus);
93         mask = CPU_ALLOC(ncpus);
94         if (!mask) {
95                 perror("malloc");
96                 return -1;
97         }
98
99         CPU_ZERO_S(size, mask);
100
101         if (sched_getaffinity(0, size, mask)) {
102                 perror("sched_getaffinity");
103                 goto done;
104         }
105
106         /* We prefer a primary thread, but skip 0 */
107         for (cpu = 8; cpu < ncpus; cpu += 8)
108                 if (CPU_ISSET_S(cpu, size, mask))
109                         goto done;
110
111         /* Search for anything, but in reverse */
112         for (cpu = ncpus - 1; cpu >= 0; cpu--)
113                 if (CPU_ISSET_S(cpu, size, mask))
114                         goto done;
115
116         printf("No cpus in affinity mask?!\n");
117
118 done:
119         CPU_FREE(mask);
120         return cpu;
121 }
122
123 bool is_ppc64le(void)
124 {
125         struct utsname uts;
126         int rc;
127
128         errno = 0;
129         rc = uname(&uts);
130         if (rc) {
131                 perror("uname");
132                 return false;
133         }
134
135         return strcmp(uts.machine, "ppc64le") == 0;
136 }