xref: /illumos-gate/usr/src/cmd/isainfo/isainfo.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/systeminfo.h>
30 #include <sys/utsname.h>
31 #include <sys/stat.h>
32 
33 #include <sys/auxv.h>
34 #include <sys/cpuid_drv.h>
35 #include <sys/elf.h>
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <libintl.h>
43 #include <locale.h>
44 #include <fcntl.h>
45 
46 #include <elfcap.h>
47 
48 static const char dev_cpu_self_cpuid[] = "/dev/" CPUID_SELF_NAME;
49 static char *pgmname;
50 static int mode = 0;
51 
52 #define	BITS_MODE	0x1
53 #define	NATIVE_MODE	0x2
54 #define	KERN_MODE	0x4
55 #define	VERBOSE_MODE	0x8
56 #define	EXTN_MODE	0x10
57 
58 static char *
59 getsysinfo(int cmd)
60 {
61 	char *buf;
62 	size_t bufsize = 20;	/* wild guess */
63 	long ret;
64 
65 	if ((buf = malloc(bufsize)) == NULL)
66 		return (NULL);
67 	do {
68 		ret = sysinfo(cmd, buf, bufsize);
69 		if (ret == -1)
70 			return (NULL);
71 		if (ret > bufsize) {
72 			bufsize = ret;
73 			buf = realloc(buf, bufsize);
74 		} else
75 			break;
76 	} while (buf != NULL);
77 
78 	return (buf);
79 }
80 
81 /*
82  * Classify isa's as to bitness of the corresponding ABIs.
83  * isa's which have no "official" Solaris ABI are returned
84  * unrecognised i.e. "zero bit".
85  */
86 static uint_t
87 bitness(const char *isaname)
88 {
89 	if (strcmp(isaname, "sparc") == 0 ||
90 	    strcmp(isaname, "i386") == 0)
91 		return (32);
92 
93 	if (strcmp(isaname, "sparcv9") == 0 ||
94 	    strcmp(isaname, "amd64") == 0)
95 		return (64);
96 
97 	return (0);
98 }
99 
100 static char *
101 report_abi(int cmd, const char *vfmt)
102 {
103 	uint_t bits;
104 	char *isa;
105 
106 	if ((isa = getsysinfo(cmd)) == NULL)
107 		return (0);
108 	if ((bits = bitness(isa)) == 0) {
109 		(void) fprintf(stderr,
110 		    gettext("%s: unable to identify isa '%s'!\n"),
111 		    pgmname, isa);
112 		exit(3);
113 	}
114 
115 	if (mode & VERBOSE_MODE)
116 		(void) printf(vfmt, bits, isa);
117 	else if (mode & BITS_MODE)
118 		(void) printf("%d\n", bits);
119 	else if (mode & (NATIVE_MODE|KERN_MODE))
120 		(void) printf("%s\n", isa);
121 	else
122 		(void) printf("%s", isa);
123 	return (isa);
124 }
125 
126 /*
127  * Classify isas as their machine type.
128  */
129 static ushort_t
130 machtype(const char *isaname)
131 {
132 	if (strcmp(isaname, "sparc") == 0)
133 		return (EM_SPARC);
134 	if (strcmp(isaname, "sparcv9") == 0)
135 		return (EM_SPARCV9);
136 	if (strcmp(isaname, "i386") == 0)
137 		return (EM_386);
138 	if (strcmp(isaname, "amd64") == 0)
139 		return (EM_AMD64);
140 
141 	return (0);
142 }
143 
144 static void
145 report_hwcap(int d, const char *isa)
146 {
147 	struct cpuid_get_hwcap __cgh, *cgh = &__cgh;
148 	char buffer[1024];
149 
150 	cgh->cgh_archname = (char *)isa;
151 	if (ioctl(d, CPUID_GET_HWCAP, cgh) != 0)
152 		return;
153 
154 	(void) elfcap_hw1_to_str(ELFCAP_STYLE_LC, cgh->cgh_hwcap,
155 	    buffer, sizeof (buffer), ELFCAP_FMT_SNGSPACE, machtype(isa));
156 
157 	if (mode & EXTN_MODE) {
158 		(void) printf(": %s\n", buffer);
159 	} else {
160 		char *p;
161 		int linecnt = 0;
162 
163 		for (p = strtok(buffer, " "); p; p = strtok(NULL, " ")) {
164 			if (linecnt == 0)
165 				linecnt = printf("\t");
166 			linecnt += printf("%s ", p);
167 			if (linecnt > 68) {
168 				(void) printf("\n");
169 				linecnt = 0;
170 			}
171 		}
172 		if (linecnt != 0)
173 			(void) printf("\n");
174 	}
175 }
176 
177 #if !defined(TEXT_DOMAIN)
178 #define	TEXT_DOMAIN	"SYS_TEST"
179 #endif
180 
181 int
182 main(int argc, char *argv[])
183 {
184 	int errflg = 0;
185 	int c;
186 	char *vfmt;
187 	char *isa, *isa32;
188 	int d = -1;
189 	const int excl_modes =	/* exclusive mode settings */
190 	    NATIVE_MODE | BITS_MODE | KERN_MODE | EXTN_MODE;
191 
192 	(void) setlocale(LC_ALL, "");
193 	(void) textdomain(TEXT_DOMAIN);
194 
195 	if ((pgmname = strrchr(*argv, '/')) == 0)
196 		pgmname = argv[0];
197 	else
198 		pgmname++;
199 
200 	while ((c = getopt(argc, argv, "nbkvx")) != EOF)
201 		switch (c) {
202 		case 'n':
203 			if (mode & excl_modes)
204 				errflg++;
205 			mode |= NATIVE_MODE;
206 			break;
207 		case 'b':
208 			if (mode & excl_modes)
209 				errflg++;
210 			mode |= BITS_MODE;
211 			break;
212 		case 'k':
213 			if (mode & excl_modes)
214 				errflg++;
215 			mode |= KERN_MODE;
216 			break;
217 		case 'x':
218 			if (mode & excl_modes || mode & VERBOSE_MODE)
219 				errflg++;
220 			mode |= EXTN_MODE;
221 			break;
222 		case 'v':
223 			if (mode & EXTN_MODE)
224 				errflg++;
225 			mode |= VERBOSE_MODE;
226 			break;
227 		case '?':
228 		default:
229 			errflg++;
230 			break;
231 		}
232 
233 	if (errflg || optind != argc) {
234 		(void) fprintf(stderr,
235 		    gettext("usage: %s [ [-v] [-b | -n | -k] | [-x] ]\n"),
236 		    pgmname);
237 		return (1);
238 	}
239 
240 	/*
241 	 * We use dev_cpu_self_cpuid for discovering hardware capabilities;
242 	 * but we only complain if we can't open it if we've been
243 	 * asked to report on those capabilities.
244 	 */
245 	if ((mode & (VERBOSE_MODE|EXTN_MODE)) != 0 &&
246 	    (d = open(dev_cpu_self_cpuid, O_RDONLY)) == -1)
247 		perror(dev_cpu_self_cpuid), exit(1);
248 
249 	if (mode & KERN_MODE) {
250 		vfmt = gettext("%d-bit %s kernel modules\n");
251 		(void) report_abi(SI_ARCHITECTURE_K, vfmt);
252 		return (0);
253 	}
254 
255 	vfmt = gettext("%d-bit %s applications\n");
256 
257 	if (mode & (BITS_MODE | NATIVE_MODE)) {
258 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) == NULL)
259 			isa = report_abi(SI_ARCHITECTURE_32, vfmt);
260 		if (isa != NULL && (mode & VERBOSE_MODE) != 0)
261 			report_hwcap(d, isa);
262 	} else {
263 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) != NULL) {
264 			if (mode & (EXTN_MODE|VERBOSE_MODE))
265 				report_hwcap(d, isa);
266 			else
267 				(void) putchar(' ');
268 		}
269 
270 		if ((isa32 = report_abi(SI_ARCHITECTURE_32, vfmt)) != NULL) {
271 			if (mode & (EXTN_MODE|VERBOSE_MODE))
272 				report_hwcap(d, isa32);
273 		}
274 
275 		if ((isa32 != NULL || isa != NULL) &&
276 		    (mode & (EXTN_MODE|VERBOSE_MODE)) == 0)
277 			(void) putchar('\n');
278 	}
279 
280 	return (0);
281 }
282