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