/* $NetBSD: devpath1.c,v 1.2 2025/02/24 15:42:05 martin Exp $ */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: devpath1.c,v 1.2 2025/02/24 15:42:05 martin Exp $"); #endif /* not lint */ #include #include #include #include #include "defs.h" #include "devpath.h" #include "devpath1.h" #include "utils.h" #define easprintf (size_t)easprintf /************************************************************************ * Type 1 - PCI Device Path ************************************************************************/ /* * XXX: I can't find this GUID documented anywhere online. I snarfed * it from * https://github.com/rhboot/efivar::efivar-main/src/include/efivar/efivar-dp.h * Comment out the define if you don't want to use it. */ /* Used in subtype 4 */ #if 1 #define EFI_EDD10_PATH_GUID\ ((uuid_t){0xcf31fac5,0xc24e,0x11d2,0x85,0xf3,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}) #endif #define EFI_MEMORY_TYPE \ _X(ReservedMemoryType) \ _X(LoaderCode) \ _X(LoaderData) \ _X(BootServicesCode) \ _X(BootServicesData) \ _X(RuntimeServicesCode) \ _X(RuntimeServicesData) \ _X(ConventionalMemory) \ _X(UnusableMemory) \ _X(ACPIReclaimMemory) \ _X(ACPIMemoryNVS) \ _X(MemoryMappedIO) \ _X(MemoryMappedIOPortSpace) \ _X(PalCode) \ _X(PersistentMemory) \ _X(UnacceptedMemoryType) \ _X(MaxMemoryTyp) typedef enum { #define _X(n) Efi ## n, EFI_MEMORY_TYPE #undef _X } EfiMemoryType_t; static const char * efi_memory_type_name(EfiMemoryType_t t) { static const char *memtype[] = { #define _X(n) #n, EFI_MEMORY_TYPE #undef _X }; if (t >= __arraycount(memtype)) return "Unknown"; return memtype[t]; } /****************************************/ static inline void devpath_hw_pci(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.2 */ struct { /* Sub-Type 1 */ devpath_t hdr; /* Length = 6 */ uint8_t FunctionNum; uint8_t DeviceNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 6); path->sz = easprintf(&path->cp, "Pci(0x%x,0x%x)", p->DeviceNum, p->FunctionNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(FunctionNum: %u\n) DEVPATH_FMT(DeviceNum: %u\n), DEVPATH_DAT_HDR(dp), p->FunctionNum, p->DeviceNum); } } static inline void devpath_hw_pccard(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.2 */ struct { /* Sub-Type 2 */ devpath_t hdr; /* Length = 5 */ uint8_t FunctionNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 5); path->sz = easprintf(&path->cp, "PcCard(0x%x)", p->FunctionNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(FunctionNum: %u\n), DEVPATH_DAT_HDR(dp), p->FunctionNum); } } static inline void devpath_hw_memmap(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.3 */ struct { /* Sub-Type 3 */ devpath_t hdr; /* Length = 24 */ uint32_t MemoryType; uint64_t StartAddress; uint64_t EndAddress; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); const char *typename; typename = efi_memory_type_name(p->MemoryType); path->sz = easprintf(&path->cp, "MemMap(%s,0x%016" PRIx64 ",0x%016" PRIx64 ")", typename, p->StartAddress, p->EndAddress); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(MemoryType: 0x%08x(%s)\n) DEVPATH_FMT(StartAddress:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(EndAddress:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->MemoryType, typename, p->StartAddress, p->EndAddress); } } #ifdef EFI_EDD10_PATH_GUID static inline void devpath_hw_edd10(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See unknown - snarfed from efivar-main.zip */ struct { /* Sub-Type 4 */ devpath_t hdr; /* Length = 24 */ uuid_t GUID; uint32_t devnum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); assert(p->hdr.Length == 24); /* * p->data will be printed by debug */ path->sz = easprintf(&path->cp, "EDD10(0x%02x)", p->devnum); if (dbg != NULL) { char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n) DEVPATH_FMT(devnum: 0x%08x\n), DEVPATH_DAT_HDR(dp), uuid_str, p->devnum); } } #endif /* EFI_EDD10_PATH_GUID */ static inline void devpath_hw_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.4 */ struct { /* Sub-Type 4 */ devpath_t hdr; /* Length = 20 + n */ uuid_t GUID; uint8_t data[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; #ifdef EFI_EDD10_PATH_GUID if (memcmp(&p->GUID, &EFI_EDD10_PATH_GUID, sizeof(uuid_t)) == 0) { devpath_hw_edd10(dp, path, dbg); return; } #endif /* EFI_EDD10_PATH_GUID */ uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); /* * p->data will be printed by debug */ path->sz = easprintf(&path->cp, "VenHw(%s)", uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n), DEVPATH_DAT_HDR(dp), uuid_str); } } static inline void devpath_hw_controller(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.5 */ struct { /* Sub-Type 5 */ devpath_t hdr; /* Length = 8 */ uint32_t CtrlNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 8); path->sz = easprintf(&path->cp, "Ctrl(0x%x)", p->CtrlNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(CtrlNum: 0x%x\n), DEVPATH_DAT_HDR(dp), p->CtrlNum); } } static inline const char * devpath_hw_bmc_iftype(uint type) { static const char *tbl[] = { [0] = "Unknown", [1] = "KCS", // Keyboard Controller Style [2] = "SMIC", // Server Management Interface Chip [3] = "BT", // Block Transfer }; if (type >= __arraycount(tbl)) type = 0; return tbl[type]; } /* Baseboard Management Controller */ static inline void devpath_hw_bmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.2.6 */ struct { /* Sub-Type 6 */ devpath_t hdr; /* Length = 13 */ uint8_t IfaceType; uint64_t BaseAddress; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 13); const char *iftype; iftype = devpath_hw_bmc_iftype(p->IfaceType); path->sz = easprintf(&path->cp, "(%s,0x%016" PRIx64 ")", iftype, p->BaseAddress); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(IfaceType: %u(%s)\n) DEVPATH_FMT(BaseAddress:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->IfaceType, iftype, p->BaseAddress); } } PUBLIC void devpath_hw(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { assert(dp->Type = 1); switch (dp->SubType) { case 1: devpath_hw_pci(dp, path, dbg); return; case 2: devpath_hw_pccard(dp, path, dbg); return; case 3: devpath_hw_memmap(dp, path, dbg); return; case 4: devpath_hw_vendor(dp, path, dbg); return; case 5: devpath_hw_controller(dp, path, dbg); return; case 6: devpath_hw_bmc(dp, path, dbg); return; default: devpath_unsupported(dp, path, dbg); return; } }