/* $NetBSD: devpath4.c,v 1.3 2025/02/25 22:11:36 christos 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: devpath4.c,v 1.3 2025/02/25 22:11:36 christos Exp $"); #endif /* not lint */ #include #include #include #include #include #include "defs.h" #include "devpath.h" #include "devpath4.h" #include "utils.h" #define easprintf (size_t)easprintf #define EFI_VIRTUAL_DISK_GUID \ {0x77AB535A,0x45FC,0x624B,0x55,0x60,{0xF7,0xB2,0x81,0xD1,0xF9,0x6E}} #define EFI_VIRTUAL_CD_GUID \ {0x3D5ABD30,0x4175,0x87CE,0x6D,0x64,{0xD2,0xAD,0xE5,0x23,0xC4,0xBB}} #define EFI_PERSISTENT_VIRTUAL_DISK_GUID \ {0x5CEA02C9,0x4D07,0x69D3,0x26,0x9F,{0x44,0x96,0xFB,0xE0,0x96,0xF9}} #define EFI_PERSISTENT_VIRTUAL_CD_GUID \ {0x08018188,0x42CD,0xBB48,0x10,0x0F,{0x53,0x87,0xD5,0x3D,0xED,0x3D}} /************************************************************************ * Type 4 - Media Device Path ************************************************************************/ static void devpath_media_harddisk(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.1 */ struct { /* Sub-Type 1 */ devpath_t hdr; /* Length 42 */ uint32_t PartitionNumber; uint64_t PartitionStart; uint64_t PartitionSize; uuid_t PartitionSignature; uint8_t PartitionFormat; #define PARTITION_FORMAT_MBR 0x01 #define PARTITION_FORMAT_GPT 0x02 uint8_t SignatureType; #define SIGNATURE_TYPE_NONE 0x00 #define SIGNATURE_TYPE_MBR 0x01 #define SIGNATURE_TYPE_GUID 0x02 } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 42); char uuid_str[UUID_STR_LEN]; const char *name_PartitionFormat; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->PartitionSignature); switch (p->PartitionFormat) { case PARTITION_FORMAT_MBR: name_PartitionFormat = "MBR"; break; case PARTITION_FORMAT_GPT: name_PartitionFormat = "GPT"; break; default: name_PartitionFormat = "unknown"; break; } path->sz = easprintf(&path->cp, "HD(%u,%s,%s,0x%" PRIx64 ",0x%" PRIx64 ")", p->PartitionNumber, name_PartitionFormat, uuid_str, p->PartitionStart, p->PartitionSize); if (dbg != NULL) { const char *name_SignatureType; switch (p->SignatureType) { case SIGNATURE_TYPE_NONE: name_SignatureType = "NONE"; break; case SIGNATURE_TYPE_MBR: name_SignatureType = "MBR"; break; case SIGNATURE_TYPE_GUID: name_SignatureType = "GUID"; break; default: name_SignatureType = "unknown"; break; } dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(PartitionNumber: %u\n) DEVPATH_FMT(PartitionStart:) " 0x%" PRIx64 "\n" DEVPATH_FMT(PartitionSize:) " 0x%" PRIx64 "\n" DEVPATH_FMT(PartitionSignature: %s\n) DEVPATH_FMT(PartitionFormat: %s(%u)\n) DEVPATH_FMT(SignatureType: %s(%u)\n), DEVPATH_DAT_HDR(dp), p->PartitionNumber, p->PartitionStart, p->PartitionSize, uuid_str, name_PartitionFormat, p->PartitionFormat, name_SignatureType, p->SignatureType); } } static void devpath_media_cdrom(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.2 */ struct { /* Sub-Type 2 */ devpath_t hdr; /* Length 24 */ uint32_t BootEntry; uint64_t PartitionStart; uint64_t PartitionSize; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); path->sz = easprintf(&path->cp, "CDROM(0x%x,0x%016" PRIx64 ",0x%016" PRIx64 ")", p->BootEntry, p->PartitionStart, p->PartitionSize); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(BootEntry: 0x%04x\n) DEVPATH_FMT(PartitionStart:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(PartitionSize:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->BootEntry, p->PartitionStart, p->PartitionSize); } } static void devpath_media_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.3 */ struct { /* Sub-Type 3 */ devpath_t hdr; /* Length = 20 + n */ uuid_t VendorGUID; uint8_t vendorData[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->VendorGUID); path->sz = easprintf(&path->cp, "VenMedia(%s)", uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(VendorGUID: %s\n), DEVPATH_DAT_HDR(dp), uuid_str); } } static void devpath_media_filepath(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.4 */ struct { /* Sub-Type 4 */ devpath_t hdr; /* Length = 4 + n */ uint16_t PathName[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 4); char *PathName; size_t sz = p->hdr.Length - sizeof(*p); PathName = ucs2_to_utf8(p->PathName, sz, NULL, NULL); path->sz = easprintf(&path->cp, "File(%s)", PathName); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(PathName: %s\n), DEVPATH_DAT_HDR(dp), PathName); } free(PathName); } static void devpath_media_protocol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.5 */ struct { /* Sub-Type 5 */ devpath_t hdr; /* Length 20 */ uuid_t ProtocolGUID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->ProtocolGUID); path->sz = easprintf(&path->cp, "Media(%s)", uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(ProtocolGUID: %s\n), DEVPATH_DAT_HDR(dp), uuid_str); } } static void devpath_media_PIWGfwfile(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.6 */ /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.3 */ struct { /* Sub-Type 6 */ devpath_t hdr; /* Length 20 */ uuid_t FWFileName; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->FWFileName); path->sz = easprintf(&path->cp, "FvFile(%s)", uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(FirmwareFileName: %s\n), DEVPATH_DAT_HDR(dp), uuid_str); } } static void devpath_media_PIWGfwvol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.7 */ /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.2 */ struct { /* Sub-Type 7 */ devpath_t hdr; /* Length 20 */ uuid_t GUID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); path->sz = easprintf(&path->cp, "Fv(%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 void devpath_media_reloff(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.8 */ struct { /* Sub-Type 8 */ devpath_t hdr; /* Length 24 */ uint32_t Reserved; uint64_t StartingOffset; uint64_t EndingOffset; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); path->sz = easprintf(&path->cp, "Offset(0x%016" PRIx64 ",0x%016" PRIx64 ")", p->StartingOffset, p->EndingOffset); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Reserved: 0x%08x\n) DEVPATH_FMT(StartingOffset:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(EndingOffset:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->Reserved, p->StartingOffset, p->EndingOffset); } } static const char * devpath_media_ramdisk_type(uuid_t *uuid) { static struct { uuid_t GUID; const char *type; } tbl[] = { { .GUID = EFI_VIRTUAL_DISK_GUID, .type = "VirtualDisk", }, { .GUID = EFI_VIRTUAL_CD_GUID, .type = "VirtualCD", }, { .GUID = EFI_PERSISTENT_VIRTUAL_DISK_GUID, .type = "PersistentVirtualDisk", }, { .GUID =EFI_PERSISTENT_VIRTUAL_CD_GUID, .type = "PersistentVirtualCD", }, }; for (size_t i = 0; i < __arraycount(tbl); i++) { if (memcmp(uuid, &tbl[i].GUID, sizeof(*uuid)) == 0) { return tbl[i].type; } } return NULL; } static void devpath_media_ramdisk(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.5.9 */ struct { /* Sub-Type 9 */ devpath_t hdr; /* Length 38 */ uint64_t StartingAddress; uint64_t EndingAddress; uuid_t GUID; uint16_t Instance; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 38); char uuid_str[UUID_STR_LEN]; const char *type; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); type = devpath_media_ramdisk_type(&p->GUID); if (type != NULL) path->sz = easprintf(&path->cp, "%s(0x%016" PRIx64 ",0x%016" PRIx64 ",%u)", type, p->StartingAddress, p->EndingAddress, p->Instance); else path->sz = easprintf(&path->cp, "RamDisk(0x%016" PRIx64 ",0x%016" PRIx64 ",%u,%s)", p->StartingAddress, p->EndingAddress, p->Instance, uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(StartingAddress:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(EndingAddress:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(Instance: 0x%08x\n) DEVPATH_FMT(GUID: %s\n), DEVPATH_DAT_HDR(dp), p->StartingAddress, p->EndingAddress, p->Instance, uuid_str); } } PUBLIC void devpath_media(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { switch (dp->SubType) { case 1: devpath_media_harddisk(dp, path, dbg); return; case 2: devpath_media_cdrom(dp, path, dbg); return; case 3: devpath_media_vendor(dp, path, dbg); return; case 4: devpath_media_filepath(dp, path, dbg); return; case 5: devpath_media_protocol(dp, path, dbg); return; case 6: devpath_media_PIWGfwfile(dp, path, dbg); return; case 7: devpath_media_PIWGfwvol(dp, path, dbg); return; case 8: devpath_media_reloff(dp, path, dbg); return; case 9: devpath_media_ramdisk(dp, path, dbg); return; default: devpath_unsupported(dp, path, dbg); return; } }