devpath2.c revision 1.1 1 /* $NetBSD: devpath2.c,v 1.1 2025/02/24 13:47:56 christos 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.1 2025/02/24 13:47:56 christos 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
53 #define PNP0A03 0x0a0341d0
54 #define PNP0A08 0x0a0841d0
55
56 static const char *
57 eisaid_to_str(uint32_t eisaid)
58 {
59 static const char hexdigits[] = "0123456789ABCDEF";
60 static char text[8];
61 union {
62 uint32_t eisaid;
63 uint8_t b[4];
64 } u;
65
66 u.eisaid = eisaid;
67
68 text[0] = (char)__SHIFTOUT(u.b[0], __BITS(4,0));
69 text[1] = (char)__SHIFTOUT(u.b[0], __BITS(7,5));
70 text[1] |= (char)__SHIFTOUT(u.b[1], __BITS(1,0)) << 3;
71 text[2] = (char)__SHIFTOUT(u.b[1], __BITS(7,2));
72
73 text[0] += 0x40; /* '@' */
74 text[1] += 0x40;
75 text[2] += 0x40;
76
77 #define hi_nib(v) (((v) >> 4) & 0x0f)
78 #define lo_nib(v) (((v) >> 0) & 0x0f)
79 text[3] = hexdigits[hi_nib(u.b[3])];
80 text[4] = hexdigits[lo_nib(u.b[3])];
81 text[5] = hexdigits[hi_nib(u.b[2])];
82 text[6] = hexdigits[lo_nib(u.b[2])];
83 text[7] = 0;
84 #undef lo_nib
85 #undef hi_nib
86
87 return text;
88 }
89
90 static inline const char *
91 devpath_acpi_acpi_eisaid(uint32_t eisaid)
92 {
93
94 #define PNP(v) (0x000041d0 | ((v) << 16))
95 switch (eisaid) {
96 // case PNP(0x0f03): return "PS2Mouse"; /* legacy? */
97 // case PNP(0x0303): return "FloppyPNP"; /* legacy? */
98 case PNP(0x0a03): return "PciRoot";
99 case PNP(0x0a08): return "PcieRoot";
100 case PNP(0x0604): return "Floppy";
101 case PNP(0x0301): return "Keyboard";
102 case PNP(0x0501): return "Serial";
103 case PNP(0x0401): return "ParallelPort";
104 default: return NULL;
105 }
106 #undef PNP
107 }
108
109 static inline void
110 devpath_acpi_acpi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
111 { /* See 10.3.3 */
112 struct { /* Sub-Type 1 */
113 devpath_t hdr; /* Length = 12 */
114 uint32_t _HID;
115 uint32_t _UID;
116 } __packed *p = (void *)dp;
117 __CTASSERT(sizeof(*p) == 12);
118 const char *str;
119
120 str = devpath_acpi_acpi_eisaid(p->_HID);
121 if (str == NULL)
122 path->sz = easprintf(&path->cp, "ACPI(%s,0x%x)", eisaid_to_str(p->_HID), p->_UID);
123 else
124 path->sz = easprintf(&path->cp, "%s(0x%x)", str, p->_UID);
125
126 if (dbg != NULL) {
127 dbg->sz = easprintf(&dbg->cp,
128 DEVPATH_FMT_HDR
129 DEVPATH_FMT(_HID: 0x%08x(%s)\n)
130 DEVPATH_FMT(_UID: 0x%08x\n),
131 DEVPATH_DAT_HDR(dp),
132 p->_HID,
133 eisaid_to_str(p->_HID),
134 p->_UID);
135 }
136 }
137
138 static inline void
139 devpath_acpi_acpiex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
140 { /* See 10.3.3 */
141 struct { /* Sub-Type 2 */
142 devpath_t hdr; /* Length = 19 + n */
143 uint32_t _HID;
144 uint32_t _UID;
145 uint32_t _CID;
146 char _HIDSTR[]; /* at least NUL byte */
147 // char _UIDSTR[]; /* at least NUL byte */
148 // char _CIDSTR[]; /* at least NUL byte */
149 } __packed *p = (void *)dp;
150 __CTASSERT(sizeof(*p) == 16);
151 char *hidstr = p->_HIDSTR;
152 char *uidstr = hidstr + strlen(hidstr) + 1;
153 char *cidstr = uidstr + strlen(uidstr) + 1;
154
155 #if 0
156 There are 4 different subsubtypes depending on the ?ID, ?IDSTR values.
157
158 "AcpiEx"
159 "AcpiExp"
160 "PciRoot"
161 "PcipRoot"
162 #endif
163 if (p->_HID == PNP0A08 || p->_CID == PNP0A08) {
164 // PcieRoot(UID|UIDSTR)
165 path->sz = easprintf(&path->cp, "PcieRoot(%s)",
166 *uidstr != '\0' ? uidstr : eisaid_to_str(p->_UID));
167 }
168 else if (p->_HID == PNP0A03 || p->_CID == PNP0A03) {
169 assert(p->_HID != PNP0A08);
170 // PciRoot(UID|UIDSTR)
171 path->sz = easprintf(&path->cp, "PciRoot(%s)",
172 *uidstr != '\0' ? uidstr : eisaid_to_str(p->_UID));
173 }
174 else if (hidstr[0] == '\0' && cidstr[0] == '\0' && uidstr[0] != '\0') {
175 assert(p->_HID != 0);
176 path->sz = easprintf(&path->cp, "AcpiExp(%s,%s,%s)", eisaid_to_str(p->_HID),
177 eisaid_to_str(p->_CID), uidstr);
178 }
179 else {
180 path->sz = easprintf(&path->cp, "ACPIEX(%s,%s,0x%x,%s,%s,%s)",
181 eisaid_to_str(p->_HID), eisaid_to_str(p->_CID),
182 p->_UID, hidstr, cidstr, uidstr);
183 }
184
185 if (dbg != NULL) {
186 dbg->sz = easprintf(&dbg->cp,
187 DEVPATH_FMT_HDR
188 DEVPATH_FMT(_HID: 0x%08x(%s)\n)
189 DEVPATH_FMT(_UID: 0x%08x\n)
190 DEVPATH_FMT(_CID: 0x%08x(%s)\n)
191 DEVPATH_FMT(_HIDSTR: %s\n)
192 DEVPATH_FMT(_UIDSTR: %s\n)
193 DEVPATH_FMT(_CIDSTR: %s\n),
194 DEVPATH_DAT_HDR(dp),
195 p->_HID,
196 eisaid_to_str(p->_HID),
197 p->_UID,
198 p->_CID,
199 eisaid_to_str(p->_CID),
200 hidstr,
201 uidstr,
202 cidstr);
203 }
204 }
205
206 static inline void
207 devpath_acpi_adr(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
208 { /* See 10.3.3.1 */
209 struct { /* Sub-Type 3 */
210 devpath_t hdr; /* Length = 8; at least one _ADR */
211 uint32_t _ADR[];
212 } __packed *p = (void *)dp;
213 __CTASSERT(sizeof(*p) == 4);
214 char *tp;
215 size_t cnt;
216
217 cnt = (p->hdr.Length - sizeof(p->hdr)) / sizeof(p->_ADR[0]);
218
219 tp = estrdup("AcpiAdr(");
220 for (size_t i = 0; i < cnt; i++) {
221 path->sz = easprintf(&path->cp, "%s0x%08x%s", tp, p->_ADR[i],
222 i + 1 < cnt ? "," : "");
223 free(tp);
224 tp = path->cp;
225 }
226 path->sz = easprintf(&path->cp, "%s)", tp);
227 free(tp);
228
229 if (dbg != NULL) {
230 dbg->sz = easprintf(&dbg->cp,
231 DEVPATH_FMT_HDR,
232 DEVPATH_DAT_HDR(dp));
233 tp = dbg->cp;
234 for (size_t i = 0; i < cnt; i++) {
235 dbg->sz = easprintf(&dbg->cp, "%s"
236 DEVPATH_FMT(_ADR[%zu]: 0x%08x\n),
237 tp, i, p->_ADR[i]);
238 free(tp);
239 tp = dbg->cp;
240 }
241 }
242 }
243
244 static inline void
245 devpath_acpi_nvdimm(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
246 { /* See 10.3.3.2 */
247 struct { /* Sub-Type 4 */
248 devpath_t hdr; /* Length = 8 */
249 uint32_t NFIT_DevHdl;
250 } __packed *p = (void *)dp;
251 __CTASSERT(sizeof(*p) == 8);
252
253 path->sz = easprintf(&path->cp, "NvdimmAcpiAdr(0x%x)", p->NFIT_DevHdl);
254
255 if (dbg != NULL) {
256 dbg->sz = easprintf(&dbg->cp,
257 DEVPATH_FMT_HDR
258 DEVPATH_FMT(NFIT_DevHdl: 0x%08x\n),
259 DEVPATH_DAT_HDR(dp),
260 p->NFIT_DevHdl);
261 }
262 }
263
264 static inline void
265 devpath_acpi_unknown(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
266 {
267
268 path->sz = easprintf(&path->cp, "Msg(%d,%s)", dp->SubType,
269 encode_data(dp->Data, dp->Length - 4));
270
271 if (dbg != NULL) {
272 dbg->sz = easprintf(&dbg->cp,
273 DEVPATH_FMT_HDR,
274 DEVPATH_DAT_HDR(dp));
275 }
276 }
277
278 PUBLIC void
279 devpath_acpi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
280 {
281
282 assert(dp->Type = 2);
283
284 switch (dp->SubType) {
285 case 1: devpath_acpi_acpi(dp, path, dbg); return;
286 case 2: devpath_acpi_acpiex(dp, path, dbg); return;
287 case 3: devpath_acpi_adr(dp, path, dbg); return;
288 case 4: devpath_acpi_nvdimm(dp, path, dbg); return;
289 default: devpath_unsupported(dp, path, dbg); return;
290 }
291 }
292