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