Home | History | Annotate | Line # | Download | only in efi
      1 /* $NetBSD: devpath1.c,v 1.4 2025/03/02 00:23:59 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: devpath1.c,v 1.4 2025/03/02 00:23:59 riastradh Exp $");
     29 #endif /* not lint */
     30 
     31 #include <sys/uuid.h>
     32 
     33 #include <assert.h>
     34 #include <stdio.h>
     35 #include <util.h>
     36 
     37 #include "defs.h"
     38 #include "devpath.h"
     39 #include "devpath1.h"
     40 #include "utils.h"
     41 
     42 #define easprintf	(size_t)easprintf
     43 
     44 /************************************************************************
     45  * Type 1 - PCI Device Path
     46  ************************************************************************/
     47 
     48 /*
     49  * XXX: I can't find this GUID documented anywhere online.  I snarfed
     50  * it from
     51  * https://github.com/rhboot/efivar::efivar-main/src/include/efivar/efivar-dp.h
     52  * Comment out the define if you don't want to use it.
     53  */
     54 /* Used in subtype 4 */
     55 #if 1
     56 #define EFI_EDD10_PATH_GUID						      \
     57 	((uuid_t){0xcf31fac5,0xc24e,0x11d2,0x85,0xf3,			      \
     58 	    {0x00,0xa0,0xc9,0x3e,0xc9,0x3b}})
     59 #endif
     60 
     61 #define EFI_MEMORY_TYPE \
     62 	_X(ReservedMemoryType)		\
     63 	_X(LoaderCode)			\
     64 	_X(LoaderData)			\
     65 	_X(BootServicesCode)		\
     66 	_X(BootServicesData)		\
     67 	_X(RuntimeServicesCode)		\
     68 	_X(RuntimeServicesData)		\
     69 	_X(ConventionalMemory)		\
     70 	_X(UnusableMemory)		\
     71 	_X(ACPIReclaimMemory)		\
     72 	_X(ACPIMemoryNVS)		\
     73 	_X(MemoryMappedIO)		\
     74 	_X(MemoryMappedIOPortSpace)	\
     75 	_X(PalCode)			\
     76 	_X(PersistentMemory)		\
     77 	_X(UnacceptedMemoryType)	\
     78 	_X(MaxMemoryTyp)
     79 
     80 typedef enum {
     81 #define _X(n)	Efi ## n,
     82 	EFI_MEMORY_TYPE
     83 #undef _X
     84 } EfiMemoryType_t;
     85 
     86 static const char *
     87 efi_memory_type_name(EfiMemoryType_t t)
     88 {
     89 	static const char *memtype[] = {
     90 #define _X(n)	#n,
     91 		EFI_MEMORY_TYPE
     92 #undef _X
     93 	};
     94 
     95 	if (t >= __arraycount(memtype))
     96 		return "Unknown";
     97 
     98 	return memtype[t];
     99 }
    100 
    101 /****************************************/
    102 
    103 static inline void
    104 devpath_hw_pci(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    105 {	/* See 10.3.2.2 */
    106 	struct { /* Sub-Type 1 */
    107 		devpath_t	hdr;	/* Length = 6 */
    108 		uint8_t		FunctionNum;
    109 		uint8_t		DeviceNum;
    110 	} __packed *p = (void *)dp;
    111 	__CTASSERT(sizeof(*p) == 6);
    112 
    113 	path->sz = easprintf(&path->cp, "Pci(0x%x,0x%x)",
    114 	    p->DeviceNum, p->FunctionNum);
    115 
    116 	if (dbg != NULL) {
    117 		dbg->sz = easprintf(&dbg->cp,
    118 		    DEVPATH_FMT_HDR
    119 		    DEVPATH_FMT(FunctionNum: %u\n)
    120 		    DEVPATH_FMT(DeviceNum: %u\n),
    121 		    DEVPATH_DAT_HDR(dp),
    122 		    p->FunctionNum,
    123 		    p->DeviceNum);
    124 	}
    125 }
    126 
    127 static inline void
    128 devpath_hw_pccard(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    129 {	/* See 10.3.2.2 */
    130 	struct { /* Sub-Type 2 */
    131 		devpath_t	hdr;	/* Length = 5 */
    132 		uint8_t		FunctionNum;
    133 	} __packed *p = (void *)dp;
    134 	__CTASSERT(sizeof(*p) == 5);
    135 
    136 	path->sz = easprintf(&path->cp, "PcCard(0x%x)", p->FunctionNum);
    137 
    138 	if (dbg != NULL) {
    139 		dbg->sz = easprintf(&dbg->cp,
    140 		    DEVPATH_FMT_HDR
    141 		    DEVPATH_FMT(FunctionNum: %u\n),
    142 		    DEVPATH_DAT_HDR(dp),
    143 		    p->FunctionNum);
    144 	}
    145 }
    146 
    147 static inline void
    148 devpath_hw_memmap(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    149 {	/* See 10.3.2.3 */
    150 	struct { /* Sub-Type 3 */
    151 		devpath_t	hdr;	/* Length = 24 */
    152 		uint32_t	MemoryType;
    153 		uint64_t	StartAddress;
    154 		uint64_t	EndAddress;
    155 	} __packed *p = (void *)dp;
    156 	__CTASSERT(sizeof(*p) == 24);
    157 	const char *typename;
    158 
    159 	typename = efi_memory_type_name(p->MemoryType);
    160 
    161 	path->sz = easprintf(&path->cp, "MemMap(%s,0x%016" PRIx64
    162 	    ",0x%016" PRIx64 ")", typename,
    163 	    p->StartAddress, p->EndAddress);
    164 
    165 	if (dbg != NULL) {
    166 		dbg->sz = easprintf(&dbg->cp,
    167 		    DEVPATH_FMT_HDR
    168 		    DEVPATH_FMT(MemoryType: 0x%08x(%s)\n)
    169 		    DEVPATH_FMT(StartAddress:) " 0x%016" PRIx64 "\n"
    170 		    DEVPATH_FMT(EndAddress:) " 0x%016" PRIx64 "\n",
    171 		    DEVPATH_DAT_HDR(dp),
    172 		    p->MemoryType, typename,
    173 		    p->StartAddress,
    174 		    p->EndAddress);
    175 
    176 	}
    177 }
    178 
    179 #ifdef EFI_EDD10_PATH_GUID
    180 static inline void
    181 devpath_hw_edd10(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    182 {	/* See unknown - snarfed from efivar-main.zip */
    183 	struct { /* Sub-Type 4 */
    184 		devpath_t	hdr;	/* Length = 24 */
    185 		uuid_t		GUID;
    186 		uint32_t	devnum;
    187 	} __packed *p = (void *)dp;
    188 	__CTASSERT(sizeof(*p) == 24);
    189 
    190 	assert(p->hdr.Length == 24);
    191 
    192 	/*
    193 	 * p->data will be printed by debug
    194 	 */
    195 	path->sz = easprintf(&path->cp, "EDD10(0x%02x)", p->devnum);
    196 
    197 	if (dbg != NULL) {
    198 		char uuid_str[UUID_STR_LEN];
    199 
    200 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    201 		dbg->sz = easprintf(&dbg->cp,
    202 		    DEVPATH_FMT_HDR
    203 		    DEVPATH_FMT(GUID: %s\n)
    204 		    DEVPATH_FMT(devnum: 0x%08x\n),
    205 		    DEVPATH_DAT_HDR(dp),
    206 		    uuid_str,
    207 		    p->devnum);
    208 	}
    209 }
    210 #endif /* EFI_EDD10_PATH_GUID */
    211 
    212 static inline void
    213 devpath_hw_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    214 {	/* See 10.3.2.4 */
    215 	struct { /* Sub-Type 4 */
    216 		devpath_t	hdr;	/* Length = 20 + n */
    217 		uuid_t		GUID;
    218 		uint8_t		data[];
    219 	} __packed *p = (void *)dp;
    220 	__CTASSERT(sizeof(*p) == 20);
    221 	char uuid_str[UUID_STR_LEN];
    222 
    223 #ifdef EFI_EDD10_PATH_GUID
    224 	if (memcmp(&p->GUID, &EFI_EDD10_PATH_GUID, sizeof(uuid_t)) == 0) {
    225 		devpath_hw_edd10(dp, path, dbg);
    226 		return;
    227 	}
    228 #endif /* EFI_EDD10_PATH_GUID */
    229 
    230 	uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    231 
    232 	/*
    233 	 * p->data will be printed by debug
    234 	 */
    235 	path->sz = easprintf(&path->cp, "VenHw(%s)", uuid_str);
    236 
    237 	if (dbg != NULL) {
    238 		dbg->sz = easprintf(&dbg->cp,
    239 		    DEVPATH_FMT_HDR
    240 		    DEVPATH_FMT(GUID: %s\n),
    241 		    DEVPATH_DAT_HDR(dp),
    242 		    uuid_str);
    243 	}
    244 }
    245 
    246 static inline void
    247 devpath_hw_controller(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    248 {	/* See 10.3.2.5 */
    249 	struct { /* Sub-Type 5 */
    250 		devpath_t	hdr;	/* Length = 8 */
    251 		uint32_t	CtrlNum;
    252 	} __packed *p = (void *)dp;
    253 	__CTASSERT(sizeof(*p) == 8);
    254 
    255 	path->sz = easprintf(&path->cp, "Ctrl(0x%x)", p->CtrlNum);
    256 
    257 	if (dbg != NULL) {
    258 		dbg->sz = easprintf(&dbg->cp,
    259 		    DEVPATH_FMT_HDR
    260 		    DEVPATH_FMT(CtrlNum: 0x%x\n),
    261 		    DEVPATH_DAT_HDR(dp),
    262 		    p->CtrlNum);
    263 	}
    264 }
    265 
    266 static inline const char *
    267 devpath_hw_bmc_iftype(uint type)
    268 {
    269 	static const char *tbl[] = {
    270 		[0] = "Unknown",
    271 		[1] = "KCS",	// Keyboard Controller Style
    272 		[2] = "SMIC",	// Server Management Interface Chip
    273 		[3] = "BT",	// Block Transfer
    274 	};
    275 
    276 	if (type >= __arraycount(tbl))
    277 		type = 0;
    278 
    279 	return tbl[type];
    280 }
    281 
    282 /* Baseboard Management Controller */
    283 static inline void
    284 devpath_hw_bmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    285 {	/* See 10.3.2.6 */
    286 	struct { /* Sub-Type 6 */
    287 		devpath_t	hdr;	/* Length = 13 */
    288 		uint8_t		IfaceType;
    289 		uint64_t	BaseAddress;
    290 	} __packed *p = (void *)dp;
    291 	__CTASSERT(sizeof(*p) == 13);
    292 	const char *iftype;
    293 
    294 	iftype = devpath_hw_bmc_iftype(p->IfaceType);
    295 
    296 	path->sz = easprintf(&path->cp, "(%s,0x%016" PRIx64 ")",
    297 	    iftype, p->BaseAddress);
    298 
    299 	if (dbg != NULL) {
    300 		dbg->sz = easprintf(&dbg->cp,
    301 		    DEVPATH_FMT_HDR
    302 		    DEVPATH_FMT(IfaceType: %u(%s)\n)
    303 		    DEVPATH_FMT(BaseAddress:) " 0x%016" PRIx64 "\n",
    304 		    DEVPATH_DAT_HDR(dp),
    305 		    p->IfaceType, iftype,
    306 		    p->BaseAddress);
    307 	}
    308 }
    309 
    310 PUBLIC void
    311 devpath_hw(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    312 {
    313 
    314 	assert(dp->Type = 1);
    315 
    316 	switch (dp->SubType) {
    317 	case 1:   devpath_hw_pci(dp, path, dbg);		return;
    318 	case 2:   devpath_hw_pccard(dp, path, dbg);		return;
    319 	case 3:   devpath_hw_memmap(dp, path, dbg);		return;
    320 	case 4:   devpath_hw_vendor(dp, path, dbg);		return;
    321 	case 5:   devpath_hw_controller(dp, path, dbg);		return;
    322 	case 6:   devpath_hw_bmc(dp, path, dbg);		return;
    323 	default:  devpath_unsupported(dp, path, dbg);		return;
    324 	}
    325 }
    326