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 * 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], 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] != 0) 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 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