1 /* $NetBSD: devpath2.c,v 1.6 2025/03/02 14:18:04 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.6 2025/03/02 14:18:04 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 + 1), dp->Length - sizeof(*dp))); 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