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