devpath2.c revision 1.5 1 /* $NetBSD: devpath2.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $ */
2
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 #ifndef lint
28 __RCSID("$NetBSD: devpath2.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $");
29 #endif /* not lint */
30
31 #include <assert.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <util.h>
35
36 #include "defs.h"
37 #include "devpath.h"
38 #include "devpath2.h"
39 #include "utils.h"
40
41 #define easprintf (size_t)easprintf
42
43 /************************************************************************
44 * Type 2 - ACPI Device Path
45 ************************************************************************/
46
47 /*
48 * See 19.3.4 of ACPI Specification, Release 6.5 for compressed EISAID
49 * algorithm.
50 */
51
52 #define PNP0A03 0x0a0341d0
53 #define PNP0A08 0x0a0841d0
54
55 static const char *
56 eisaid_to_str(uint32_t eisaid)
57 {
58 static const char hexdigits[] = "0123456789ABCDEF";
59 static char text[8];
60 union {
61 uint32_t eisaid;
62 uint8_t b[4];
63 } u;
64
65 u.eisaid = eisaid;
66
67 text[0] = (char)__SHIFTOUT(u.b[0], __BITS(4,0));
68 text[1] = (char)__SHIFTOUT(u.b[0], __BITS(7,5));
69 text[1] |= (char)__SHIFTOUT(u.b[1], __BITS(1,0)) << 3;
70 text[2] = (char)__SHIFTOUT(u.b[1], __BITS(7,2));
71
72 text[0] += 0x40; /* '@' */
73 text[1] += 0x40;
74 text[2] += 0x40;
75
76 #define hi_nib(v) (((v) >> 4) & 0x0f)
77 #define lo_nib(v) (((v) >> 0) & 0x0f)
78 text[3] = hexdigits[hi_nib(u.b[3])];
79 text[4] = hexdigits[lo_nib(u.b[3])];
80 text[5] = hexdigits[hi_nib(u.b[2])];
81 text[6] = hexdigits[lo_nib(u.b[2])];
82 text[7] = 0;
83 #undef lo_nib
84 #undef hi_nib
85
86 return text;
87 }
88
89 static inline const char *
90 devpath_acpi_acpi_eisaid(uint32_t eisaid)
91 {
92
93 #define PNP(v) (0x000041d0 | ((v) << 16))
94 switch (eisaid) {
95 // case PNP(0x0f03): return "PS2Mouse"; /* legacy? */
96 // case PNP(0x0303): return "FloppyPNP"; /* legacy? */
97 case PNP(0x0a03): return "PciRoot";
98 case PNP(0x0a08): return "PcieRoot";
99 case PNP(0x0604): return "Floppy";
100 case PNP(0x0301): return "Keyboard";
101 case PNP(0x0501): return "Serial";
102 case PNP(0x0401): return "ParallelPort";
103 default: return NULL;
104 }
105 #undef PNP
106 }
107
108 static inline void
109 devpath_acpi_acpi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
110 { /* See 10.3.3 */
111 struct { /* Sub-Type 1 */
112 devpath_t hdr; /* Length = 12 */
113 uint32_t _HID;
114 uint32_t _UID;
115 } __packed *p = (void *)dp;
116 __CTASSERT(sizeof(*p) == 12);
117 const char *str;
118
119 str = devpath_acpi_acpi_eisaid(p->_HID);
120 if (str == NULL) {
121 path->sz = easprintf(&path->cp, "ACPI(%s,0x%x)",
122 eisaid_to_str(p->_HID), p->_UID);
123 } else {
124 path->sz = easprintf(&path->cp, "%s(0x%x)", str, p->_UID);
125 }
126
127 if (dbg != NULL) {
128 dbg->sz = easprintf(&dbg->cp,
129 DEVPATH_FMT_HDR
130 DEVPATH_FMT(_HID: 0x%08x(%s)\n)
131 DEVPATH_FMT(_UID: 0x%08x\n),
132 DEVPATH_DAT_HDR(dp),
133 p->_HID,
134 eisaid_to_str(p->_HID),
135 p->_UID);
136 }
137 }
138
139 static inline void
140 devpath_acpi_acpiex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
141 { /* See 10.3.3 */
142 struct { /* Sub-Type 2 */
143 devpath_t hdr; /* Length = 19 + n */
144 uint32_t _HID;
145 uint32_t _UID;
146 uint32_t _CID;
147 char _HIDSTR[]; /* at least NUL byte */
148 // char _UIDSTR[]; /* at least NUL byte */
149 // char _CIDSTR[]; /* at least NUL byte */
150 } __packed *p = (void *)dp;
151 __CTASSERT(sizeof(*p) == 16);
152 char *hidstr = p->_HIDSTR;
153 char *uidstr = hidstr + strlen(hidstr) + 1;
154 char *cidstr = uidstr + strlen(uidstr) + 1;
155
156 #if 0
157 There are 4 different subsubtypes depending on the ?ID, ?IDSTR values.
158
159 "AcpiEx"
160 "AcpiExp"
161 "PciRoot"
162 "PcipRoot"
163 #endif
164 if (p->_HID == PNP0A08 || p->_CID == PNP0A08) {
165 // PcieRoot(UID|UIDSTR)
166 path->sz = easprintf(&path->cp, "PcieRoot(%s)",
167 *uidstr != '\0' ? uidstr : eisaid_to_str(p->_UID));
168 }
169 else if (p->_HID == PNP0A03 || p->_CID == PNP0A03) {
170 assert(p->_HID != PNP0A08);
171 // PciRoot(UID|UIDSTR)
172 path->sz = easprintf(&path->cp, "PciRoot(%s)",
173 *uidstr != '\0' ? uidstr : eisaid_to_str(p->_UID));
174 }
175 else if (hidstr[0] == '\0' && cidstr[0] == '\0' && uidstr[0] != '\0') {
176 assert(p->_HID != 0);
177 path->sz = easprintf(&path->cp, "AcpiExp(%s,%s,%s)",
178 eisaid_to_str(p->_HID),
179 eisaid_to_str(p->_CID),
180 uidstr);
181 }
182 else {
183 path->sz = easprintf(&path->cp, "ACPIEX(%s,%s,0x%x,%s,%s,%s)",
184 eisaid_to_str(p->_HID), eisaid_to_str(p->_CID),
185 p->_UID, hidstr, cidstr, uidstr);
186 }
187
188 if (dbg != NULL) {
189 dbg->sz = easprintf(&dbg->cp,
190 DEVPATH_FMT_HDR
191 DEVPATH_FMT(_HID: 0x%08x(%s)\n)
192 DEVPATH_FMT(_UID: 0x%08x\n)
193 DEVPATH_FMT(_CID: 0x%08x(%s)\n)
194 DEVPATH_FMT(_HIDSTR: %s\n)
195 DEVPATH_FMT(_UIDSTR: %s\n)
196 DEVPATH_FMT(_CIDSTR: %s\n),
197 DEVPATH_DAT_HDR(dp),
198 p->_HID,
199 eisaid_to_str(p->_HID),
200 p->_UID,
201 p->_CID,
202 eisaid_to_str(p->_CID),
203 hidstr,
204 uidstr,
205 cidstr);
206 }
207 }
208
209 static inline void
210 devpath_acpi_adr(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
211 { /* See 10.3.3.1 */
212 struct { /* Sub-Type 3 */
213 devpath_t hdr; /* Length = 8; at least one _ADR */
214 uint32_t _ADR[];
215 } __packed *p = (void *)dp;
216 __CTASSERT(sizeof(*p) == 4);
217 char *tp;
218 size_t cnt;
219
220 cnt = (p->hdr.Length - sizeof(p->hdr)) / sizeof(p->_ADR[0]);
221
222 tp = estrdup("AcpiAdr(");
223 for (size_t i = 0; i < cnt; i++) {
224 path->sz = easprintf(&path->cp, "%s0x%08x%s", tp, p->_ADR[i],
225 i + 1 < cnt ? "," : "");
226 free(tp);
227 tp = path->cp;
228 }
229 path->sz = easprintf(&path->cp, "%s)", tp);
230 free(tp);
231
232 if (dbg != NULL) {
233 dbg->sz = easprintf(&dbg->cp,
234 DEVPATH_FMT_HDR,
235 DEVPATH_DAT_HDR(dp));
236 tp = dbg->cp;
237 for (size_t i = 0; i < cnt; i++) {
238 dbg->sz = easprintf(&dbg->cp, "%s"
239 DEVPATH_FMT(_ADR[%zu]: 0x%08x\n),
240 tp, i, p->_ADR[i]);
241 free(tp);
242 tp = dbg->cp;
243 }
244 }
245 }
246
247 static inline void
248 devpath_acpi_nvdimm(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
249 { /* See 10.3.3.2 */
250 struct { /* Sub-Type 4 */
251 devpath_t hdr; /* Length = 8 */
252 uint32_t NFIT_DevHdl;
253 } __packed *p = (void *)dp;
254 __CTASSERT(sizeof(*p) == 8);
255
256 path->sz = easprintf(&path->cp, "NvdimmAcpiAdr(0x%x)", p->NFIT_DevHdl);
257
258 if (dbg != NULL) {
259 dbg->sz = easprintf(&dbg->cp,
260 DEVPATH_FMT_HDR
261 DEVPATH_FMT(NFIT_DevHdl: 0x%08x\n),
262 DEVPATH_DAT_HDR(dp),
263 p->NFIT_DevHdl);
264 }
265 }
266
267 #ifdef notdef
268 static inline void
269 devpath_acpi_unknown(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
270 {
271
272 path->sz = easprintf(&path->cp, "Msg(%d,%s)", dp->SubType,
273 encode_data(((uint8_t *)dp) + 4, dp->Length - 4));
274
275 if (dbg != NULL) {
276 dbg->sz = easprintf(&dbg->cp,
277 DEVPATH_FMT_HDR,
278 DEVPATH_DAT_HDR(dp));
279 }
280 }
281 #endif
282
283 PUBLIC void
284 devpath_acpi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
285 {
286
287 assert(dp->Type = 2);
288
289 switch (dp->SubType) {
290 case 1: devpath_acpi_acpi(dp, path, dbg); return;
291 case 2: devpath_acpi_acpiex(dp, path, dbg); return;
292 case 3: devpath_acpi_adr(dp, path, dbg); return;
293 case 4: devpath_acpi_nvdimm(dp, path, dbg); return;
294 default: devpath_unsupported(dp, path, dbg); return;
295 }
296 }
297