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