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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2022 Oxide Computer Company
27 */
28
29 /*
30 * String conversion routine for hardware capabilities types.
31 */
32 #include <strings.h>
33 #include <stdio.h>
34 #include <_machelf.h>
35 #include <elfcap.h>
36 #include "cap_msg.h"
37 #include "_conv.h"
38
39 static int
conv_cap(Xword val,char * str,size_t len,Half mach,Conv_fmt_flags_t fmt_flags,elfcap_to_str_func_t * fptr)40 conv_cap(Xword val, char *str, size_t len, Half mach,
41 Conv_fmt_flags_t fmt_flags, elfcap_to_str_func_t *fptr)
42 {
43 size_t _len;
44 int do_bkt = (fmt_flags & CONV_FMT_NOBKT) == 0;
45
46 /*
47 * Note that for the purposes of this routine, I consider
48 * CONV_FMT_NOBKT to mean no brackets, or anything that
49 * is placed outside of them. We also drop the hex version
50 * of the flags that are put in front of the opening bracket.
51 */
52 if (do_bkt) {
53 _len = sprintf(str, MSG_ORIG(MSG_GBL_OSQBRKT), EC_XWORD(val));
54
55 len -= _len;
56 str += _len;
57 }
58
59 if ((*fptr)(ELFCAP_STYLE_UC, val, str, len, ELFCAP_FMT_SNGSPACE,
60 mach) != 0)
61 return (0);
62
63 if (do_bkt) {
64 _len = strlen(str);
65 if ((len - _len) >= MSG_GBL_CSQBRKT_SIZE) {
66 str += _len;
67 (void) strcpy(str, MSG_ORIG(MSG_GBL_CSQBRKT));
68 }
69 }
70 return (1);
71 }
72
73 const char *
conv_cap_val_hw1(Xword val,Half mach,Conv_fmt_flags_t fmt_flags,Conv_cap_val_hw1_buf_t * cap_val_hw1_buf)74 conv_cap_val_hw1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
75 Conv_cap_val_hw1_buf_t *cap_val_hw1_buf)
76 {
77 if (val == 0)
78 return (MSG_ORIG(MSG_GBL_ZERO));
79
80 if (conv_cap(val, cap_val_hw1_buf->buf, sizeof (cap_val_hw1_buf->buf),
81 mach, fmt_flags, elfcap_hw1_to_str) == 0)
82 return (conv_invalid_val(&cap_val_hw1_buf->inv_buf, val, 0));
83 return ((const char *)cap_val_hw1_buf->buf);
84 }
85
86 const char *
conv_cap_val_hw2(Xword val,Half mach,Conv_fmt_flags_t fmt_flags,Conv_cap_val_hw2_buf_t * cap_val_hw2_buf)87 conv_cap_val_hw2(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
88 Conv_cap_val_hw2_buf_t *cap_val_hw2_buf)
89 {
90 if (val == 0)
91 return (MSG_ORIG(MSG_GBL_ZERO));
92
93 if (conv_cap(val, cap_val_hw2_buf->buf, sizeof (cap_val_hw2_buf->buf),
94 mach, fmt_flags, elfcap_hw2_to_str) == 0)
95 return (conv_invalid_val(&cap_val_hw2_buf->inv_buf, val, 0));
96 return ((const char *)cap_val_hw2_buf->buf);
97 }
98
99 const char *
conv_cap_val_sf1(Xword val,Half mach,Conv_fmt_flags_t fmt_flags,Conv_cap_val_sf1_buf_t * cap_val_sf1_buf)100 conv_cap_val_sf1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
101 Conv_cap_val_sf1_buf_t *cap_val_sf1_buf)
102 {
103 if (val == 0)
104 return (MSG_ORIG(MSG_GBL_ZERO));
105
106 if (conv_cap(val, cap_val_sf1_buf->buf, sizeof (cap_val_sf1_buf->buf),
107 mach, fmt_flags, elfcap_sf1_to_str) == 0)
108 return (conv_invalid_val(&cap_val_sf1_buf->inv_buf, val, 0));
109 return ((const char *)cap_val_sf1_buf->buf);
110 }
111
112 const char *
conv_cap_val_hw3(Xword val,Half mach,Conv_fmt_flags_t fmt_flags,Conv_cap_val_hw3_buf_t * cap_val_hw3_buf)113 conv_cap_val_hw3(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
114 Conv_cap_val_hw3_buf_t *cap_val_hw3_buf)
115 {
116 if (val == 0)
117 return (MSG_ORIG(MSG_GBL_ZERO));
118
119 if (conv_cap(val, cap_val_hw3_buf->buf, sizeof (cap_val_hw3_buf->buf),
120 mach, fmt_flags, elfcap_hw3_to_str) == 0)
121 return (conv_invalid_val(&cap_val_hw3_buf->inv_buf, val, 0));
122 return ((const char *)cap_val_hw3_buf->buf);
123 }
124
125 const char *
conv_cap_tag(Xword tag,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)126 conv_cap_tag(Xword tag, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf)
127 {
128 #ifdef _ELF64
129 /*
130 * Valid tags all fit in 32-bits, so a value larger than that
131 * is garbage. conv_map_ds() sees 32-bit values, so test for garbage
132 * here before passing it on.
133 *
134 * Since there are no valid tags with a value > 32-bits, there
135 * is no reason to expend effort decoding the low order bits.
136 */
137 if (tag & 0xffffffff00000000)
138 return (conv_invalid_val(inv_buf, tag, fmt_flags));
139 #endif
140
141 return (conv_map_ds(ELFOSABI_NONE, EM_NONE, tag,
142 conv_cap_tag_strings(fmt_flags), fmt_flags, inv_buf));
143 }
144
145 const char *
conv_cap_val(Xword tag,Xword val,Half mach,Conv_fmt_flags_t fmt_flags,Conv_cap_val_buf_t * cap_val_buf)146 conv_cap_val(Xword tag, Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
147 Conv_cap_val_buf_t *cap_val_buf)
148 {
149 switch (tag) {
150 case CA_SUNW_HW_1:
151 return (conv_cap_val_hw1(val, mach, fmt_flags,
152 &cap_val_buf->cap_val_hw1_buf));
153
154 case CA_SUNW_SF_1:
155 return (conv_cap_val_sf1(val, mach, fmt_flags,
156 &cap_val_buf->cap_val_sf1_buf));
157
158 case CA_SUNW_HW_2:
159 return (conv_cap_val_hw2(val, mach, fmt_flags,
160 &cap_val_buf->cap_val_hw2_buf));
161
162 case CA_SUNW_HW_3:
163 return (conv_cap_val_hw3(val, mach, fmt_flags,
164 &cap_val_buf->cap_val_hw3_buf));
165
166 default:
167 return (conv_invalid_val(&cap_val_buf->inv_buf, val, 0));
168 }
169 }
170