1 /*
2  * Copyright 2013-2015, Michael Ellerman, IBM Corp.
3  * Licensed under GPLv2.
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 <stdio.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <unistd.h>
19 
20 #include "utils.h"
21 
22 static char auxv[4096];
23 
24 int read_auxv(char *buf, ssize_t buf_size)
25 {
26 	ssize_t num;
27 	int rc, fd;
28 
29 	fd = open("/proc/self/auxv", O_RDONLY);
30 	if (fd == -1) {
31 		perror("open");
32 		return -errno;
33 	}
34 
35 	num = read(fd, buf, buf_size);
36 	if (num < 0) {
37 		perror("read");
38 		rc = -EIO;
39 		goto out;
40 	}
41 
42 	if (num > buf_size) {
43 		printf("overflowed auxv buffer\n");
44 		rc = -EOVERFLOW;
45 		goto out;
46 	}
47 
48 	rc = 0;
49 out:
50 	close(fd);
51 	return rc;
52 }
53 
54 void *find_auxv_entry(int type, char *auxv)
55 {
56 	ElfW(auxv_t) *p;
57 
58 	p = (ElfW(auxv_t) *)auxv;
59 
60 	while (p->a_type != AT_NULL) {
61 		if (p->a_type == type)
62 			return p;
63 
64 		p++;
65 	}
66 
67 	return NULL;
68 }
69 
70 void *get_auxv_entry(int type)
71 {
72 	ElfW(auxv_t) *p;
73 
74 	if (read_auxv(auxv, sizeof(auxv)))
75 		return NULL;
76 
77 	p = find_auxv_entry(type, auxv);
78 	if (p)
79 		return (void *)p->a_un.a_val;
80 
81 	return NULL;
82 }
83 
84 int pick_online_cpu(void)
85 {
86 	cpu_set_t mask;
87 	int cpu;
88 
89 	CPU_ZERO(&mask);
90 
91 	if (sched_getaffinity(0, sizeof(mask), &mask)) {
92 		perror("sched_getaffinity");
93 		return -1;
94 	}
95 
96 	/* We prefer a primary thread, but skip 0 */
97 	for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
98 		if (CPU_ISSET(cpu, &mask))
99 			return cpu;
100 
101 	/* Search for anything, but in reverse */
102 	for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
103 		if (CPU_ISSET(cpu, &mask))
104 			return cpu;
105 
106 	printf("No cpus in affinity mask?!\n");
107 	return -1;
108 }
109 
110 bool is_ppc64le(void)
111 {
112 	struct utsname uts;
113 	int rc;
114 
115 	errno = 0;
116 	rc = uname(&uts);
117 	if (rc) {
118 		perror("uname");
119 		return false;
120 	}
121 
122 	return strcmp(uts.machine, "ppc64le") == 0;
123 }
124