xref: /titanic_44/usr/src/cmd/isainfo/isainfo.c (revision eb23829ff08a873c612ac45d191d559394b4b408)
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) 2011, 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];
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,
157 	    buffer, sizeof (buffer), ELFCAP_FMT_SNGSPACE, machtype(isa));
158 
159 	if (mode & EXTN_MODE) {
160 		(void) printf(": %s\n", buffer);
161 	} else {
162 		char *p;
163 		int linecnt = 0;
164 
165 		for (p = strtok(buffer, " "); p; p = strtok(NULL, " ")) {
166 			if (linecnt + strlen(p) > 68) {
167 				(void) printf("\n");
168 				linecnt = 0;
169 			}
170 			if (linecnt == 0)
171 				linecnt = printf("\t");
172 			linecnt += printf("%s ", p);
173 		}
174 		if (linecnt != 0)
175 			(void) printf("\n");
176 	}
177 }
178 
179 #if !defined(TEXT_DOMAIN)
180 #define	TEXT_DOMAIN	"SYS_TEST"
181 #endif
182 
183 int
184 main(int argc, char *argv[])
185 {
186 	int errflg = 0;
187 	int c;
188 	char *vfmt;
189 	char *isa, *isa32;
190 	int d = -1;
191 	const int excl_modes =	/* exclusive mode settings */
192 	    NATIVE_MODE | BITS_MODE | KERN_MODE | EXTN_MODE;
193 
194 	(void) setlocale(LC_ALL, "");
195 	(void) textdomain(TEXT_DOMAIN);
196 
197 	if ((pgmname = strrchr(*argv, '/')) == 0)
198 		pgmname = argv[0];
199 	else
200 		pgmname++;
201 
202 	while ((c = getopt(argc, argv, "nbkvx")) != EOF)
203 		switch (c) {
204 		case 'n':
205 			if (mode & excl_modes)
206 				errflg++;
207 			mode |= NATIVE_MODE;
208 			break;
209 		case 'b':
210 			if (mode & excl_modes)
211 				errflg++;
212 			mode |= BITS_MODE;
213 			break;
214 		case 'k':
215 			if (mode & excl_modes)
216 				errflg++;
217 			mode |= KERN_MODE;
218 			break;
219 		case 'x':
220 			if (mode & excl_modes || mode & VERBOSE_MODE)
221 				errflg++;
222 			mode |= EXTN_MODE;
223 			break;
224 		case 'v':
225 			if (mode & EXTN_MODE)
226 				errflg++;
227 			mode |= VERBOSE_MODE;
228 			break;
229 		case '?':
230 		default:
231 			errflg++;
232 			break;
233 		}
234 
235 	if (errflg || optind != argc) {
236 		(void) fprintf(stderr,
237 		    gettext("usage: %s [ [-v] [-b | -n | -k] | [-x] ]\n"),
238 		    pgmname);
239 		return (1);
240 	}
241 
242 	/*
243 	 * We use dev_cpu_self_cpuid for discovering hardware capabilities;
244 	 * but we only complain if we can't open it if we've been
245 	 * asked to report on those capabilities.
246 	 */
247 	if ((mode & (VERBOSE_MODE|EXTN_MODE)) != 0 &&
248 	    (d = open(dev_cpu_self_cpuid, O_RDONLY)) == -1)
249 		perror(dev_cpu_self_cpuid), exit(1);
250 
251 	if (mode & KERN_MODE) {
252 		vfmt = gettext("%d-bit %s kernel modules\n");
253 		(void) report_abi(SI_ARCHITECTURE_K, vfmt);
254 		return (0);
255 	}
256 
257 	vfmt = gettext("%d-bit %s applications\n");
258 
259 	if (mode & (BITS_MODE | NATIVE_MODE)) {
260 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) == NULL)
261 			isa = report_abi(SI_ARCHITECTURE_32, vfmt);
262 		if (isa != NULL && (mode & VERBOSE_MODE) != 0)
263 			report_hwcap(d, isa);
264 	} else {
265 		if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) != NULL) {
266 			if (mode & (EXTN_MODE|VERBOSE_MODE))
267 				report_hwcap(d, isa);
268 			else
269 				(void) putchar(' ');
270 		}
271 
272 		if ((isa32 = report_abi(SI_ARCHITECTURE_32, vfmt)) != NULL) {
273 			if (mode & (EXTN_MODE|VERBOSE_MODE))
274 				report_hwcap(d, isa32);
275 		}
276 
277 		if ((isa32 != NULL || isa != NULL) &&
278 		    (mode & (EXTN_MODE|VERBOSE_MODE)) == 0)
279 			(void) putchar('\n');
280 	}
281 
282 	return (0);
283 }
284