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