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