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