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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/systeminfo.h> 31 #include <sys/utsname.h> 32 #include <sys/stat.h> 33 34 #include <sys/auxv.h> 35 #include <sys/cpuid_drv.h> 36 #include <sys/elf.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <strings.h> 41 #include <unistd.h> 42 #include <errno.h> 43 #include <libintl.h> 44 #include <locale.h> 45 #include <fcntl.h> 46 47 #include <elfcap.h> 48 49 static const char dev_cpu_self_cpuid[] = "/dev/" CPUID_SELF_NAME; 50 static char *pgmname; 51 static int mode = 0; 52 53 #define BITS_MODE 0x1 54 #define NATIVE_MODE 0x2 55 #define KERN_MODE 0x4 56 #define VERBOSE_MODE 0x8 57 #define EXTN_MODE 0x10 58 59 static char * 60 getsysinfo(int cmd) 61 { 62 char *buf; 63 size_t bufsize = 20; /* wild guess */ 64 long ret; 65 66 if ((buf = malloc(bufsize)) == NULL) 67 return (NULL); 68 do { 69 ret = sysinfo(cmd, buf, bufsize); 70 if (ret == -1) 71 return (NULL); 72 if (ret > bufsize) { 73 bufsize = ret; 74 buf = realloc(buf, bufsize); 75 } else 76 break; 77 } while (buf != NULL); 78 79 return (buf); 80 } 81 82 /* 83 * Classify isa's as to bitness of the corresponding ABIs. 84 * isa's which have no "official" Solaris ABI are returned 85 * unrecognised i.e. "zero bit". 86 */ 87 static uint_t 88 bitness(const char *isaname) 89 { 90 if (strcmp(isaname, "sparc") == 0 || 91 strcmp(isaname, "i386") == 0) 92 return (32); 93 94 if (strcmp(isaname, "sparcv9") == 0 || 95 strcmp(isaname, "amd64") == 0) 96 return (64); 97 98 return (0); 99 } 100 101 static char * 102 report_abi(int cmd, const char *vfmt) 103 { 104 uint_t bits; 105 char *isa; 106 107 if ((isa = getsysinfo(cmd)) == NULL) 108 return (0); 109 if ((bits = bitness(isa)) == 0) { 110 (void) fprintf(stderr, 111 gettext("%s: unable to identify isa '%s'!\n"), 112 pgmname, isa); 113 exit(3); 114 } 115 116 if (mode & VERBOSE_MODE) 117 (void) printf(vfmt, bits, isa); 118 else if (mode & BITS_MODE) 119 (void) printf("%d\n", bits); 120 else if (mode & (NATIVE_MODE|KERN_MODE)) 121 (void) printf("%s\n", isa); 122 else 123 (void) printf("%s", isa); 124 return (isa); 125 } 126 127 /* 128 * Classify isas as their machine type. 129 */ 130 static ushort_t 131 machtype(const char *isaname) 132 { 133 if (strcmp(isaname, "sparc") == 0) 134 return (EM_SPARC); 135 if (strcmp(isaname, "sparcv9") == 0) 136 return (EM_SPARCV9); 137 if (strcmp(isaname, "i386") == 0) 138 return (EM_386); 139 if (strcmp(isaname, "amd64") == 0) 140 return (EM_AMD64); 141 142 return (0); 143 } 144 145 static void 146 report_hwcap(int d, const char *isa) 147 { 148 struct cpuid_get_hwcap __cgh, *cgh = &__cgh; 149 char buffer[1024]; 150 151 cgh->cgh_archname = (char *)isa; 152 if (ioctl(d, CPUID_GET_HWCAP, cgh) != 0) 153 return; 154 155 (void) hwcap_1_val2str(cgh->cgh_hwcap, buffer, sizeof (buffer), 156 CAP_FMT_SNGSPACE, machtype(isa)); 157 158 if (mode & EXTN_MODE) { 159 (void) printf(": %s\n", buffer); 160 } else { 161 char *p; 162 int linecnt = 0; 163 164 for (p = strtok(buffer, " "); p; p = strtok(NULL, " ")) { 165 if (linecnt == 0) 166 linecnt = printf("\t"); 167 linecnt += printf("%s ", p); 168 if (linecnt > 68) { 169 (void) printf("\n"); 170 linecnt = 0; 171 } 172 } 173 if (linecnt != 0) 174 (void) printf("\n"); 175 } 176 } 177 178 #if !defined(TEXT_DOMAIN) 179 #define TEXT_DOMAIN "SYS_TEST" 180 #endif 181 182 int 183 main(int argc, char *argv[]) 184 { 185 int errflg = 0; 186 int c; 187 char *vfmt; 188 char *isa, *isa32; 189 int d = -1; 190 const int excl_modes = /* exclusive mode settings */ 191 NATIVE_MODE | BITS_MODE | KERN_MODE | EXTN_MODE; 192 193 (void) setlocale(LC_ALL, ""); 194 (void) textdomain(TEXT_DOMAIN); 195 196 if ((pgmname = strrchr(*argv, '/')) == 0) 197 pgmname = argv[0]; 198 else 199 pgmname++; 200 201 while ((c = getopt(argc, argv, "nbkvx")) != EOF) 202 switch (c) { 203 case 'n': 204 if (mode & excl_modes) 205 errflg++; 206 mode |= NATIVE_MODE; 207 break; 208 case 'b': 209 if (mode & excl_modes) 210 errflg++; 211 mode |= BITS_MODE; 212 break; 213 case 'k': 214 if (mode & excl_modes) 215 errflg++; 216 mode |= KERN_MODE; 217 break; 218 case 'x': 219 if (mode & excl_modes || mode & VERBOSE_MODE) 220 errflg++; 221 mode |= EXTN_MODE; 222 break; 223 case 'v': 224 if (mode & EXTN_MODE) 225 errflg++; 226 mode |= VERBOSE_MODE; 227 break; 228 case '?': 229 default: 230 errflg++; 231 break; 232 } 233 234 if (errflg || optind != argc) { 235 (void) fprintf(stderr, 236 gettext("usage: %s [ [-v] [-b | -n | -k] | [-x] ]\n"), 237 pgmname); 238 return (1); 239 } 240 241 /* 242 * We use dev_cpu_self_cpuid for discovering hardware capabilities; 243 * but we only complain if we can't open it if we've been 244 * asked to report on those capabilities. 245 */ 246 if ((mode & (VERBOSE_MODE|EXTN_MODE)) != 0 && 247 (d = open(dev_cpu_self_cpuid, O_RDONLY)) == -1) 248 perror(dev_cpu_self_cpuid), exit(1); 249 250 if (mode & KERN_MODE) { 251 vfmt = gettext("%d-bit %s kernel modules\n"); 252 (void) report_abi(SI_ARCHITECTURE_K, vfmt); 253 return (0); 254 } 255 256 vfmt = gettext("%d-bit %s applications\n"); 257 258 if (mode & (BITS_MODE | NATIVE_MODE)) { 259 if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) == NULL) 260 isa = report_abi(SI_ARCHITECTURE_32, vfmt); 261 if (isa != NULL && (mode & VERBOSE_MODE) != 0) 262 report_hwcap(d, isa); 263 } else { 264 if ((isa = report_abi(SI_ARCHITECTURE_64, vfmt)) != NULL) { 265 if (mode & (EXTN_MODE|VERBOSE_MODE)) 266 report_hwcap(d, isa); 267 else 268 (void) putchar(' '); 269 } 270 271 if ((isa32 = report_abi(SI_ARCHITECTURE_32, vfmt)) != NULL) { 272 if (mode & (EXTN_MODE|VERBOSE_MODE)) 273 report_hwcap(d, isa32); 274 } 275 276 if ((isa32 != NULL || isa != NULL) && 277 (mode & (EXTN_MODE|VERBOSE_MODE)) == 0) 278 (void) putchar('\n'); 279 } 280 281 return (0); 282 } 283