1 1.4 riastrad /* $NetBSD: devpath1.c,v 1.4 2025/03/02 00:23:59 riastradh Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Redistribution and use in source and binary forms, with or without 5 1.1 christos * modification, are permitted provided that the following conditions 6 1.1 christos * are met: 7 1.1 christos * 1. Redistributions of source code must retain the above copyright 8 1.1 christos * notice, this list of conditions and the following disclaimer. 9 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 10 1.1 christos * notice, this list of conditions and the following disclaimer in the 11 1.1 christos * documentation and/or other materials provided with the distribution. 12 1.1 christos * 13 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 14 1.1 christos * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 1.1 christos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 1.1 christos * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 1.1 christos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 1.1 christos * SUCH DAMAGE. 24 1.1 christos */ 25 1.1 christos 26 1.1 christos #include <sys/cdefs.h> 27 1.1 christos #ifndef lint 28 1.4 riastrad __RCSID("$NetBSD: devpath1.c,v 1.4 2025/03/02 00:23:59 riastradh Exp $"); 29 1.1 christos #endif /* not lint */ 30 1.1 christos 31 1.1 christos #include <sys/uuid.h> 32 1.1 christos 33 1.1 christos #include <assert.h> 34 1.1 christos #include <stdio.h> 35 1.1 christos #include <util.h> 36 1.1 christos 37 1.1 christos #include "defs.h" 38 1.1 christos #include "devpath.h" 39 1.1 christos #include "devpath1.h" 40 1.1 christos #include "utils.h" 41 1.1 christos 42 1.1 christos #define easprintf (size_t)easprintf 43 1.1 christos 44 1.1 christos /************************************************************************ 45 1.1 christos * Type 1 - PCI Device Path 46 1.1 christos ************************************************************************/ 47 1.1 christos 48 1.1 christos /* 49 1.1 christos * XXX: I can't find this GUID documented anywhere online. I snarfed 50 1.1 christos * it from 51 1.1 christos * https://github.com/rhboot/efivar::efivar-main/src/include/efivar/efivar-dp.h 52 1.1 christos * Comment out the define if you don't want to use it. 53 1.1 christos */ 54 1.1 christos /* Used in subtype 4 */ 55 1.1 christos #if 1 56 1.4 riastrad #define EFI_EDD10_PATH_GUID \ 57 1.4 riastrad ((uuid_t){0xcf31fac5,0xc24e,0x11d2,0x85,0xf3, \ 58 1.4 riastrad {0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}) 59 1.1 christos #endif 60 1.1 christos 61 1.1 christos #define EFI_MEMORY_TYPE \ 62 1.1 christos _X(ReservedMemoryType) \ 63 1.1 christos _X(LoaderCode) \ 64 1.1 christos _X(LoaderData) \ 65 1.1 christos _X(BootServicesCode) \ 66 1.1 christos _X(BootServicesData) \ 67 1.1 christos _X(RuntimeServicesCode) \ 68 1.1 christos _X(RuntimeServicesData) \ 69 1.1 christos _X(ConventionalMemory) \ 70 1.1 christos _X(UnusableMemory) \ 71 1.1 christos _X(ACPIReclaimMemory) \ 72 1.1 christos _X(ACPIMemoryNVS) \ 73 1.1 christos _X(MemoryMappedIO) \ 74 1.1 christos _X(MemoryMappedIOPortSpace) \ 75 1.1 christos _X(PalCode) \ 76 1.1 christos _X(PersistentMemory) \ 77 1.1 christos _X(UnacceptedMemoryType) \ 78 1.1 christos _X(MaxMemoryTyp) 79 1.1 christos 80 1.1 christos typedef enum { 81 1.1 christos #define _X(n) Efi ## n, 82 1.1 christos EFI_MEMORY_TYPE 83 1.1 christos #undef _X 84 1.1 christos } EfiMemoryType_t; 85 1.1 christos 86 1.1 christos static const char * 87 1.1 christos efi_memory_type_name(EfiMemoryType_t t) 88 1.1 christos { 89 1.1 christos static const char *memtype[] = { 90 1.1 christos #define _X(n) #n, 91 1.1 christos EFI_MEMORY_TYPE 92 1.1 christos #undef _X 93 1.1 christos }; 94 1.1 christos 95 1.1 christos if (t >= __arraycount(memtype)) 96 1.1 christos return "Unknown"; 97 1.1 christos 98 1.1 christos return memtype[t]; 99 1.1 christos } 100 1.1 christos 101 1.1 christos /****************************************/ 102 1.1 christos 103 1.1 christos static inline void 104 1.1 christos devpath_hw_pci(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 105 1.1 christos { /* See 10.3.2.2 */ 106 1.1 christos struct { /* Sub-Type 1 */ 107 1.1 christos devpath_t hdr; /* Length = 6 */ 108 1.1 christos uint8_t FunctionNum; 109 1.1 christos uint8_t DeviceNum; 110 1.1 christos } __packed *p = (void *)dp; 111 1.1 christos __CTASSERT(sizeof(*p) == 6); 112 1.1 christos 113 1.1 christos path->sz = easprintf(&path->cp, "Pci(0x%x,0x%x)", 114 1.1 christos p->DeviceNum, p->FunctionNum); 115 1.1 christos 116 1.1 christos if (dbg != NULL) { 117 1.1 christos dbg->sz = easprintf(&dbg->cp, 118 1.1 christos DEVPATH_FMT_HDR 119 1.1 christos DEVPATH_FMT(FunctionNum: %u\n) 120 1.1 christos DEVPATH_FMT(DeviceNum: %u\n), 121 1.1 christos DEVPATH_DAT_HDR(dp), 122 1.1 christos p->FunctionNum, 123 1.1 christos p->DeviceNum); 124 1.1 christos } 125 1.1 christos } 126 1.1 christos 127 1.1 christos static inline void 128 1.1 christos devpath_hw_pccard(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 129 1.1 christos { /* See 10.3.2.2 */ 130 1.1 christos struct { /* Sub-Type 2 */ 131 1.1 christos devpath_t hdr; /* Length = 5 */ 132 1.1 christos uint8_t FunctionNum; 133 1.1 christos } __packed *p = (void *)dp; 134 1.1 christos __CTASSERT(sizeof(*p) == 5); 135 1.1 christos 136 1.1 christos path->sz = easprintf(&path->cp, "PcCard(0x%x)", p->FunctionNum); 137 1.1 christos 138 1.1 christos if (dbg != NULL) { 139 1.1 christos dbg->sz = easprintf(&dbg->cp, 140 1.1 christos DEVPATH_FMT_HDR 141 1.1 christos DEVPATH_FMT(FunctionNum: %u\n), 142 1.1 christos DEVPATH_DAT_HDR(dp), 143 1.1 christos p->FunctionNum); 144 1.1 christos } 145 1.1 christos } 146 1.1 christos 147 1.1 christos static inline void 148 1.1 christos devpath_hw_memmap(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 149 1.1 christos { /* See 10.3.2.3 */ 150 1.1 christos struct { /* Sub-Type 3 */ 151 1.1 christos devpath_t hdr; /* Length = 24 */ 152 1.1 christos uint32_t MemoryType; 153 1.1 christos uint64_t StartAddress; 154 1.1 christos uint64_t EndAddress; 155 1.1 christos } __packed *p = (void *)dp; 156 1.1 christos __CTASSERT(sizeof(*p) == 24); 157 1.1 christos const char *typename; 158 1.1 christos 159 1.1 christos typename = efi_memory_type_name(p->MemoryType); 160 1.1 christos 161 1.2 martin path->sz = easprintf(&path->cp, "MemMap(%s,0x%016" PRIx64 162 1.2 martin ",0x%016" PRIx64 ")", typename, 163 1.1 christos p->StartAddress, p->EndAddress); 164 1.1 christos 165 1.1 christos if (dbg != NULL) { 166 1.1 christos dbg->sz = easprintf(&dbg->cp, 167 1.1 christos DEVPATH_FMT_HDR 168 1.1 christos DEVPATH_FMT(MemoryType: 0x%08x(%s)\n) 169 1.2 martin DEVPATH_FMT(StartAddress:) " 0x%016" PRIx64 "\n" 170 1.2 martin DEVPATH_FMT(EndAddress:) " 0x%016" PRIx64 "\n", 171 1.1 christos DEVPATH_DAT_HDR(dp), 172 1.1 christos p->MemoryType, typename, 173 1.1 christos p->StartAddress, 174 1.1 christos p->EndAddress); 175 1.3 riastrad 176 1.1 christos } 177 1.1 christos } 178 1.1 christos 179 1.1 christos #ifdef EFI_EDD10_PATH_GUID 180 1.1 christos static inline void 181 1.1 christos devpath_hw_edd10(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 182 1.1 christos { /* See unknown - snarfed from efivar-main.zip */ 183 1.1 christos struct { /* Sub-Type 4 */ 184 1.1 christos devpath_t hdr; /* Length = 24 */ 185 1.1 christos uuid_t GUID; 186 1.1 christos uint32_t devnum; 187 1.1 christos } __packed *p = (void *)dp; 188 1.1 christos __CTASSERT(sizeof(*p) == 24); 189 1.1 christos 190 1.1 christos assert(p->hdr.Length == 24); 191 1.1 christos 192 1.1 christos /* 193 1.1 christos * p->data will be printed by debug 194 1.1 christos */ 195 1.1 christos path->sz = easprintf(&path->cp, "EDD10(0x%02x)", p->devnum); 196 1.1 christos 197 1.1 christos if (dbg != NULL) { 198 1.1 christos char uuid_str[UUID_STR_LEN]; 199 1.1 christos 200 1.1 christos uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); 201 1.1 christos dbg->sz = easprintf(&dbg->cp, 202 1.1 christos DEVPATH_FMT_HDR 203 1.1 christos DEVPATH_FMT(GUID: %s\n) 204 1.1 christos DEVPATH_FMT(devnum: 0x%08x\n), 205 1.1 christos DEVPATH_DAT_HDR(dp), 206 1.1 christos uuid_str, 207 1.1 christos p->devnum); 208 1.1 christos } 209 1.1 christos } 210 1.1 christos #endif /* EFI_EDD10_PATH_GUID */ 211 1.1 christos 212 1.1 christos static inline void 213 1.1 christos devpath_hw_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 214 1.1 christos { /* See 10.3.2.4 */ 215 1.1 christos struct { /* Sub-Type 4 */ 216 1.1 christos devpath_t hdr; /* Length = 20 + n */ 217 1.1 christos uuid_t GUID; 218 1.1 christos uint8_t data[]; 219 1.1 christos } __packed *p = (void *)dp; 220 1.1 christos __CTASSERT(sizeof(*p) == 20); 221 1.1 christos char uuid_str[UUID_STR_LEN]; 222 1.1 christos 223 1.1 christos #ifdef EFI_EDD10_PATH_GUID 224 1.1 christos if (memcmp(&p->GUID, &EFI_EDD10_PATH_GUID, sizeof(uuid_t)) == 0) { 225 1.1 christos devpath_hw_edd10(dp, path, dbg); 226 1.1 christos return; 227 1.1 christos } 228 1.1 christos #endif /* EFI_EDD10_PATH_GUID */ 229 1.1 christos 230 1.1 christos uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); 231 1.1 christos 232 1.1 christos /* 233 1.1 christos * p->data will be printed by debug 234 1.1 christos */ 235 1.1 christos path->sz = easprintf(&path->cp, "VenHw(%s)", uuid_str); 236 1.1 christos 237 1.1 christos if (dbg != NULL) { 238 1.1 christos dbg->sz = easprintf(&dbg->cp, 239 1.1 christos DEVPATH_FMT_HDR 240 1.1 christos DEVPATH_FMT(GUID: %s\n), 241 1.1 christos DEVPATH_DAT_HDR(dp), 242 1.1 christos uuid_str); 243 1.1 christos } 244 1.1 christos } 245 1.1 christos 246 1.1 christos static inline void 247 1.1 christos devpath_hw_controller(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 248 1.1 christos { /* See 10.3.2.5 */ 249 1.1 christos struct { /* Sub-Type 5 */ 250 1.1 christos devpath_t hdr; /* Length = 8 */ 251 1.1 christos uint32_t CtrlNum; 252 1.1 christos } __packed *p = (void *)dp; 253 1.1 christos __CTASSERT(sizeof(*p) == 8); 254 1.1 christos 255 1.1 christos path->sz = easprintf(&path->cp, "Ctrl(0x%x)", p->CtrlNum); 256 1.1 christos 257 1.1 christos if (dbg != NULL) { 258 1.1 christos dbg->sz = easprintf(&dbg->cp, 259 1.1 christos DEVPATH_FMT_HDR 260 1.1 christos DEVPATH_FMT(CtrlNum: 0x%x\n), 261 1.1 christos DEVPATH_DAT_HDR(dp), 262 1.1 christos p->CtrlNum); 263 1.1 christos } 264 1.1 christos } 265 1.1 christos 266 1.1 christos static inline const char * 267 1.1 christos devpath_hw_bmc_iftype(uint type) 268 1.1 christos { 269 1.1 christos static const char *tbl[] = { 270 1.1 christos [0] = "Unknown", 271 1.1 christos [1] = "KCS", // Keyboard Controller Style 272 1.1 christos [2] = "SMIC", // Server Management Interface Chip 273 1.1 christos [3] = "BT", // Block Transfer 274 1.1 christos }; 275 1.1 christos 276 1.1 christos if (type >= __arraycount(tbl)) 277 1.1 christos type = 0; 278 1.1 christos 279 1.1 christos return tbl[type]; 280 1.1 christos } 281 1.1 christos 282 1.1 christos /* Baseboard Management Controller */ 283 1.1 christos static inline void 284 1.1 christos devpath_hw_bmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 285 1.1 christos { /* See 10.3.2.6 */ 286 1.1 christos struct { /* Sub-Type 6 */ 287 1.1 christos devpath_t hdr; /* Length = 13 */ 288 1.1 christos uint8_t IfaceType; 289 1.1 christos uint64_t BaseAddress; 290 1.1 christos } __packed *p = (void *)dp; 291 1.1 christos __CTASSERT(sizeof(*p) == 13); 292 1.1 christos const char *iftype; 293 1.1 christos 294 1.1 christos iftype = devpath_hw_bmc_iftype(p->IfaceType); 295 1.1 christos 296 1.4 riastrad path->sz = easprintf(&path->cp, "(%s,0x%016" PRIx64 ")", 297 1.4 riastrad iftype, p->BaseAddress); 298 1.1 christos 299 1.1 christos if (dbg != NULL) { 300 1.1 christos dbg->sz = easprintf(&dbg->cp, 301 1.1 christos DEVPATH_FMT_HDR 302 1.1 christos DEVPATH_FMT(IfaceType: %u(%s)\n) 303 1.2 martin DEVPATH_FMT(BaseAddress:) " 0x%016" PRIx64 "\n", 304 1.1 christos DEVPATH_DAT_HDR(dp), 305 1.1 christos p->IfaceType, iftype, 306 1.1 christos p->BaseAddress); 307 1.1 christos } 308 1.1 christos } 309 1.1 christos 310 1.1 christos PUBLIC void 311 1.1 christos devpath_hw(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 312 1.1 christos { 313 1.1 christos 314 1.1 christos assert(dp->Type = 1); 315 1.1 christos 316 1.1 christos switch (dp->SubType) { 317 1.1 christos case 1: devpath_hw_pci(dp, path, dbg); return; 318 1.1 christos case 2: devpath_hw_pccard(dp, path, dbg); return; 319 1.1 christos case 3: devpath_hw_memmap(dp, path, dbg); return; 320 1.1 christos case 4: devpath_hw_vendor(dp, path, dbg); return; 321 1.1 christos case 5: devpath_hw_controller(dp, path, dbg); return; 322 1.1 christos case 6: devpath_hw_bmc(dp, path, dbg); return; 323 1.1 christos default: devpath_unsupported(dp, path, dbg); return; 324 1.1 christos } 325 1.1 christos } 326