Home | History | Annotate | Line # | Download | only in efi
devpath1.c revision 1.1
      1 /* $NetBSD: devpath1.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: devpath1.c,v 1.1 2025/02/24 13:47:56 christos 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%016tx,0x%016tx)", typename,
    161 	    p->StartAddress, p->EndAddress);
    162 
    163 	if (dbg != NULL) {
    164 		dbg->sz = easprintf(&dbg->cp,
    165 		    DEVPATH_FMT_HDR
    166 		    DEVPATH_FMT(MemoryType: 0x%08x(%s)\n)
    167 		    DEVPATH_FMT(StartAddress: 0x%016tx\n)
    168 		    DEVPATH_FMT(EndAddress: 0x%016tx\n),
    169 		    DEVPATH_DAT_HDR(dp),
    170 		    p->MemoryType, typename,
    171 		    p->StartAddress,
    172 		    p->EndAddress);
    173 
    174 	}
    175 }
    176 
    177 #ifdef EFI_EDD10_PATH_GUID
    178 static inline void
    179 devpath_hw_edd10(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    180 {	/* See unknown - snarfed from efivar-main.zip */
    181 	struct { /* Sub-Type 4 */
    182 		devpath_t	hdr;	/* Length = 24 */
    183 		uuid_t		GUID;
    184 		uint32_t	devnum;
    185 	} __packed *p = (void *)dp;
    186 	__CTASSERT(sizeof(*p) == 24);
    187 
    188 	assert(p->hdr.Length == 24);
    189 
    190 	/*
    191 	 * p->data will be printed by debug
    192 	 */
    193 	path->sz = easprintf(&path->cp, "EDD10(0x%02x)", p->devnum);
    194 
    195 	if (dbg != NULL) {
    196 		char uuid_str[UUID_STR_LEN];
    197 
    198 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    199 		dbg->sz = easprintf(&dbg->cp,
    200 		    DEVPATH_FMT_HDR
    201 		    DEVPATH_FMT(GUID: %s\n)
    202 		    DEVPATH_FMT(devnum: 0x%08x\n),
    203 		    DEVPATH_DAT_HDR(dp),
    204 		    uuid_str,
    205 		    p->devnum);
    206 	}
    207 }
    208 #endif /* EFI_EDD10_PATH_GUID */
    209 
    210 static inline void
    211 devpath_hw_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    212 {	/* See 10.3.2.4 */
    213 	struct { /* Sub-Type 4 */
    214 		devpath_t	hdr;	/* Length = 20 + n */
    215 		uuid_t		GUID;
    216 		uint8_t		data[];
    217 	} __packed *p = (void *)dp;
    218 	__CTASSERT(sizeof(*p) == 20);
    219 	char uuid_str[UUID_STR_LEN];
    220 
    221 #ifdef EFI_EDD10_PATH_GUID
    222 	if (memcmp(&p->GUID, &EFI_EDD10_PATH_GUID, sizeof(uuid_t)) == 0) {
    223 		devpath_hw_edd10(dp, path, dbg);
    224 		return;
    225 	}
    226 #endif /* EFI_EDD10_PATH_GUID */
    227 
    228 	uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    229 
    230 	/*
    231 	 * p->data will be printed by debug
    232 	 */
    233 	path->sz = easprintf(&path->cp, "VenHw(%s)", uuid_str);
    234 
    235 	if (dbg != NULL) {
    236 		dbg->sz = easprintf(&dbg->cp,
    237 		    DEVPATH_FMT_HDR
    238 		    DEVPATH_FMT(GUID: %s\n),
    239 		    DEVPATH_DAT_HDR(dp),
    240 		    uuid_str);
    241 	}
    242 }
    243 
    244 static inline void
    245 devpath_hw_controller(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    246 {	/* See 10.3.2.5 */
    247 	struct { /* Sub-Type 5 */
    248 		devpath_t	hdr;	/* Length = 8 */
    249 		uint32_t	CtrlNum;
    250 	} __packed *p = (void *)dp;
    251 	__CTASSERT(sizeof(*p) == 8);
    252 
    253 	path->sz = easprintf(&path->cp, "Ctrl(0x%x)", p->CtrlNum);
    254 
    255 	if (dbg != NULL) {
    256 		dbg->sz = easprintf(&dbg->cp,
    257 		    DEVPATH_FMT_HDR
    258 		    DEVPATH_FMT(CtrlNum: 0x%x\n),
    259 		    DEVPATH_DAT_HDR(dp),
    260 		    p->CtrlNum);
    261 	}
    262 }
    263 
    264 static inline const char *
    265 devpath_hw_bmc_iftype(uint type)
    266 {
    267 	static const char *tbl[] = {
    268 		[0] = "Unknown",
    269 		[1] = "KCS",	// Keyboard Controller Style
    270 		[2] = "SMIC",	// Server Management Interface Chip
    271 		[3] = "BT",	// Block Transfer
    272 	};
    273 
    274 	if (type >= __arraycount(tbl))
    275 		type = 0;
    276 
    277 	return tbl[type];
    278 }
    279 
    280 /* Baseboard Management Controller */
    281 static inline void
    282 devpath_hw_bmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    283 {	/* See 10.3.2.6 */
    284 	struct { /* Sub-Type 6 */
    285 		devpath_t	hdr;	/* Length = 13 */
    286 		uint8_t		IfaceType;
    287 		uint64_t	BaseAddress;
    288 	} __packed *p = (void *)dp;
    289 	__CTASSERT(sizeof(*p) == 13);
    290 	const char *iftype;
    291 
    292 	iftype = devpath_hw_bmc_iftype(p->IfaceType);
    293 
    294 	path->sz = easprintf(&path->cp, "(%s,0x%016tx)", iftype, p->BaseAddress);
    295 
    296 	if (dbg != NULL) {
    297 		dbg->sz = easprintf(&dbg->cp,
    298 		    DEVPATH_FMT_HDR
    299 		    DEVPATH_FMT(IfaceType: %u(%s)\n)
    300 		    DEVPATH_FMT(BaseAddress: 0x%016tx\n),
    301 		    DEVPATH_DAT_HDR(dp),
    302 		    p->IfaceType, iftype,
    303 		    p->BaseAddress);
    304 	}
    305 }
    306 
    307 PUBLIC void
    308 devpath_hw(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    309 {
    310 
    311 	assert(dp->Type = 1);
    312 
    313 	switch (dp->SubType) {
    314 	case 1:   devpath_hw_pci(dp, path, dbg);		return;
    315 	case 2:   devpath_hw_pccard(dp, path, dbg);		return;
    316 	case 3:   devpath_hw_memmap(dp, path, dbg);		return;
    317 	case 4:   devpath_hw_vendor(dp, path, dbg);		return;
    318 	case 5:   devpath_hw_controller(dp, path, dbg);		return;
    319 	case 6:   devpath_hw_bmc(dp, path, dbg);		return;
    320 	default:  devpath_unsupported(dp, path, dbg);		return;
    321 	}
    322 }
    323