Home | History | Annotate | Line # | Download | only in efi
      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