638ffacc90aa18283e807e4f9d6fe3a2c272aa24
[linux-2.6-microblaze.git] / tools / testing / selftests / powerpc / utils.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
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 <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18 #include <sys/stat.h>
19 #include <sys/sysinfo.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
22 #include <unistd.h>
23 #include <asm/unistd.h>
24 #include <linux/limits.h>
25
26 #include "utils.h"
27
28 static char auxv[4096];
29
30 int read_auxv(char *buf, ssize_t buf_size)
31 {
32         ssize_t num;
33         int rc, fd;
34
35         fd = open("/proc/self/auxv", O_RDONLY);
36         if (fd == -1) {
37                 perror("open");
38                 return -errno;
39         }
40
41         num = read(fd, buf, buf_size);
42         if (num < 0) {
43                 perror("read");
44                 rc = -EIO;
45                 goto out;
46         }
47
48         if (num > buf_size) {
49                 printf("overflowed auxv buffer\n");
50                 rc = -EOVERFLOW;
51                 goto out;
52         }
53
54         rc = 0;
55 out:
56         close(fd);
57         return rc;
58 }
59
60 void *find_auxv_entry(int type, char *auxv)
61 {
62         ElfW(auxv_t) *p;
63
64         p = (ElfW(auxv_t) *)auxv;
65
66         while (p->a_type != AT_NULL) {
67                 if (p->a_type == type)
68                         return p;
69
70                 p++;
71         }
72
73         return NULL;
74 }
75
76 void *get_auxv_entry(int type)
77 {
78         ElfW(auxv_t) *p;
79
80         if (read_auxv(auxv, sizeof(auxv)))
81                 return NULL;
82
83         p = find_auxv_entry(type, auxv);
84         if (p)
85                 return (void *)p->a_un.a_val;
86
87         return NULL;
88 }
89
90 int pick_online_cpu(void)
91 {
92         int ncpus, cpu = -1;
93         cpu_set_t *mask;
94         size_t size;
95
96         ncpus = get_nprocs_conf();
97         size = CPU_ALLOC_SIZE(ncpus);
98         mask = CPU_ALLOC(ncpus);
99         if (!mask) {
100                 perror("malloc");
101                 return -1;
102         }
103
104         CPU_ZERO_S(size, mask);
105
106         if (sched_getaffinity(0, size, mask)) {
107                 perror("sched_getaffinity");
108                 goto done;
109         }
110
111         /* We prefer a primary thread, but skip 0 */
112         for (cpu = 8; cpu < ncpus; cpu += 8)
113                 if (CPU_ISSET_S(cpu, size, mask))
114                         goto done;
115
116         /* Search for anything, but in reverse */
117         for (cpu = ncpus - 1; cpu >= 0; cpu--)
118                 if (CPU_ISSET_S(cpu, size, mask))
119                         goto done;
120
121         printf("No cpus in affinity mask?!\n");
122
123 done:
124         CPU_FREE(mask);
125         return cpu;
126 }
127
128 bool is_ppc64le(void)
129 {
130         struct utsname uts;
131         int rc;
132
133         errno = 0;
134         rc = uname(&uts);
135         if (rc) {
136                 perror("uname");
137                 return false;
138         }
139
140         return strcmp(uts.machine, "ppc64le") == 0;
141 }
142
143 int read_sysfs_file(char *fpath, char *result, size_t result_size)
144 {
145         char path[PATH_MAX] = "/sys/";
146         int rc = -1, fd;
147
148         strncat(path, fpath, PATH_MAX - strlen(path) - 1);
149
150         if ((fd = open(path, O_RDONLY)) < 0)
151                 return rc;
152
153         rc = read(fd, result, result_size);
154
155         close(fd);
156
157         if (rc < 0)
158                 return rc;
159
160         return 0;
161 }
162
163 int read_debugfs_file(char *debugfs_file, int *result)
164 {
165         int rc = -1, fd;
166         char path[PATH_MAX];
167         char value[16];
168
169         strcpy(path, "/sys/kernel/debug/");
170         strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
171
172         if ((fd = open(path, O_RDONLY)) < 0)
173                 return rc;
174
175         if ((rc = read(fd, value, sizeof(value))) < 0)
176                 return rc;
177
178         value[15] = 0;
179         *result = atoi(value);
180         close(fd);
181
182         return 0;
183 }
184
185 int write_debugfs_file(char *debugfs_file, int result)
186 {
187         int rc = -1, fd;
188         char path[PATH_MAX];
189         char value[16];
190
191         strcpy(path, "/sys/kernel/debug/");
192         strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
193
194         if ((fd = open(path, O_WRONLY)) < 0)
195                 return rc;
196
197         snprintf(value, 16, "%d", result);
198
199         if ((rc = write(fd, value, strlen(value))) < 0)
200                 return rc;
201
202         close(fd);
203
204         return 0;
205 }
206
207 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
208                 int cpu, int group_fd, unsigned long flags)
209 {
210         return syscall(__NR_perf_event_open, hw_event, pid, cpu,
211                       group_fd, flags);
212 }
213
214 static void perf_event_attr_init(struct perf_event_attr *event_attr,
215                                         unsigned int type,
216                                         unsigned long config)
217 {
218         memset(event_attr, 0, sizeof(*event_attr));
219
220         event_attr->type = type;
221         event_attr->size = sizeof(struct perf_event_attr);
222         event_attr->config = config;
223         event_attr->read_format = PERF_FORMAT_GROUP;
224         event_attr->disabled = 1;
225         event_attr->exclude_kernel = 1;
226         event_attr->exclude_hv = 1;
227         event_attr->exclude_guest = 1;
228 }
229
230 int perf_event_open_counter(unsigned int type,
231                             unsigned long config, int group_fd)
232 {
233         int fd;
234         struct perf_event_attr event_attr;
235
236         perf_event_attr_init(&event_attr, type, config);
237
238         fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
239
240         if (fd < 0)
241                 perror("perf_event_open() failed");
242
243         return fd;
244 }
245
246 int perf_event_enable(int fd)
247 {
248         if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
249                 perror("error while enabling perf events");
250                 return -1;
251         }
252
253         return 0;
254 }
255
256 int perf_event_disable(int fd)
257 {
258         if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
259                 perror("error disabling perf events");
260                 return -1;
261         }
262
263         return 0;
264 }
265
266 int perf_event_reset(int fd)
267 {
268         if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
269                 perror("error resetting perf events");
270                 return -1;
271         }
272
273         return 0;
274 }
275
276 static void sigill_handler(int signr, siginfo_t *info, void *unused)
277 {
278         static int warned = 0;
279         ucontext_t *ctx = (ucontext_t *)unused;
280         unsigned long *pc = &UCONTEXT_NIA(ctx);
281
282         /* mtspr 3,RS to check for move to DSCR below */
283         if ((*((unsigned int *)*pc) & 0xfc1fffff) == 0x7c0303a6) {
284                 if (!warned++)
285                         printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
286                 *pc += 4;
287         } else {
288                 printf("SIGILL at %p\n", pc);
289                 abort();
290         }
291 }
292
293 void set_dscr(unsigned long val)
294 {
295         static int init = 0;
296         struct sigaction sa;
297
298         if (!init) {
299                 memset(&sa, 0, sizeof(sa));
300                 sa.sa_sigaction = sigill_handler;
301                 sa.sa_flags = SA_SIGINFO;
302                 if (sigaction(SIGILL, &sa, NULL))
303                         perror("sigill_handler");
304                 init = 1;
305         }
306
307         asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
308 }
309
310 int using_hash_mmu(bool *using_hash)
311 {
312         char line[128];
313         FILE *f;
314         int rc;
315
316         f = fopen("/proc/cpuinfo", "r");
317         FAIL_IF(!f);
318
319         rc = 0;
320         while (fgets(line, sizeof(line), f) != NULL) {
321                 if (!strcmp(line, "MMU          : Hash\n") ||
322                     !strcmp(line, "platform     : Cell\n") ||
323                     !strcmp(line, "platform     : PowerMac\n")) {
324                         *using_hash = true;
325                         goto out;
326                 }
327
328                 if (strcmp(line, "MMU           : Radix\n") == 0) {
329                         *using_hash = false;
330                         goto out;
331                 }
332         }
333
334         rc = -1;
335 out:
336         fclose(f);
337         return rc;
338 }