Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
0004  */
0005 
0006 #define _GNU_SOURCE /* For CPU_ZERO etc. */
0007 
0008 #include <elf.h>
0009 #include <errno.h>
0010 #include <fcntl.h>
0011 #include <link.h>
0012 #include <sched.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <sys/ioctl.h>
0017 #include <sys/stat.h>
0018 #include <sys/sysinfo.h>
0019 #include <sys/types.h>
0020 #include <sys/utsname.h>
0021 #include <unistd.h>
0022 #include <asm/unistd.h>
0023 #include <linux/limits.h>
0024 
0025 #include "utils.h"
0026 
0027 static char auxv[4096];
0028 
0029 int read_auxv(char *buf, ssize_t buf_size)
0030 {
0031     ssize_t num;
0032     int rc, fd;
0033 
0034     fd = open("/proc/self/auxv", O_RDONLY);
0035     if (fd == -1) {
0036         perror("open");
0037         return -errno;
0038     }
0039 
0040     num = read(fd, buf, buf_size);
0041     if (num < 0) {
0042         perror("read");
0043         rc = -EIO;
0044         goto out;
0045     }
0046 
0047     if (num > buf_size) {
0048         printf("overflowed auxv buffer\n");
0049         rc = -EOVERFLOW;
0050         goto out;
0051     }
0052 
0053     rc = 0;
0054 out:
0055     close(fd);
0056     return rc;
0057 }
0058 
0059 void *find_auxv_entry(int type, char *auxv)
0060 {
0061     ElfW(auxv_t) *p;
0062 
0063     p = (ElfW(auxv_t) *)auxv;
0064 
0065     while (p->a_type != AT_NULL) {
0066         if (p->a_type == type)
0067             return p;
0068 
0069         p++;
0070     }
0071 
0072     return NULL;
0073 }
0074 
0075 void *get_auxv_entry(int type)
0076 {
0077     ElfW(auxv_t) *p;
0078 
0079     if (read_auxv(auxv, sizeof(auxv)))
0080         return NULL;
0081 
0082     p = find_auxv_entry(type, auxv);
0083     if (p)
0084         return (void *)p->a_un.a_val;
0085 
0086     return NULL;
0087 }
0088 
0089 int pick_online_cpu(void)
0090 {
0091     int ncpus, cpu = -1;
0092     cpu_set_t *mask;
0093     size_t size;
0094 
0095     ncpus = get_nprocs_conf();
0096     size = CPU_ALLOC_SIZE(ncpus);
0097     mask = CPU_ALLOC(ncpus);
0098     if (!mask) {
0099         perror("malloc");
0100         return -1;
0101     }
0102 
0103     CPU_ZERO_S(size, mask);
0104 
0105     if (sched_getaffinity(0, size, mask)) {
0106         perror("sched_getaffinity");
0107         goto done;
0108     }
0109 
0110     /* We prefer a primary thread, but skip 0 */
0111     for (cpu = 8; cpu < ncpus; cpu += 8)
0112         if (CPU_ISSET_S(cpu, size, mask))
0113             goto done;
0114 
0115     /* Search for anything, but in reverse */
0116     for (cpu = ncpus - 1; cpu >= 0; cpu--)
0117         if (CPU_ISSET_S(cpu, size, mask))
0118             goto done;
0119 
0120     printf("No cpus in affinity mask?!\n");
0121 
0122 done:
0123     CPU_FREE(mask);
0124     return cpu;
0125 }
0126 
0127 bool is_ppc64le(void)
0128 {
0129     struct utsname uts;
0130     int rc;
0131 
0132     errno = 0;
0133     rc = uname(&uts);
0134     if (rc) {
0135         perror("uname");
0136         return false;
0137     }
0138 
0139     return strcmp(uts.machine, "ppc64le") == 0;
0140 }
0141 
0142 int read_sysfs_file(char *fpath, char *result, size_t result_size)
0143 {
0144     char path[PATH_MAX] = "/sys/";
0145     int rc = -1, fd;
0146 
0147     strncat(path, fpath, PATH_MAX - strlen(path) - 1);
0148 
0149     if ((fd = open(path, O_RDONLY)) < 0)
0150         return rc;
0151 
0152     rc = read(fd, result, result_size);
0153 
0154     close(fd);
0155 
0156     if (rc < 0)
0157         return rc;
0158 
0159     return 0;
0160 }
0161 
0162 int read_debugfs_file(char *debugfs_file, int *result)
0163 {
0164     int rc = -1, fd;
0165     char path[PATH_MAX];
0166     char value[16];
0167 
0168     strcpy(path, "/sys/kernel/debug/");
0169     strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
0170 
0171     if ((fd = open(path, O_RDONLY)) < 0)
0172         return rc;
0173 
0174     if ((rc = read(fd, value, sizeof(value))) < 0)
0175         return rc;
0176 
0177     value[15] = 0;
0178     *result = atoi(value);
0179     close(fd);
0180 
0181     return 0;
0182 }
0183 
0184 int write_debugfs_file(char *debugfs_file, int result)
0185 {
0186     int rc = -1, fd;
0187     char path[PATH_MAX];
0188     char value[16];
0189 
0190     strcpy(path, "/sys/kernel/debug/");
0191     strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
0192 
0193     if ((fd = open(path, O_WRONLY)) < 0)
0194         return rc;
0195 
0196     snprintf(value, 16, "%d", result);
0197 
0198     if ((rc = write(fd, value, strlen(value))) < 0)
0199         return rc;
0200 
0201     close(fd);
0202 
0203     return 0;
0204 }
0205 
0206 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
0207         int cpu, int group_fd, unsigned long flags)
0208 {
0209     return syscall(__NR_perf_event_open, hw_event, pid, cpu,
0210               group_fd, flags);
0211 }
0212 
0213 static void perf_event_attr_init(struct perf_event_attr *event_attr,
0214                     unsigned int type,
0215                     unsigned long config)
0216 {
0217     memset(event_attr, 0, sizeof(*event_attr));
0218 
0219     event_attr->type = type;
0220     event_attr->size = sizeof(struct perf_event_attr);
0221     event_attr->config = config;
0222     event_attr->read_format = PERF_FORMAT_GROUP;
0223     event_attr->disabled = 1;
0224     event_attr->exclude_kernel = 1;
0225     event_attr->exclude_hv = 1;
0226     event_attr->exclude_guest = 1;
0227 }
0228 
0229 int perf_event_open_counter(unsigned int type,
0230                 unsigned long config, int group_fd)
0231 {
0232     int fd;
0233     struct perf_event_attr event_attr;
0234 
0235     perf_event_attr_init(&event_attr, type, config);
0236 
0237     fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
0238 
0239     if (fd < 0)
0240         perror("perf_event_open() failed");
0241 
0242     return fd;
0243 }
0244 
0245 int perf_event_enable(int fd)
0246 {
0247     if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
0248         perror("error while enabling perf events");
0249         return -1;
0250     }
0251 
0252     return 0;
0253 }
0254 
0255 int perf_event_disable(int fd)
0256 {
0257     if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
0258         perror("error disabling perf events");
0259         return -1;
0260     }
0261 
0262     return 0;
0263 }
0264 
0265 int perf_event_reset(int fd)
0266 {
0267     if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
0268         perror("error resetting perf events");
0269         return -1;
0270     }
0271 
0272     return 0;
0273 }
0274 
0275 int using_hash_mmu(bool *using_hash)
0276 {
0277     char line[128];
0278     FILE *f;
0279     int rc;
0280 
0281     f = fopen("/proc/cpuinfo", "r");
0282     FAIL_IF(!f);
0283 
0284     rc = 0;
0285     while (fgets(line, sizeof(line), f) != NULL) {
0286         if (!strcmp(line, "MMU      : Hash\n") ||
0287             !strcmp(line, "platform : Cell\n") ||
0288             !strcmp(line, "platform : PowerMac\n")) {
0289             *using_hash = true;
0290             goto out;
0291         }
0292 
0293         if (strcmp(line, "MMU       : Radix\n") == 0) {
0294             *using_hash = false;
0295             goto out;
0296         }
0297     }
0298 
0299     rc = -1;
0300 out:
0301     fclose(f);
0302     return rc;
0303 }