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 * 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 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 * 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 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 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 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