root/tools/testing/selftests/powerpc/utils.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_auxv
  2. find_auxv_entry
  3. get_auxv_entry
  4. pick_online_cpu
  5. is_ppc64le
  6. read_debugfs_file
  7. write_debugfs_file
  8. perf_event_open
  9. perf_event_attr_init
  10. perf_event_open_counter
  11. perf_event_enable
  12. perf_event_disable
  13. perf_event_reset
  14. sigill_handler
  15. set_dscr

   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/types.h>
  20 #include <sys/utsname.h>
  21 #include <unistd.h>
  22 #include <asm/unistd.h>
  23 #include <linux/limits.h>
  24 
  25 #include "utils.h"
  26 
  27 static char auxv[4096];
  28 
  29 int read_auxv(char *buf, ssize_t buf_size)
  30 {
  31         ssize_t num;
  32         int rc, fd;
  33 
  34         fd = open("/proc/self/auxv", O_RDONLY);
  35         if (fd == -1) {
  36                 perror("open");
  37                 return -errno;
  38         }
  39 
  40         num = read(fd, buf, buf_size);
  41         if (num < 0) {
  42                 perror("read");
  43                 rc = -EIO;
  44                 goto out;
  45         }
  46 
  47         if (num > buf_size) {
  48                 printf("overflowed auxv buffer\n");
  49                 rc = -EOVERFLOW;
  50                 goto out;
  51         }
  52 
  53         rc = 0;
  54 out:
  55         close(fd);
  56         return rc;
  57 }
  58 
  59 void *find_auxv_entry(int type, char *auxv)
  60 {
  61         ElfW(auxv_t) *p;
  62 
  63         p = (ElfW(auxv_t) *)auxv;
  64 
  65         while (p->a_type != AT_NULL) {
  66                 if (p->a_type == type)
  67                         return p;
  68 
  69                 p++;
  70         }
  71 
  72         return NULL;
  73 }
  74 
  75 void *get_auxv_entry(int type)
  76 {
  77         ElfW(auxv_t) *p;
  78 
  79         if (read_auxv(auxv, sizeof(auxv)))
  80                 return NULL;
  81 
  82         p = find_auxv_entry(type, auxv);
  83         if (p)
  84                 return (void *)p->a_un.a_val;
  85 
  86         return NULL;
  87 }
  88 
  89 int pick_online_cpu(void)
  90 {
  91         cpu_set_t mask;
  92         int cpu;
  93 
  94         CPU_ZERO(&mask);
  95 
  96         if (sched_getaffinity(0, sizeof(mask), &mask)) {
  97                 perror("sched_getaffinity");
  98                 return -1;
  99         }
 100 
 101         /* We prefer a primary thread, but skip 0 */
 102         for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
 103                 if (CPU_ISSET(cpu, &mask))
 104                         return cpu;
 105 
 106         /* Search for anything, but in reverse */
 107         for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
 108                 if (CPU_ISSET(cpu, &mask))
 109                         return cpu;
 110 
 111         printf("No cpus in affinity mask?!\n");
 112         return -1;
 113 }
 114 
 115 bool is_ppc64le(void)
 116 {
 117         struct utsname uts;
 118         int rc;
 119 
 120         errno = 0;
 121         rc = uname(&uts);
 122         if (rc) {
 123                 perror("uname");
 124                 return false;
 125         }
 126 
 127         return strcmp(uts.machine, "ppc64le") == 0;
 128 }
 129 
 130 int read_debugfs_file(char *debugfs_file, int *result)
 131 {
 132         int rc = -1, fd;
 133         char path[PATH_MAX];
 134         char value[16];
 135 
 136         strcpy(path, "/sys/kernel/debug/");
 137         strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
 138 
 139         if ((fd = open(path, O_RDONLY)) < 0)
 140                 return rc;
 141 
 142         if ((rc = read(fd, value, sizeof(value))) < 0)
 143                 return rc;
 144 
 145         value[15] = 0;
 146         *result = atoi(value);
 147         close(fd);
 148 
 149         return 0;
 150 }
 151 
 152 int write_debugfs_file(char *debugfs_file, int result)
 153 {
 154         int rc = -1, fd;
 155         char path[PATH_MAX];
 156         char value[16];
 157 
 158         strcpy(path, "/sys/kernel/debug/");
 159         strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
 160 
 161         if ((fd = open(path, O_WRONLY)) < 0)
 162                 return rc;
 163 
 164         snprintf(value, 16, "%d", result);
 165 
 166         if ((rc = write(fd, value, strlen(value))) < 0)
 167                 return rc;
 168 
 169         close(fd);
 170 
 171         return 0;
 172 }
 173 
 174 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
 175                 int cpu, int group_fd, unsigned long flags)
 176 {
 177         return syscall(__NR_perf_event_open, hw_event, pid, cpu,
 178                       group_fd, flags);
 179 }
 180 
 181 static void perf_event_attr_init(struct perf_event_attr *event_attr,
 182                                         unsigned int type,
 183                                         unsigned long config)
 184 {
 185         memset(event_attr, 0, sizeof(*event_attr));
 186 
 187         event_attr->type = type;
 188         event_attr->size = sizeof(struct perf_event_attr);
 189         event_attr->config = config;
 190         event_attr->read_format = PERF_FORMAT_GROUP;
 191         event_attr->disabled = 1;
 192         event_attr->exclude_kernel = 1;
 193         event_attr->exclude_hv = 1;
 194         event_attr->exclude_guest = 1;
 195 }
 196 
 197 int perf_event_open_counter(unsigned int type,
 198                             unsigned long config, int group_fd)
 199 {
 200         int fd;
 201         struct perf_event_attr event_attr;
 202 
 203         perf_event_attr_init(&event_attr, type, config);
 204 
 205         fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
 206 
 207         if (fd < 0)
 208                 perror("perf_event_open() failed");
 209 
 210         return fd;
 211 }
 212 
 213 int perf_event_enable(int fd)
 214 {
 215         if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
 216                 perror("error while enabling perf events");
 217                 return -1;
 218         }
 219 
 220         return 0;
 221 }
 222 
 223 int perf_event_disable(int fd)
 224 {
 225         if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
 226                 perror("error disabling perf events");
 227                 return -1;
 228         }
 229 
 230         return 0;
 231 }
 232 
 233 int perf_event_reset(int fd)
 234 {
 235         if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
 236                 perror("error resetting perf events");
 237                 return -1;
 238         }
 239 
 240         return 0;
 241 }
 242 
 243 static void sigill_handler(int signr, siginfo_t *info, void *unused)
 244 {
 245         static int warned = 0;
 246         ucontext_t *ctx = (ucontext_t *)unused;
 247         unsigned long *pc = &UCONTEXT_NIA(ctx);
 248 
 249         /* mtspr 3,RS to check for move to DSCR below */
 250         if ((*((unsigned int *)*pc) & 0xfc1fffff) == 0x7c0303a6) {
 251                 if (!warned++)
 252                         printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
 253                 *pc += 4;
 254         } else {
 255                 printf("SIGILL at %p\n", pc);
 256                 abort();
 257         }
 258 }
 259 
 260 void set_dscr(unsigned long val)
 261 {
 262         static int init = 0;
 263         struct sigaction sa;
 264 
 265         if (!init) {
 266                 memset(&sa, 0, sizeof(sa));
 267                 sa.sa_sigaction = sigill_handler;
 268                 sa.sa_flags = SA_SIGINFO;
 269                 if (sigaction(SIGILL, &sa, NULL))
 270                         perror("sigill_handler");
 271                 init = 1;
 272         }
 273 
 274         asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
 275 }

/* [<][>][^][v][top][bottom][index][help] */