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 *
getsysinfo(int cmd)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
bitness(const char * isaname)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 *
report_abi(int cmd,const char * vfmt)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
machtype(const char * isaname)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
report_hwcap(int d,const char * isa)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] != NULL)
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
main(int argc,char * argv[])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