1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2013-2015, Michael Ellerman, IBM Corp.
6 #define _GNU_SOURCE /* For CPU_ZERO etc. */
17 #include <sys/ioctl.h>
19 #include <sys/sysinfo.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
23 #include <asm/unistd.h>
24 #include <linux/limits.h>
28 static char auxv[4096];
30 int read_auxv(char *buf, ssize_t buf_size)
35 fd = open("/proc/self/auxv", O_RDONLY);
41 num = read(fd, buf, buf_size);
49 printf("overflowed auxv buffer\n");
60 void *find_auxv_entry(int type, char *auxv)
64 p = (ElfW(auxv_t) *)auxv;
66 while (p->a_type != AT_NULL) {
67 if (p->a_type == type)
76 void *get_auxv_entry(int type)
80 if (read_auxv(auxv, sizeof(auxv)))
83 p = find_auxv_entry(type, auxv);
85 return (void *)p->a_un.a_val;
90 int pick_online_cpu(void)
96 ncpus = get_nprocs_conf();
97 size = CPU_ALLOC_SIZE(ncpus);
98 mask = CPU_ALLOC(ncpus);
104 CPU_ZERO_S(size, mask);
106 if (sched_getaffinity(0, size, mask)) {
107 perror("sched_getaffinity");
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))
116 /* Search for anything, but in reverse */
117 for (cpu = ncpus - 1; cpu >= 0; cpu--)
118 if (CPU_ISSET_S(cpu, size, mask))
121 printf("No cpus in affinity mask?!\n");
128 bool is_ppc64le(void)
140 return strcmp(uts.machine, "ppc64le") == 0;
143 int read_sysfs_file(char *fpath, char *result, size_t result_size)
145 char path[PATH_MAX] = "/sys/";
148 strncat(path, fpath, PATH_MAX - strlen(path) - 1);
150 if ((fd = open(path, O_RDONLY)) < 0)
153 rc = read(fd, result, result_size);
163 int read_debugfs_file(char *debugfs_file, int *result)
169 strcpy(path, "/sys/kernel/debug/");
170 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
172 if ((fd = open(path, O_RDONLY)) < 0)
175 if ((rc = read(fd, value, sizeof(value))) < 0)
179 *result = atoi(value);
185 int write_debugfs_file(char *debugfs_file, int result)
191 strcpy(path, "/sys/kernel/debug/");
192 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
194 if ((fd = open(path, O_WRONLY)) < 0)
197 snprintf(value, 16, "%d", result);
199 if ((rc = write(fd, value, strlen(value))) < 0)
207 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
208 int cpu, int group_fd, unsigned long flags)
210 return syscall(__NR_perf_event_open, hw_event, pid, cpu,
214 static void perf_event_attr_init(struct perf_event_attr *event_attr,
216 unsigned long config)
218 memset(event_attr, 0, sizeof(*event_attr));
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;
230 int perf_event_open_counter(unsigned int type,
231 unsigned long config, int group_fd)
234 struct perf_event_attr event_attr;
236 perf_event_attr_init(&event_attr, type, config);
238 fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
241 perror("perf_event_open() failed");
246 int perf_event_enable(int fd)
248 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
249 perror("error while enabling perf events");
256 int perf_event_disable(int fd)
258 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
259 perror("error disabling perf events");
266 int perf_event_reset(int fd)
268 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
269 perror("error resetting perf events");
276 static void sigill_handler(int signr, siginfo_t *info, void *unused)
278 static int warned = 0;
279 ucontext_t *ctx = (ucontext_t *)unused;
280 unsigned long *pc = &UCONTEXT_NIA(ctx);
282 /* mtspr 3,RS to check for move to DSCR below */
283 if ((*((unsigned int *)*pc) & 0xfc1fffff) == 0x7c0303a6) {
285 printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
288 printf("SIGILL at %p\n", pc);
293 void set_dscr(unsigned long val)
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");
307 asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
310 int using_hash_mmu(bool *using_hash)
316 f = fopen("/proc/cpuinfo", "r");
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")) {
328 if (strcmp(line, "MMU : Radix\n") == 0) {