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 /* 23 * Copyright 2007 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 /* LINTLIBRARY */ 30 31 /* 32 * String conversion routine for hardware capabilities types. 33 */ 34 #include <strings.h> 35 #include <stdio.h> 36 #include <ctype.h> 37 #include <limits.h> 38 #include <sys/machelf.h> 39 #include <sys/elf.h> 40 #include <sys/auxv_SPARC.h> 41 #include <sys/auxv_386.h> 42 #include <elfcap.h> 43 44 /* 45 * Define separators for val2str processing. 46 */ 47 static const Fmt_desc format[] = { 48 {" ", 1 }, 49 {" ", 2 }, 50 {" | ", 3 } 51 }; 52 53 /* 54 * Define all known capabilities as both lower and upper case strings. This 55 * duplication is necessary, rather than have one string and use something 56 * like toupper(), as a client such as ld.so.1 doesn't need the overhead of 57 * dragging in the internationalization support of toupper(). The Intel 3DNow 58 * flags are a slightly odd convention too. 59 * 60 * Define all known software capabilities. 61 */ 62 #ifdef CAP_UPPERCASE 63 static const char Sf1_fpknwn[] = "FPKNWN"; 64 static const char Sf1_fpused[] = "FPUSED"; 65 #elif CAP_LOWERCASE 66 static const char Sf1_fpknwn[] = "fpknwn"; 67 static const char Sf1_fpused[] = "fpused"; 68 #else 69 #error "Software Capabilities - what case do you want?" 70 #endif 71 72 /* 73 * Order the software capabilities to match their numeric value. See SF1_SUNW_ 74 * values in sys/elf.h. 75 */ 76 static const Cap_desc sf1[] = { 77 { SF1_SUNW_FPKNWN, Sf1_fpknwn, (sizeof (Sf1_fpknwn) - 1) }, 78 { SF1_SUNW_FPUSED, Sf1_fpused, (sizeof (Sf1_fpused) - 1) } 79 }; 80 static const uint_t sf1_num = sizeof (sf1) / sizeof (Cap_desc); 81 82 /* 83 * Define all known SPARC hardware capabilities. 84 */ 85 #ifdef CAP_UPPERCASE 86 static const char Hw1_s_mul32[] = "MUL32"; 87 static const char Hw1_s_div32[] = "DIV32"; 88 static const char Hw1_s_fsmuld[] = "FSMULD"; 89 static const char Hw1_s_v8plus[] = "V8PLUS"; 90 static const char Hw1_s_popc[] = "POPC"; 91 static const char Hw1_s_vis[] = "VIS"; 92 static const char Hw1_s_vis2[] = "VIS2"; 93 static const char Hw1_s_asi_blk_init[] = "ASI_BLK_INIT"; 94 static const char Hw1_s_fmaf[] = "FMAF"; 95 static const char Hw1_s_reserved1[] = "RESERVED1"; 96 static const char Hw1_s_reserved2[] = "RESERVED2"; 97 static const char Hw1_s_reserved3[] = "RESERVED3"; 98 static const char Hw1_s_reserved4[] = "RESERVED4"; 99 static const char Hw1_s_reserved5[] = "RESERVED5"; 100 static const char Hw1_s_fjfmau[] = "FJFMAU"; 101 static const char Hw1_s_ima[] = "IMA"; 102 #elif CAP_LOWERCASE 103 static const char Hw1_s_mul32[] = "mul32"; 104 static const char Hw1_s_div32[] = "div32"; 105 static const char Hw1_s_fsmuld[] = "fsmuld"; 106 static const char Hw1_s_v8plus[] = "v8plus"; 107 static const char Hw1_s_popc[] = "popc"; 108 static const char Hw1_s_vis[] = "vis"; 109 static const char Hw1_s_vis2[] = "vis2"; 110 static const char Hw1_s_asi_blk_init[] = "asi_blk_init"; 111 static const char Hw1_s_fmaf[] = "fmaf"; 112 static const char Hw1_s_reserved1[] = "reserved1"; 113 static const char Hw1_s_reserved2[] = "reserved2"; 114 static const char Hw1_s_reserved3[] = "reserved3"; 115 static const char Hw1_s_reserved4[] = "reserved4"; 116 static const char Hw1_s_reserved5[] = "reserved5"; 117 static const char Hw1_s_fjfmau[] = "fjfmau"; 118 static const char Hw1_s_ima[] = "ima"; 119 120 #else 121 #error "Hardware Capabilities (sparc) - what case do you want?" 122 #endif 123 124 /* 125 * Order the SPARC hardware capabilities to match their numeric value. See 126 * AV_SPARC_ values in sys/auxv_SPARC.h. 127 */ 128 static const Cap_desc hw1_s[] = { 129 { AV_SPARC_MUL32, Hw1_s_mul32, sizeof (Hw1_s_mul32) - 1 }, 130 { AV_SPARC_DIV32, Hw1_s_div32, sizeof (Hw1_s_div32) - 1 }, 131 { AV_SPARC_FSMULD, Hw1_s_fsmuld, sizeof (Hw1_s_fsmuld) - 1 }, 132 { AV_SPARC_V8PLUS, Hw1_s_v8plus, sizeof (Hw1_s_v8plus) - 1 }, 133 { AV_SPARC_POPC, Hw1_s_popc, sizeof (Hw1_s_popc) - 1 }, 134 { AV_SPARC_VIS, Hw1_s_vis, sizeof (Hw1_s_vis) - 1 }, 135 { AV_SPARC_VIS2, Hw1_s_vis2, sizeof (Hw1_s_vis2) - 1 }, 136 { AV_SPARC_ASI_BLK_INIT, Hw1_s_asi_blk_init, 137 sizeof (Hw1_s_asi_blk_init) - 1 }, 138 { AV_SPARC_FMAF, Hw1_s_fmaf, sizeof (Hw1_s_fmaf) - 1 }, 139 { 0, Hw1_s_reserved1, sizeof (Hw1_s_reserved1) - 1 }, 140 { 0, Hw1_s_reserved2, sizeof (Hw1_s_reserved2) - 1 }, 141 { 0, Hw1_s_reserved3, sizeof (Hw1_s_reserved3) - 1 }, 142 { 0, Hw1_s_reserved4, sizeof (Hw1_s_reserved4) - 1 }, 143 { 0, Hw1_s_reserved5, sizeof (Hw1_s_reserved5) - 1 }, 144 { AV_SPARC_FJFMAU, Hw1_s_fjfmau, sizeof (Hw1_s_fjfmau) - 1 }, 145 { AV_SPARC_IMA, Hw1_s_ima, sizeof (Hw1_s_ima) - 1 } 146 }; 147 static const uint_t hw1_s_num = sizeof (hw1_s) / sizeof (Cap_desc); 148 149 /* 150 * Define all known Intel hardware capabilities. 151 */ 152 #ifdef CAP_UPPERCASE 153 static const char Hw1_i_fpu[] = "FPU"; 154 static const char Hw1_i_tsc[] = "TSC"; 155 static const char Hw1_i_cx8[] = "CX8"; 156 static const char Hw1_i_sep[] = "SEP"; 157 static const char Hw1_i_amd_sysc[] = "AMD_SYSC"; 158 static const char Hw1_i_cmov[] = "CMOV"; 159 static const char Hw1_i_mmx[] = "MMX"; 160 static const char Hw1_i_amd_mmx[] = "AMD_MMX"; 161 static const char Hw1_i_amd_3dnow[] = "AMD_3DNow"; 162 static const char Hw1_i_amd_3dnowx[] = "AMD_3DNowx"; 163 static const char Hw1_i_fxsr[] = "FXSR"; 164 static const char Hw1_i_sse[] = "SSE"; 165 static const char Hw1_i_sse2[] = "SSE2"; 166 static const char Hw1_i_pause[] = "PAUSE"; 167 static const char Hw1_i_sse3[] = "SSE3"; 168 static const char Hw1_i_mon[] = "MON"; 169 static const char Hw1_i_cx16[] = "CX16"; 170 static const char Hw1_i_ahf[] = "AHF"; 171 static const char Hw1_i_tscp[] = "TSCP"; 172 static const char Hw1_i_amd_sse4a[] = "AMD_SSE4A"; 173 static const char Hw1_i_popcnt[] = "POPCNT"; 174 static const char Hw1_i_amd_lzcnt[] = "AMD_LZCNT"; 175 static const char Hw1_i_ssse3[] = "SSSE3"; 176 static const char Hw1_i_sse4_1[] = "SSE4.1"; 177 static const char Hw1_i_sse4_2[] = "SSE4.2"; 178 #elif CAP_LOWERCASE 179 static const char Hw1_i_fpu[] = "fpu"; 180 static const char Hw1_i_tsc[] = "tsc"; 181 static const char Hw1_i_cx8[] = "cx8"; 182 static const char Hw1_i_sep[] = "sep"; 183 static const char Hw1_i_amd_sysc[] = "amd_sysc"; 184 static const char Hw1_i_cmov[] = "cmov"; 185 static const char Hw1_i_mmx[] = "mmx"; 186 static const char Hw1_i_amd_mmx[] = "amd_mmx"; 187 static const char Hw1_i_amd_3dnow[] = "amd_3dnow"; 188 static const char Hw1_i_amd_3dnowx[] = "amd_3dnowx"; 189 static const char Hw1_i_fxsr[] = "fxsr"; 190 static const char Hw1_i_sse[] = "sse"; 191 static const char Hw1_i_sse2[] = "sse2"; 192 static const char Hw1_i_pause[] = "pause"; 193 static const char Hw1_i_sse3[] = "sse3"; 194 static const char Hw1_i_mon[] = "mon"; 195 static const char Hw1_i_cx16[] = "cx16"; 196 static const char Hw1_i_ahf[] = "ahf"; 197 static const char Hw1_i_tscp[] = "tscp"; 198 static const char Hw1_i_amd_sse4a[] = "amd_sse4a"; 199 static const char Hw1_i_popcnt[] = "popcnt"; 200 static const char Hw1_i_amd_lzcnt[] = "amd_lzcnt"; 201 static const char Hw1_i_ssse3[] = "ssse3"; 202 static const char Hw1_i_sse4_1[] = "sse4.1"; 203 static const char Hw1_i_sse4_2[] = "sse4.2"; 204 #else 205 #error "Hardware Capabilities (intel) - what case do you want?" 206 #endif 207 208 /* 209 * Order the Intel hardware capabilities to match their numeric value. See 210 * AV_386_ values in sys/auxv_386.h. 211 */ 212 static const Cap_desc hw1_i[] = { 213 { AV_386_FPU, Hw1_i_fpu, sizeof (Hw1_i_fpu) - 1 }, 214 { AV_386_TSC, Hw1_i_tsc, sizeof (Hw1_i_tsc) - 1 }, 215 { AV_386_CX8, Hw1_i_cx8, sizeof (Hw1_i_cx8) - 1 }, 216 { AV_386_SEP, Hw1_i_sep, sizeof (Hw1_i_sep) - 1 }, 217 { AV_386_AMD_SYSC, Hw1_i_amd_sysc, sizeof (Hw1_i_amd_sysc) - 1 }, 218 { AV_386_CMOV, Hw1_i_cmov, sizeof (Hw1_i_cmov) - 1 }, 219 { AV_386_MMX, Hw1_i_mmx, sizeof (Hw1_i_mmx) - 1 }, 220 { AV_386_AMD_MMX, Hw1_i_amd_mmx, sizeof (Hw1_i_amd_mmx) - 1 }, 221 { AV_386_AMD_3DNow, Hw1_i_amd_3dnow, 222 sizeof (Hw1_i_amd_3dnow) - 1 }, 223 { AV_386_AMD_3DNowx, Hw1_i_amd_3dnowx, 224 sizeof (Hw1_i_amd_3dnowx) - 1 }, 225 { AV_386_FXSR, Hw1_i_fxsr, sizeof (Hw1_i_fxsr) - 1 }, 226 { AV_386_SSE, Hw1_i_sse, sizeof (Hw1_i_sse) - 1 }, 227 { AV_386_SSE2, Hw1_i_sse2, sizeof (Hw1_i_sse2) - 1 }, 228 { AV_386_PAUSE, Hw1_i_pause, sizeof (Hw1_i_pause) - 1 }, 229 { AV_386_SSE3, Hw1_i_sse3, sizeof (Hw1_i_sse3) - 1 }, 230 { AV_386_MON, Hw1_i_mon, sizeof (Hw1_i_mon) - 1 }, 231 { AV_386_CX16, Hw1_i_cx16, sizeof (Hw1_i_cx16) - 1 }, 232 { AV_386_AHF, Hw1_i_ahf, sizeof (Hw1_i_ahf) - 1 }, 233 { AV_386_TSCP, Hw1_i_tscp, sizeof (Hw1_i_tscp) - 1 }, 234 { AV_386_AMD_SSE4A, Hw1_i_amd_sse4a, 235 sizeof (Hw1_i_amd_sse4a) - 1 }, 236 { AV_386_POPCNT, Hw1_i_popcnt, sizeof (Hw1_i_popcnt) - 1 }, 237 { AV_386_AMD_LZCNT, Hw1_i_amd_lzcnt, 238 sizeof (Hw1_i_amd_lzcnt) - 1 }, 239 { AV_386_SSSE3, Hw1_i_ssse3, sizeof (Hw1_i_ssse3) - 1 }, 240 { AV_386_SSE4_1, Hw1_i_sse4_1, sizeof (Hw1_i_sse4_1) - 1 }, 241 { AV_386_SSE4_2, Hw1_i_sse4_2, sizeof (Hw1_i_sse4_2) - 1 } 242 }; 243 static const uint_t hw1_i_num = sizeof (hw1_i) / sizeof (Cap_desc); 244 245 /* 246 * Concatenate a token to the string buffer. This can be a capabilities token 247 * or a separator token. 248 */ 249 static int 250 token(char **ostr, size_t *olen, const char *nstr, size_t nlen) 251 { 252 if (*olen < nlen) 253 return (CAP_ERR_BUFOVFL); 254 255 (void) strcat(*ostr, nstr); 256 *ostr += nlen; 257 *olen -= nlen; 258 259 return (0); 260 } 261 262 /* 263 * Expand a capabilities value into the strings defined in the associated 264 * capabilities descriptor. 265 */ 266 static int 267 expand(uint64_t val, const Cap_desc *cdp, uint_t cnum, char *str, size_t slen, 268 int fmt) 269 { 270 uint_t cnt, mask; 271 int follow = 0, err; 272 273 if (val == 0) 274 return (0); 275 276 for (cnt = WORD_BIT, mask = 0x80000000; cnt; cnt--, 277 (mask = mask >> 1)) { 278 if ((val & mask) && (cnt <= cnum) && cdp[cnt - 1].c_val) { 279 if (follow++ && ((err = token(&str, &slen, 280 format[fmt].f_str, format[fmt].f_len)) != 0)) 281 return (err); 282 283 if ((err = token(&str, &slen, cdp[cnt - 1].c_str, 284 cdp[cnt - 1].c_len)) != 0) 285 return (err); 286 287 val = val & ~mask; 288 } 289 } 290 291 /* 292 * If there are any unknown bits remaining display the numeric value. 293 */ 294 if (val) { 295 if (follow && ((err = token(&str, &slen, format[fmt].f_str, 296 format[fmt].f_len)) != 0)) 297 return (err); 298 299 (void) snprintf(str, slen, "0x%llx", val); 300 } 301 return (0); 302 } 303 304 /* 305 * Expand a CA_SUNW_HW_1 value. 306 */ 307 int 308 hwcap_1_val2str(uint64_t val, char *str, size_t len, int fmt, ushort_t mach) 309 { 310 /* 311 * Initialize the string buffer, and validate the format request. 312 */ 313 *str = '\0'; 314 if (fmt > CAP_MAX_TYPE) 315 return (CAP_ERR_INVFMT); 316 317 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64)) 318 return (expand(val, &hw1_i[0], hw1_i_num, str, len, fmt)); 319 320 if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) || 321 (mach == EM_SPARCV9)) 322 return (expand(val, &hw1_s[0], hw1_s_num, str, len, fmt)); 323 324 return (CAP_ERR_UNKMACH); 325 } 326 327 /* 328 * Expand a CA_SUNW_SF_1 value. Note, that at present these capabilities are 329 * common across all platforms. The use of "mach" is therefore redundant, but 330 * is retained for compatibility with the interface of hwcap_1_val2str(), and 331 * possible future expansion. 332 */ 333 int 334 /* ARGSUSED4 */ 335 sfcap_1_val2str(uint64_t val, char *str, size_t len, int fmt, ushort_t mach) 336 { 337 /* 338 * Initialize the string buffer, and validate the format request. 339 */ 340 *str = '\0'; 341 if (fmt > CAP_MAX_TYPE) 342 return (CAP_ERR_INVFMT); 343 344 return (expand(val, &sf1[0], sf1_num, str, len, fmt)); 345 } 346 347 /* 348 * Determine capability type from the capability tag. 349 */ 350 int 351 cap_val2str(uint64_t tag, uint64_t val, char *str, size_t len, int fmt, 352 ushort_t mach) 353 { 354 if (tag == CA_SUNW_HW_1) 355 return (hwcap_1_val2str(val, str, len, fmt, mach)); 356 if (tag == CA_SUNW_SF_1) 357 return (sfcap_1_val2str(val, str, len, fmt, mach)); 358 359 return (CAP_ERR_UNKTAG); 360 } 361 362 /* 363 * Determine a capabilities value from a capabilities string. 364 */ 365 static uint64_t 366 value(const char *str, const Cap_desc *cdp, uint_t cnum) 367 { 368 uint_t num; 369 370 for (num = 0; num < cnum; num++) { 371 if (strcmp(str, cdp[num].c_str) == 0) 372 return (cdp[num].c_val); 373 } 374 return (0); 375 } 376 377 uint64_t 378 sfcap_1_str2val(const char *str, ushort_t mach) 379 { 380 return (value(str, &sf1[0], sf1_num)); 381 } 382 383 uint64_t 384 hwcap_1_str2val(const char *str, ushort_t mach) 385 { 386 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64)) 387 return (value(str, &hw1_i[0], hw1_i_num)); 388 389 if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) || 390 (mach == EM_SPARCV9)) 391 return (value(str, &hw1_s[0], hw1_s_num)); 392 393 return (0); 394 } 395