~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/utils.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <inttypes.h>
 12 #include <limits.h>
 13 #include <link.h>
 14 #include <sched.h>
 15 #include <stdio.h>
 16 #include <stdlib.h>
 17 #include <string.h>
 18 #include <sys/ioctl.h>
 19 #include <sys/stat.h>
 20 #include <sys/sysinfo.h>
 21 #include <sys/types.h>
 22 #include <sys/utsname.h>
 23 #include <unistd.h>
 24 #include <asm/unistd.h>
 25 #include <linux/limits.h>
 26 
 27 #include "utils.h"
 28 
 29 static char auxv[4096];
 30 
 31 int read_file(const char *path, char *buf, size_t count, size_t *len)
 32 {
 33         ssize_t rc;
 34         int fd;
 35         int err;
 36         char eof;
 37 
 38         fd = open(path, O_RDONLY);
 39         if (fd < 0)
 40                 return -errno;
 41 
 42         rc = read(fd, buf, count);
 43         if (rc < 0) {
 44                 err = -errno;
 45                 goto out;
 46         }
 47 
 48         if (len)
 49                 *len = rc;
 50 
 51         /* Overflow if there are still more bytes after filling the buffer */
 52         if (rc == count) {
 53                 rc = read(fd, &eof, 1);
 54                 if (rc != 0) {
 55                         err = -EOVERFLOW;
 56                         goto out;
 57                 }
 58         }
 59 
 60         err = 0;
 61 
 62 out:
 63         close(fd);
 64         errno = -err;
 65         return err;
 66 }
 67 
 68 int read_file_alloc(const char *path, char **buf, size_t *len)
 69 {
 70         size_t read_offset = 0;
 71         size_t buffer_len = 0;
 72         char *buffer = NULL;
 73         int err;
 74         int fd;
 75 
 76         fd = open(path, O_RDONLY);
 77         if (fd < 0)
 78                 return -errno;
 79 
 80         /*
 81          * We don't use stat & preallocate st_size because some non-files
 82          * report 0 file size. Instead just dynamically grow the buffer
 83          * as needed.
 84          */
 85         while (1) {
 86                 ssize_t rc;
 87 
 88                 if (read_offset >= buffer_len / 2) {
 89                         char *next_buffer;
 90 
 91                         buffer_len = buffer_len ? buffer_len * 2 : 4096;
 92                         next_buffer = realloc(buffer, buffer_len);
 93                         if (!next_buffer) {
 94                                 err = -errno;
 95                                 goto out;
 96                         }
 97                         buffer = next_buffer;
 98                 }
 99 
100                 rc = read(fd, buffer + read_offset, buffer_len - read_offset);
101                 if (rc < 0) {
102                         err = -errno;
103                         goto out;
104                 }
105 
106                 if (rc == 0)
107                         break;
108 
109                 read_offset += rc;
110         }
111 
112         *buf = buffer;
113         if (len)
114                 *len = read_offset;
115 
116         err = 0;
117 
118 out:
119         close(fd);
120         if (err)
121                 free(buffer);
122         errno = -err;
123         return err;
124 }
125 
126 int write_file(const char *path, const char *buf, size_t count)
127 {
128         int fd;
129         int err;
130         ssize_t rc;
131 
132         fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
133         if (fd < 0)
134                 return -errno;
135 
136         rc = write(fd, buf, count);
137         if (rc < 0) {
138                 err = -errno;
139                 goto out;
140         }
141 
142         if (rc != count) {
143                 err = -EOVERFLOW;
144                 goto out;
145         }
146 
147         err = 0;
148 
149 out:
150         close(fd);
151         errno = -err;
152         return err;
153 }
154 
155 int read_auxv(char *buf, ssize_t buf_size)
156 {
157         int err;
158 
159         err = read_file("/proc/self/auxv", buf, buf_size, NULL);
160         if (err) {
161                 perror("Error reading /proc/self/auxv");
162                 return err;
163         }
164 
165         return 0;
166 }
167 
168 int read_debugfs_file(const char *subpath, char *buf, size_t count)
169 {
170         char path[PATH_MAX] = "/sys/kernel/debug/";
171 
172         strncat(path, subpath, sizeof(path) - strlen(path) - 1);
173 
174         return read_file(path, buf, count, NULL);
175 }
176 
177 int write_debugfs_file(const char *subpath, const char *buf, size_t count)
178 {
179         char path[PATH_MAX] = "/sys/kernel/debug/";
180 
181         strncat(path, subpath, sizeof(path) - strlen(path) - 1);
182 
183         return write_file(path, buf, count);
184 }
185 
186 static int validate_int_parse(const char *buffer, size_t count, char *end)
187 {
188         int err = 0;
189 
190         /* Require at least one digit */
191         if (end == buffer) {
192                 err = -EINVAL;
193                 goto out;
194         }
195 
196         /* Require all remaining characters be whitespace-ish */
197         for (; end < buffer + count; end++) {
198                 if (*end == '\0')
199                         break;
200 
201                 if (*end != ' ' && *end != '\n') {
202                         err = -EINVAL;
203                         goto out;
204                 }
205         }
206 
207 out:
208         errno = -err;
209         return err;
210 }
211 
212 static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
213                              int base, intmax_t min, intmax_t max)
214 {
215         int err;
216         char *end;
217 
218         errno = 0;
219         *result = strtoimax(buffer, &end, base);
220 
221         if (errno)
222                 return -errno;
223 
224         err = validate_int_parse(buffer, count, end);
225         if (err)
226                 goto out;
227 
228         if (*result < min || *result > max)
229                 err = -EOVERFLOW;
230 
231 out:
232         errno = -err;
233         return err;
234 }
235 
236 static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
237                               int base, uintmax_t max)
238 {
239         int err = 0;
240         char *end;
241 
242         errno = 0;
243         *result = strtoumax(buffer, &end, base);
244 
245         if (errno)
246                 return -errno;
247 
248         err = validate_int_parse(buffer, count, end);
249         if (err)
250                 goto out;
251 
252         if (*result > max)
253                 err = -EOVERFLOW;
254 
255 out:
256         errno = -err;
257         return err;
258 }
259 
260 int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
261 {
262         return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
263 }
264 
265 int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
266 {
267         return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
268 }
269 
270 int parse_int(const char *buffer, size_t count, int *result, int base)
271 {
272         intmax_t parsed;
273         int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
274 
275         *result = parsed;
276         return err;
277 }
278 
279 int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
280 {
281         uintmax_t parsed;
282         int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
283 
284         *result = parsed;
285         return err;
286 }
287 
288 int parse_long(const char *buffer, size_t count, long *result, int base)
289 {
290         intmax_t parsed;
291         int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
292 
293         *result = parsed;
294         return err;
295 }
296 
297 int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
298 {
299         uintmax_t parsed;
300         int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
301 
302         *result = parsed;
303         return err;
304 }
305 
306 int read_long(const char *path, long *result, int base)
307 {
308         int err;
309         char buffer[32] = {0};
310 
311         err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
312         if (err)
313                 return err;
314 
315         return parse_long(buffer, sizeof(buffer), result, base);
316 }
317 
318 int read_ulong(const char *path, unsigned long *result, int base)
319 {
320         int err;
321         char buffer[32] = {0};
322 
323         err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
324         if (err)
325                 return err;
326 
327         return parse_ulong(buffer, sizeof(buffer), result, base);
328 }
329 
330 int write_long(const char *path, long result, int base)
331 {
332         int err;
333         int len;
334         char buffer[32];
335 
336         /* Decimal only for now: no format specifier for signed hex values */
337         if (base != 10) {
338                 err = -EINVAL;
339                 goto out;
340         }
341 
342         len = snprintf(buffer, sizeof(buffer), "%ld", result);
343         if (len < 0 || len >= sizeof(buffer)) {
344                 err = -EOVERFLOW;
345                 goto out;
346         }
347 
348         err = write_file(path, buffer, len);
349 
350 out:
351         errno = -err;
352         return err;
353 }
354 
355 int write_ulong(const char *path, unsigned long result, int base)
356 {
357         int err;
358         int len;
359         char buffer[32];
360         char *fmt;
361 
362         switch (base) {
363         case 10:
364                 fmt = "%lu";
365                 break;
366         case 16:
367                 fmt = "%lx";
368                 break;
369         default:
370                 err = -EINVAL;
371                 goto out;
372         }
373 
374         len = snprintf(buffer, sizeof(buffer), fmt, result);
375         if (len < 0 || len >= sizeof(buffer)) {
376                 err = -errno;
377                 goto out;
378         }
379 
380         err = write_file(path, buffer, len);
381 
382 out:
383         errno = -err;
384         return err;
385 }
386 
387 void *find_auxv_entry(int type, char *auxv)
388 {
389         ElfW(auxv_t) *p;
390 
391         p = (ElfW(auxv_t) *)auxv;
392 
393         while (p->a_type != AT_NULL) {
394                 if (p->a_type == type)
395                         return p;
396 
397                 p++;
398         }
399 
400         return NULL;
401 }
402 
403 void *get_auxv_entry(int type)
404 {
405         ElfW(auxv_t) *p;
406 
407         if (read_auxv(auxv, sizeof(auxv)))
408                 return NULL;
409 
410         p = find_auxv_entry(type, auxv);
411         if (p)
412                 return (void *)p->a_un.a_val;
413 
414         return NULL;
415 }
416 
417 int pick_online_cpu(void)
418 {
419         int ncpus, cpu = -1;
420         cpu_set_t *mask;
421         size_t size;
422 
423         ncpus = get_nprocs_conf();
424         size = CPU_ALLOC_SIZE(ncpus);
425         mask = CPU_ALLOC(ncpus);
426         if (!mask) {
427                 perror("malloc");
428                 return -1;
429         }
430 
431         CPU_ZERO_S(size, mask);
432 
433         if (sched_getaffinity(0, size, mask)) {
434                 perror("sched_getaffinity");
435                 goto done;
436         }
437 
438         /* We prefer a primary thread, but skip 0 */
439         for (cpu = 8; cpu < ncpus; cpu += 8)
440                 if (CPU_ISSET_S(cpu, size, mask))
441                         goto done;
442 
443         /* Search for anything, but in reverse */
444         for (cpu = ncpus - 1; cpu >= 0; cpu--)
445                 if (CPU_ISSET_S(cpu, size, mask))
446                         goto done;
447 
448         printf("No cpus in affinity mask?!\n");
449 
450 done:
451         CPU_FREE(mask);
452         return cpu;
453 }
454 
455 int bind_to_cpu(int cpu)
456 {
457         cpu_set_t mask;
458         int err;
459 
460         if (cpu == BIND_CPU_ANY) {
461                 cpu = pick_online_cpu();
462                 if (cpu < 0)
463                         return cpu;
464         }
465 
466         printf("Binding to cpu %d\n", cpu);
467 
468         CPU_ZERO(&mask);
469         CPU_SET(cpu, &mask);
470 
471         err = sched_setaffinity(0, sizeof(mask), &mask);
472         if (err)
473                 return err;
474 
475         return cpu;
476 }
477 
478 bool is_ppc64le(void)
479 {
480         struct utsname uts;
481         int rc;
482 
483         errno = 0;
484         rc = uname(&uts);
485         if (rc) {
486                 perror("uname");
487                 return false;
488         }
489 
490         return strcmp(uts.machine, "ppc64le") == 0;
491 }
492 
493 int read_sysfs_file(char *fpath, char *result, size_t result_size)
494 {
495         char path[PATH_MAX] = "/sys/";
496 
497         strncat(path, fpath, PATH_MAX - strlen(path) - 1);
498 
499         return read_file(path, result, result_size, NULL);
500 }
501 
502 int read_debugfs_int(const char *debugfs_file, int *result)
503 {
504         int err;
505         char value[16] = {0};
506 
507         err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
508         if (err)
509                 return err;
510 
511         return parse_int(value, sizeof(value), result, 10);
512 }
513 
514 int write_debugfs_int(const char *debugfs_file, int result)
515 {
516         char value[16];
517 
518         snprintf(value, 16, "%d", result);
519 
520         return write_debugfs_file(debugfs_file, value, strlen(value));
521 }
522 
523 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
524                 int cpu, int group_fd, unsigned long flags)
525 {
526         return syscall(__NR_perf_event_open, hw_event, pid, cpu,
527                       group_fd, flags);
528 }
529 
530 static void perf_event_attr_init(struct perf_event_attr *event_attr,
531                                         unsigned int type,
532                                         unsigned long config)
533 {
534         memset(event_attr, 0, sizeof(*event_attr));
535 
536         event_attr->type = type;
537         event_attr->size = sizeof(struct perf_event_attr);
538         event_attr->config = config;
539         event_attr->read_format = PERF_FORMAT_GROUP;
540         event_attr->disabled = 1;
541         event_attr->exclude_kernel = 1;
542         event_attr->exclude_hv = 1;
543         event_attr->exclude_guest = 1;
544 }
545 
546 int perf_event_open_counter(unsigned int type,
547                             unsigned long config, int group_fd)
548 {
549         int fd;
550         struct perf_event_attr event_attr;
551 
552         perf_event_attr_init(&event_attr, type, config);
553 
554         fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
555 
556         if (fd < 0)
557                 perror("perf_event_open() failed");
558 
559         return fd;
560 }
561 
562 int perf_event_enable(int fd)
563 {
564         if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
565                 perror("error while enabling perf events");
566                 return -1;
567         }
568 
569         return 0;
570 }
571 
572 int perf_event_disable(int fd)
573 {
574         if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
575                 perror("error disabling perf events");
576                 return -1;
577         }
578 
579         return 0;
580 }
581 
582 int perf_event_reset(int fd)
583 {
584         if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
585                 perror("error resetting perf events");
586                 return -1;
587         }
588 
589         return 0;
590 }
591 
592 int using_hash_mmu(bool *using_hash)
593 {
594         char line[128];
595         FILE *f;
596         int rc;
597 
598         f = fopen("/proc/cpuinfo", "r");
599         FAIL_IF(!f);
600 
601         rc = 0;
602         while (fgets(line, sizeof(line), f) != NULL) {
603                 if (!strcmp(line, "MMU          : Hash\n") ||
604                     !strcmp(line, "platform     : Cell\n") ||
605                     !strcmp(line, "platform     : PowerMac\n")) {
606                         *using_hash = true;
607                         goto out;
608                 }
609 
610                 if (strcmp(line, "MMU           : Radix\n") == 0) {
611                         *using_hash = false;
612                         goto out;
613                 }
614         }
615 
616         rc = -1;
617 out:
618         fclose(f);
619         return rc;
620 }
621 
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 
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php