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