xref: /illumos-gate/usr/src/cmd/isainfo/isainfo.c (revision 9cfcc091666d5546e419c22f4963474d11673f5e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/systeminfo.h>
32 #include <sys/utsname.h>
33 #include <sys/stat.h>
34 
35 #include <sys/auxv.h>
36 #include <sys/cpuid_drv.h>
37 #include <sys/elf.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <unistd.h>
43 #include <errno.h>
44 #include <libintl.h>
45 #include <locale.h>
46 #include <fcntl.h>
47 
48 #include <elfcap.h>
49 
50 static const char dev_cpu_self_cpuid[] = "/dev/" CPUID_SELF_NAME;
51 static char *pgmname;
52 static int mode = 0;
53 
54 #define	BITS_MODE	0x1
55 #define	NATIVE_MODE	0x2
56 #define	KERN_MODE	0x4
57 #define	VERBOSE_MODE	0x8
58 #define	EXTN_MODE	0x10
59 
60 static char *
61 getsysinfo(int cmd)
62 {
63 	char *buf;
64 	size_t bufsize = 20;	/* wild guess */
65 	long ret;
66 
67 	if ((buf = malloc(bufsize)) == NULL)
68 		return (NULL);
69 	do {
70 		ret = sysinfo(cmd, buf, bufsize);
71 		if (ret == -1)
72 			return (NULL);
73 		if (ret > bufsize) {
74 			bufsize = ret;
75 			buf = realloc(buf, bufsize);
76 		} else
77 			break;
78 	} while (buf != NULL);
79 
80 	return (buf);
81 }
82 
83 /*
84  * Classify isa's as to bitness of the corresponding ABIs.
85  * isa's which have no "official" Solaris ABI are returned
86  * unrecognised i.e. "zero bit".
87  */
88 static uint_t
89 bitness(const char *isaname)
90 {
91 	if (strcmp(isaname, "sparc") == 0 ||
92 	    strcmp(isaname, "i386") == 0)
93 		return (32);
94 
95 	if (strcmp(isaname, "sparcv9") == 0 ||
96 	    strcmp(isaname, "amd64") == 0)
97 		return (64);
98 
99 	return (0);
100 }
101 
102 static char *
103 report_abi(int cmd, const char *vfmt)
104 {
105 	uint_t bits;
106 	char *isa;
107 
108 	if ((isa = getsysinfo(cmd)) == NULL)
109 		return (0);
110 	if ((bits = bitness(isa)) == 0) {
111 		(void) fprintf(stderr,
112 		    gettext("%s: unable to identify isa '%s'!\n"),
113 		    pgmname, isa);
114 		exit(3);
115 	}
116 
117 	if (mode & VERBOSE_MODE)
118 		(void) printf(vfmt, bits, isa);
119 	else if (mode & BITS_MODE)
120 		(void) printf("%d\n", bits);
121 	else if (mode & (NATIVE_MODE|KERN_MODE))
122 		(void) printf("%s\n", isa);
123 	else
124 		(void) printf("%s", isa);
125 	return (isa);
126 }
127 
128 /*
129  * Classify isas as their machine type.
130  */
131 static ushort_t
132 machtype(const char *isaname)
133 {
134 	if (strcmp(isaname, "sparc") == 0)
135 		return (EM_SPARC);
136 	if (strcmp(isaname, "sparcv9") == 0)
137 		return (EM_SPARCV9);
138 	if (strcmp(isaname, "i386") == 0)
139 		return (EM_386);
140 	if (strcmp(isaname, "amd64") == 0)
141 		return (EM_AMD64);
142 
143 	return (0);
144 }
145 
146 static void
147 report_hwcap(int d, const char *isa)
148 {
149 	struct cpuid_get_hwcap __cgh, *cgh = &__cgh;
150 	char buffer[1024], cap2[1024];
151 
152 	cgh->cgh_archname = (char *)isa;
153 	if (ioctl(d, CPUID_GET_HWCAP, cgh) != 0)
154 		return;
155 
156 	(void) elfcap_hw1_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap[0],
157 	    buffer, sizeof (buffer), ELFCAP_FMT_SNGSPACE, machtype(isa));
158 
159 	if (cgh->cgh_hwcap[1] != 0)
160 		(void) elfcap_hw2_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap[1],
161 		    cap2, sizeof (cap2), ELFCAP_FMT_SNGSPACE, machtype(isa));
162 	else
163 		cap2[0] = '\0';
164 
165 	if (mode & EXTN_MODE) {
166 		(void) printf(":");
167 		if (cgh->cgh_hwcap[1] != 0)
168 			(void) printf(" %s", cap2);
169 		(void) printf(" %s", buffer);
170 		(void) printf("\n");
171 	} else {
172 		char *p;
173 		int linecnt = 0;
174 
175 		for (p = strtok(cap2, " "); p; p = strtok(NULL, " ")) {
176 			if (linecnt + strlen(p) > 68) {
177 				(void) printf("\n");
178 				linecnt = 0;
179 			}
180 			if (linecnt == 0)
181 				linecnt = printf("\t");
182 			linecnt += printf("%s ", p);
183 		}
184 
185 		for (p = strtok(buffer, " "); p; p = strtok(NULL, " ")) {
186 			if (linecnt + strlen(p) > 68) {
187 				(void) printf("\n");
188 				linecnt = 0;
189 			}
190 			if (linecnt == 0)
191 				linecnt = printf("\t");
192 			linecnt += printf("%s ", p);
193 		}
194 
195 		if (linecnt != 0)
196 			(void) printf("\n");
197 	}
198 }
199 
200 #if !defined(TEXT_DOMAIN)
201 #define	TEXT_DOMAIN	"SYS_TEST"
202 #endif
203 
204 int
205 main(int argc, char *argv[])
206 {
207 	int errflg = 0;
208 	int c;
209 	char *vfmt;
210 	char *isa, *isa32;
211 	int d = -1;
212 	const int excl_modes =	/* exclusive mode settings */
213 	    NATIVE_MODE | BITS_MODE | KERN_MODE | EXTN_MODE;
214 
215 	(void) setlocale(LC_ALL, "");
216 	(void) textdomain(TEXT_DOMAIN);
217 
218 	if ((pgmname = strrchr(*argv, '/')) == 0)
219 		pgmname = argv[0];
220 	else
221 		pgmname++;
222 
223 	while ((c = getopt(argc, argv, "nbkvx")) != EOF)
224 		switch (c) {
225 		case 'n':
226 			if (mode & excl_modes)
227 				errflg++;
228 			mode |= NATIVE_MODE;
229 			break;
230 		case 'b':
231 			if (mode & excl_modes)
232 				errflg++;
233 			mode |= BITS_MODE;
234 			break;
235 		case 'k':
236 			if (mode & excl_modes)
237 				errflg++;
238 			mode |= KERN_MODE;
239 			break;
240 		case 'x':
241 			if (mode & excl_modes || mode & VERBOSE_MODE)
242 				errflg++;
243 			mode |= EXTN_MODE;
244 			break;
245 		case 'v':
246 			if (mode & EXTN_MODE)
247 				errflg++;
248 			mode |= VERBOSE_MODE;
249 			break;
250 		case '?':
251 		default:
252 			errflg++;
253 			break;
254 		}
255 
256 	if (errflg || optind != argc) {
257 		(void) fprintf(stderr,
258 		    gettext("usage: %s [ [-v] [-b | -n | -k] | [-x] ]\n"),
259 		    pgmname);
260 		return (1);
261 	}
262 
263 	/*
264 	 * We use dev_cpu_self_cpuid for discovering hardware capabilities;
265 	 * but we only complain if we can't open it if we've been
266 	 * asked to report on those capabilities.
267 	 */
268 	if ((mode & (VERBOSE_MODE|EXTN_MODE)) != 0 &&
269 	    (d = open(dev_cpu_self_cpuid, O_RDONLY)) == -1)
270 		perror(dev_cpu_self_cpuid), exit(1);
271 
272 	if (mode & KERN_MODE) {
273 		vfmt = gettext("%d-bit %s kernel modules\n");
274 		(void) report_abi(SI_ARCHITECTURE_K, vfmt);
275 		return (0);
276 	}
277 
278 	vfmt = gettext("%d-bit %s applications\n");
279 
280 	if (mode & (BITS_MODE | NATIVE_MODE)) {
281 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) == NULL)
282 			isa = report_abi(SI_ARCHITECTURE_32, vfmt);
283 		if (isa != NULL && (mode & VERBOSE_MODE) != 0)
284 			report_hwcap(d, isa);
285 	} else {
286 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) != NULL) {
287 			if (mode & (EXTN_MODE|VERBOSE_MODE))
288 				report_hwcap(d, isa);
289 			else
290 				(void) putchar(' ');
291 		}
292 
293 		if ((isa32 = report_abi(SI_ARCHITECTURE_32, vfmt)) != NULL) {
294 			if (mode & (EXTN_MODE|VERBOSE_MODE))
295 				report_hwcap(d, isa32);
296 		}
297 
298 		if ((isa32 != NULL || isa != NULL) &&
299 		    (mode & (EXTN_MODE|VERBOSE_MODE)) == 0)
300 			(void) putchar('\n');
301 	}
302 
303 	return (0);
304 }
305