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