Home | History | Annotate | Download | only in elfcap
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /* LINTLIBRARY */
     28 
     29 /*
     30  * String conversion routine for hardware capabilities types.
     31  */
     32 #include	<strings.h>
     33 #include	<stdio.h>
     34 #include	<ctype.h>
     35 #include	<sys/machelf.h>
     36 #include	<sys/elf.h>
     37 #include	<sys/auxv_SPARC.h>
     38 #include	<sys/auxv_386.h>
     39 #include	<elfcap.h>
     40 
     41 /*
     42  * Given a literal string, generate an initialization for an
     43  * elfcap_str_t value.
     44  */
     45 #define	STRDESC(_str) { _str, sizeof (_str) - 1 }
     46 
     47 /*
     48  * The items in the elfcap_desc_t arrays are required to be
     49  * ordered so that the array index is related to the
     50  * c_val field as:
     51  *
     52  *	array[ndx].c_val = 2^ndx
     53  *
     54  * meaning that
     55  *
     56  *	array[0].c_val = 2^0 = 1
     57  *	array[1].c_val = 2^1 = 2
     58  *	array[2].c_val = 2^2 = 4
     59  *	.
     60  *	.
     61  *	.
     62  *
     63  * Since 0 is not a valid value for the c_val field, we use it to
     64  * mark an array entry that is a placeholder. This can happen if there
     65  * is a hole in the assigned bits.
     66  *
     67  * The RESERVED_ELFCAP_DESC macro is used to reserve such holes.
     68  */
     69 #define	RESERVED_ELFCAP_DESC { 0, { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }
     70 
     71 /*
     72  * Define separators for output string processing. This must be kept in
     73  * sync with the elfcap_fmt_t values in elfcap.h.
     74  */
     75 static const elfcap_str_t format[] = {
     76 	STRDESC(" "),			/* ELFCAP_FMT_SNGSPACE */
     77 	STRDESC("  "),			/* ELFCAP_FMT_DBLSPACE */
     78 	STRDESC(" | ")			/* ELFCAP_FMT_PIPSPACE */
     79 };
     80 #define	FORMAT_NELTS	(sizeof (format) / sizeof (format[0]))
     81 
     82 
     83 
     84 /*
     85  * Define all known software capabilities in all the supported styles.
     86  * Order the capabilities by their numeric value. See SF1_SUNW_
     87  * values in sys/elf.h.
     88  */
     89 #if (ELFCAP_NUM_SF1 > 32)
     90 #error ELFCAP_NUM_SF1 is limited to no more than 32 items
     91 #endif
     92 static const elfcap_desc_t sf1[ELFCAP_NUM_SF1] = {
     93 	{						/* 0x00000001 */
     94 		SF1_SUNW_FPKNWN, STRDESC("SF1_SUNW_FPKNWN"),
     95 		STRDESC("FPKNWN"), STRDESC("fpknwn")
     96 	},
     97 	{						/* 0x00000002 */
     98 		SF1_SUNW_FPUSED, STRDESC("SF1_SUNW_FPUSED"),
     99 		STRDESC("FPUSED"), STRDESC("fpused"),
    100 	},
    101 	{						/* 0x00000004 */
    102 		SF1_SUNW_ADDR32, STRDESC("SF1_SUNW_ADDR32"),
    103 		STRDESC("ADDR32"), STRDESC("addr32"),
    104 	}
    105 };
    106 
    107 
    108 
    109 /*
    110  * Order the SPARC hardware capabilities to match their numeric value.  See
    111  * AV_SPARC_ values in sys/auxv_SPARC.h.
    112  */
    113 #if (ELFCAP_NUM_HW1_SPARC > 32)
    114 #error ELFCAP_NUM_HW1_SPARC is limited to no more than 32 items
    115 #endif
    116 static const elfcap_desc_t hw1_sparc[ELFCAP_NUM_HW1_SPARC] = {
    117 	{						/* 0x00000001 */
    118 		AV_SPARC_MUL32, STRDESC("AV_SPARC_MUL32"),
    119 		STRDESC("MUL32"), STRDESC("mul32"),
    120 	},
    121 	{						/* 0x00000002 */
    122 		AV_SPARC_DIV32, STRDESC("AV_SPARC_DIV32"),
    123 		STRDESC("DIV32"), STRDESC("div32"),
    124 	},
    125 	{						/* 0x00000004 */
    126 		AV_SPARC_FSMULD, STRDESC("AV_SPARC_FSMULD"),
    127 		STRDESC("FSMULD"), STRDESC("fsmuld"),
    128 	},
    129 	{						/* 0x00000008 */
    130 		AV_SPARC_V8PLUS, STRDESC("AV_SPARC_V8PLUS"),
    131 		STRDESC("V8PLUS"), STRDESC("v8plus"),
    132 	},
    133 	{						/* 0x00000010 */
    134 		AV_SPARC_POPC, STRDESC("AV_SPARC_POPC"),
    135 		STRDESC("POPC"), STRDESC("popc"),
    136 	},
    137 	{						/* 0x00000020 */
    138 		AV_SPARC_VIS, STRDESC("AV_SPARC_VIS"),
    139 		STRDESC("VIS"), STRDESC("vis"),
    140 	},
    141 	{						/* 0x00000040 */
    142 		AV_SPARC_VIS2, STRDESC("AV_SPARC_VIS2"),
    143 		STRDESC("VIS2"), STRDESC("vis2"),
    144 	},
    145 	{						/* 0x00000080 */
    146 		AV_SPARC_ASI_BLK_INIT, STRDESC("AV_SPARC_ASI_BLK_INIT"),
    147 		STRDESC("ASI_BLK_INIT"), STRDESC("asi_blk_init"),
    148 	},
    149 	{						/* 0x00000100 */
    150 		AV_SPARC_FMAF, STRDESC("AV_SPARC_FMAF"),
    151 		STRDESC("FMAF"), STRDESC("fmaf"),
    152 	},
    153 	RESERVED_ELFCAP_DESC,				/* 0x00000200 */
    154 	{						/* 0x00000400 */
    155 		AV_SPARC_VIS3, STRDESC("AV_SPARC_VIS3"),
    156 		STRDESC("VIS3"), STRDESC("vis3"),
    157 	},
    158 	{						/* 0x00000800 */
    159 		AV_SPARC_HPC, STRDESC("AV_SPARC_HPC"),
    160 		STRDESC("HPC"), STRDESC("hpc"),
    161 	},
    162 	{						/* 0x00001000 */
    163 		AV_SPARC_RANDOM, STRDESC("AV_SPARC_RANDOM"),
    164 		STRDESC("RANDOM"), STRDESC("random"),
    165 	},
    166 	{						/* 0x00002000 */
    167 		AV_SPARC_TRANS, STRDESC("AV_SPARC_TRANS"),
    168 		STRDESC("TRANS"), STRDESC("trans"),
    169 	},
    170 	{						/* 0x00004000 */
    171 		AV_SPARC_FJFMAU, STRDESC("AV_SPARC_FJFMAU"),
    172 		STRDESC("FJFMAU"), STRDESC("fjfmau"),
    173 	},
    174 	{						/* 0x00008000 */
    175 		AV_SPARC_IMA, STRDESC("AV_SPARC_IMA"),
    176 		STRDESC("IMA"), STRDESC("ima"),
    177 	},
    178 	{						/* 0x00010000 */
    179 		AV_SPARC_ASI_CACHE_SPARING,
    180 		STRDESC("AV_SPARC_ASI_CACHE_SPARING"),
    181 		STRDESC("CSPARE"), STRDESC("cspare"),
    182 	}
    183 };
    184 
    185 
    186 
    187 /*
    188  * Order the Intel hardware capabilities to match their numeric value.  See
    189  * AV_386_ values in sys/auxv_386.h.
    190  */
    191 #if (ELFCAP_NUM_HW1_386 > 32)
    192 #error ELFCAP_NUM_HW1_386 is limited to no more than 32 items
    193 #endif
    194 static const elfcap_desc_t hw1_386[ELFCAP_NUM_HW1_386] = {
    195 	{						/* 0x00000001 */
    196 		AV_386_FPU, STRDESC("AV_386_FPU"),
    197 		STRDESC("FPU"), STRDESC("fpu"),
    198 	},
    199 	{						/* 0x00000002 */
    200 		AV_386_TSC, STRDESC("AV_386_TSC"),
    201 		STRDESC("TSC"), STRDESC("tsc"),
    202 	},
    203 	{						/* 0x00000004 */
    204 		AV_386_CX8, STRDESC("AV_386_CX8"),
    205 		STRDESC("CX8"), STRDESC("cx8"),
    206 	},
    207 	{						/* 0x00000008 */
    208 		AV_386_SEP, STRDESC("AV_386_SEP"),
    209 		STRDESC("SEP"), STRDESC("sep"),
    210 	},
    211 	{						/* 0x00000010 */
    212 		AV_386_AMD_SYSC, STRDESC("AV_386_AMD_SYSC"),
    213 		STRDESC("AMD_SYSC"), STRDESC("amd_sysc"),
    214 	},
    215 	{						/* 0x00000020 */
    216 		AV_386_CMOV, STRDESC("AV_386_CMOV"),
    217 		STRDESC("CMOV"), STRDESC("cmov"),
    218 	},
    219 	{						/* 0x00000040 */
    220 		AV_386_MMX, STRDESC("AV_386_MMX"),
    221 		STRDESC("MMX"), STRDESC("mmx"),
    222 	},
    223 	{						/* 0x00000080 */
    224 		AV_386_AMD_MMX, STRDESC("AV_386_AMD_MMX"),
    225 		STRDESC("AMD_MMX"), STRDESC("amd_mmx"),
    226 	},
    227 	{						/* 0x00000100 */
    228 		AV_386_AMD_3DNow, STRDESC("AV_386_AMD_3DNow"),
    229 		STRDESC("AMD_3DNow"), STRDESC("amd_3dnow"),
    230 	},
    231 	{						/* 0x00000200 */
    232 		AV_386_AMD_3DNowx, STRDESC("AV_386_AMD_3DNowx"),
    233 		STRDESC("AMD_3DNowx"), STRDESC("amd_3dnowx"),
    234 	},
    235 	{						/* 0x00000400 */
    236 		AV_386_FXSR, STRDESC("AV_386_FXSR"),
    237 		STRDESC("FXSR"), STRDESC("fxsr"),
    238 	},
    239 	{						/* 0x00000800 */
    240 		AV_386_SSE, STRDESC("AV_386_SSE"),
    241 		STRDESC("SSE"), STRDESC("sse"),
    242 	},
    243 	{						/* 0x00001000 */
    244 		AV_386_SSE2, STRDESC("AV_386_SSE2"),
    245 		STRDESC("SSE2"), STRDESC("sse2"),
    246 	},
    247 	{						/* 0x00002000 */
    248 		AV_386_PAUSE, STRDESC("AV_386_PAUSE"),
    249 		STRDESC("PAUSE"), STRDESC("pause"),
    250 	},
    251 	{						/* 0x00004000 */
    252 		AV_386_SSE3, STRDESC("AV_386_SSE3"),
    253 		STRDESC("SSE3"), STRDESC("sse3"),
    254 	},
    255 	{						/* 0x00008000 */
    256 		AV_386_MON, STRDESC("AV_386_MON"),
    257 		STRDESC("MON"), STRDESC("mon"),
    258 	},
    259 	{						/* 0x00010000 */
    260 		AV_386_CX16, STRDESC("AV_386_CX16"),
    261 		STRDESC("CX16"), STRDESC("cx16"),
    262 	},
    263 	{						/* 0x00020000 */
    264 		AV_386_AHF, STRDESC("AV_386_AHF"),
    265 		STRDESC("AHF"), STRDESC("ahf"),
    266 	},
    267 	{						/* 0x00040000 */
    268 		AV_386_TSCP, STRDESC("AV_386_TSCP"),
    269 		STRDESC("TSCP"), STRDESC("tscp"),
    270 	},
    271 	{						/* 0x00080000 */
    272 		AV_386_AMD_SSE4A, STRDESC("AV_386_AMD_SSE4A"),
    273 		STRDESC("AMD_SSE4A"), STRDESC("amd_sse4a"),
    274 	},
    275 	{						/* 0x00100000 */
    276 		AV_386_POPCNT, STRDESC("AV_386_POPCNT"),
    277 		STRDESC("POPCNT"), STRDESC("popcnt"),
    278 	},
    279 	{						/* 0x00200000 */
    280 		AV_386_AMD_LZCNT, STRDESC("AV_386_AMD_LZCNT"),
    281 		STRDESC("AMD_LZCNT"), STRDESC("amd_lzcnt"),
    282 	},
    283 	{						/* 0x00400000 */
    284 		AV_386_SSSE3, STRDESC("AV_386_SSSE3"),
    285 		STRDESC("SSSE3"), STRDESC("ssse3"),
    286 	},
    287 	{						/* 0x00800000 */
    288 		AV_386_SSE4_1, STRDESC("AV_386_SSE4_1"),
    289 		STRDESC("SSE4.1"), STRDESC("sse4.1"),
    290 	},
    291 	{						/* 0x01000000 */
    292 		AV_386_SSE4_2, STRDESC("AV_386_SSE4_2"),
    293 		STRDESC("SSE4.2"), STRDESC("sse4.2"),
    294 	},
    295 	{						/* 0x02000000 */
    296 		AV_386_MOVBE, STRDESC("AV_386_MOVBE"),
    297 		STRDESC("MOVBE"), STRDESC("movbe"),
    298 	},
    299 	{						/* 0x04000000 */
    300 		AV_386_AES, STRDESC("AV_386_AES"),
    301 		STRDESC("AES"), STRDESC("aes"),
    302 	},
    303 	{						/* 0x08000000 */
    304 		AV_386_PCLMULQDQ, STRDESC("AV_386_PCLMULQDQ"),
    305 		STRDESC("PCLMULQDQ"), STRDESC("pclmulqdq"),
    306 	}
    307 };
    308 
    309 /*
    310  * Concatenate a token to the string buffer.  This can be a capabilities token
    311  * or a separator token.
    312  */
    313 static elfcap_err_t
    314 token(char **ostr, size_t *olen, const elfcap_str_t *nstr)
    315 {
    316 	if (*olen < nstr->s_len)
    317 		return (ELFCAP_ERR_BUFOVFL);
    318 
    319 	(void) strcat(*ostr, nstr->s_str);
    320 	*ostr += nstr->s_len;
    321 	*olen -= nstr->s_len;
    322 
    323 	return (ELFCAP_ERR_NONE);
    324 }
    325 
    326 static elfcap_err_t
    327 get_str_desc(elfcap_style_t style, const elfcap_desc_t *cdp,
    328     const elfcap_str_t **ret_str)
    329 {
    330 	switch (style) {
    331 	case ELFCAP_STYLE_FULL:
    332 		*ret_str = &cdp->c_full;
    333 		break;
    334 	case ELFCAP_STYLE_UC:
    335 		*ret_str = &cdp->c_uc;
    336 		break;
    337 	case ELFCAP_STYLE_LC:
    338 		*ret_str = &cdp->c_lc;
    339 		break;
    340 	default:
    341 		return (ELFCAP_ERR_INVSTYLE);
    342 	}
    343 
    344 	return (ELFCAP_ERR_NONE);
    345 }
    346 
    347 
    348 /*
    349  * Expand a capabilities value into the strings defined in the associated
    350  * capabilities descriptor.
    351  */
    352 static elfcap_err_t
    353 expand(elfcap_style_t style, uint64_t val, const elfcap_desc_t *cdp,
    354     uint_t cnum, char *str, size_t slen, elfcap_fmt_t fmt)
    355 {
    356 	uint_t			cnt;
    357 	int			follow = 0, err;
    358 	const elfcap_str_t	*nstr;
    359 
    360 	if (val == 0)
    361 		return (ELFCAP_ERR_NONE);
    362 
    363 	for (cnt = cnum; cnt > 0; cnt--) {
    364 		uint_t mask = cdp[cnt - 1].c_val;
    365 
    366 		if ((val & mask) != 0) {
    367 			if (follow++ && ((err = token(&str, &slen,
    368 			    &format[fmt])) != ELFCAP_ERR_NONE))
    369 				return (err);
    370 
    371 			err = get_str_desc(style, &cdp[cnt - 1], &nstr);
    372 			if (err != ELFCAP_ERR_NONE)
    373 				return (err);
    374 			if ((err = token(&str, &slen, nstr)) != ELFCAP_ERR_NONE)
    375 				return (err);
    376 
    377 			val = val & ~mask;
    378 		}
    379 	}
    380 
    381 	/*
    382 	 * If there are any unknown bits remaining display the numeric value.
    383 	 */
    384 	if (val) {
    385 		if (follow && ((err = token(&str, &slen, &format[fmt])) !=
    386 		    ELFCAP_ERR_NONE))
    387 			return (err);
    388 
    389 		(void) snprintf(str, slen, "0x%llx", val);
    390 	}
    391 	return (ELFCAP_ERR_NONE);
    392 }
    393 
    394 /*
    395  * Expand a CA_SUNW_HW_1 value.
    396  */
    397 elfcap_err_t
    398 elfcap_hw1_to_str(elfcap_style_t style, uint64_t val, char *str,
    399     size_t len, elfcap_fmt_t fmt, ushort_t mach)
    400 {
    401 	/*
    402 	 * Initialize the string buffer, and validate the format request.
    403 	 */
    404 	*str = '\0';
    405 	if ((fmt < 0) || (fmt >= FORMAT_NELTS))
    406 		return (ELFCAP_ERR_INVFMT);
    407 
    408 	if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
    409 		return (expand(style, val, &hw1_386[0], ELFCAP_NUM_HW1_386,
    410 		    str, len, fmt));
    411 
    412 	if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
    413 	    (mach == EM_SPARCV9))
    414 		return (expand(style, val, hw1_sparc, ELFCAP_NUM_HW1_SPARC,
    415 		    str, len, fmt));
    416 
    417 	return (ELFCAP_ERR_UNKMACH);
    418 }
    419 
    420 /*
    421  * Expand a CA_SUNW_SF_1 value.  Note, that at present these capabilities are
    422  * common across all platforms.  The use of "mach" is therefore redundant, but
    423  * is retained for compatibility with the interface of elfcap_hw1_to_str(), and
    424  * possible future expansion.
    425  */
    426 elfcap_err_t
    427 /* ARGSUSED4 */
    428 elfcap_sf1_to_str(elfcap_style_t style, uint64_t val, char *str,
    429     size_t len, elfcap_fmt_t fmt, ushort_t mach)
    430 {
    431 	/*
    432 	 * Initialize the string buffer, and validate the format request.
    433 	 */
    434 	*str = '\0';
    435 	if ((fmt < 0) || (fmt >= FORMAT_NELTS))
    436 		return (ELFCAP_ERR_INVFMT);
    437 
    438 	return (expand(style, val, &sf1[0], ELFCAP_NUM_SF1, str, len, fmt));
    439 }
    440 
    441 /*
    442  * Given a capability tag type and value, map it to a string representation.
    443  */
    444 elfcap_err_t
    445 elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, uint64_t val,
    446     char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach)
    447 {
    448 	if (tag == CA_SUNW_HW_1)
    449 		return (elfcap_hw1_to_str(style, val, str, len, fmt, mach));
    450 	if (tag == CA_SUNW_SF_1)
    451 		return (elfcap_sf1_to_str(style, val, str, len, fmt, mach));
    452 
    453 	return (ELFCAP_ERR_UNKTAG);
    454 }
    455 
    456 /*
    457  * Determine a capabilities value from a capabilities string.
    458  */
    459 static uint64_t
    460 value(elfcap_style_t style, const char *str, const elfcap_desc_t *cdp,
    461     uint_t cnum)
    462 {
    463 	const elfcap_str_t	*nstr;
    464 	uint_t	num;
    465 	int	err;
    466 
    467 	for (num = 0; num < cnum; num++) {
    468 		/*
    469 		 * Skip "reserved" bits. These are unassigned bits in the
    470 		 * middle of the assigned range.
    471 		 */
    472 		if (cdp[num].c_val == 0)
    473 			continue;
    474 
    475 		if ((err = get_str_desc(style, &cdp[num], &nstr)) != 0)
    476 			return (err);
    477 		if (strcmp(str, nstr->s_str) == 0)
    478 			return (cdp[num].c_val);
    479 	}
    480 	return (0);
    481 }
    482 
    483 uint64_t
    484 elfcap_sf1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
    485 {
    486 	return (value(style, str, &sf1[0], ELFCAP_NUM_SF1));
    487 }
    488 
    489 uint64_t
    490 elfcap_hw1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
    491 {
    492 	if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
    493 		return (value(style, str, &hw1_386[0], ELFCAP_NUM_HW1_386));
    494 
    495 	if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
    496 	    (mach == EM_SPARCV9))
    497 		return (value(style, str, hw1_sparc, ELFCAP_NUM_HW1_SPARC));
    498 
    499 	return (0);
    500 }
    501 
    502 /*
    503  * These functions allow the caller to get direct access to the
    504  * cap descriptors.
    505  */
    506 const elfcap_desc_t *
    507 elfcap_getdesc_hw1_sparc(void)
    508 {
    509 	return (hw1_sparc);
    510 }
    511 
    512 const elfcap_desc_t *
    513 elfcap_getdesc_hw1_386(void)
    514 {
    515 	return (hw1_386);
    516 }
    517 
    518 const elfcap_desc_t *
    519 elfcap_getdesc_sf1(void)
    520 {
    521 	return (sf1);
    522 }
    523