devpath4.c revision 1.2 1 /* $NetBSD: devpath4.c,v 1.2 2025/02/24 15:42:05 martin 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: devpath4.c,v 1.2 2025/02/24 15:42:05 martin Exp $");
29 #endif /* not lint */
30
31 #include <sys/uuid.h>
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <util.h>
37
38 #include "defs.h"
39 #include "devpath.h"
40 #include "devpath4.h"
41 #include "utils.h"
42
43 #define easprintf (size_t)easprintf
44
45 #define EFI_VIRTUAL_DISK_GUID \
46 ((uuid_t){0x77AB535A,0x45FC,0x624B,0x55,0x60,\
47 {0xF7,0xB2,0x81,0xD1,0xF9,0x6E}})
48
49 #define EFI_VIRTUAL_CD_GUID \
50 ((uuid_t){0x3D5ABD30,0x4175,0x87CE,0x6D,0x64,\
51 {0xD2,0xAD,0xE5,0x23,0xC4,0xBB}})
52
53 #define EFI_PERSISTENT_VIRTUAL_DISK_GUID \
54 ((uuid_t){0x5CEA02C9,0x4D07,0x69D3,0x26,0x9F,\
55 {0x44,0x96,0xFB,0xE0,0x96,0xF9}})
56
57 #define EFI_PERSISTENT_VIRTUAL_CD_GUID \
58 ((uuid_t){0x08018188,0x42CD,0xBB48,0x10,0x0F,\
59 {0x53,0x87,0xD5,0x3D,0xED,0x3D }})
60
61 /************************************************************************
62 * Type 4 - Media Device Path
63 ************************************************************************/
64
65 static void
66 devpath_media_harddisk(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
67 { /* See 10.3.5.1 */
68 struct { /* Sub-Type 1 */
69 devpath_t hdr; /* Length 42 */
70 uint32_t PartitionNumber;
71 uint64_t PartitionStart;
72 uint64_t PartitionSize;
73 uuid_t PartitionSignature;
74 uint8_t PartitionFormat;
75 #define PARTITION_FORMAT_MBR 0x01
76 #define PARTITION_FORMAT_GPT 0x02
77 uint8_t SignatureType;
78 #define SIGNATURE_TYPE_NONE 0x00
79 #define SIGNATURE_TYPE_MBR 0x01
80 #define SIGNATURE_TYPE_GUID 0x02
81 } __packed *p = (void *)dp;
82 __CTASSERT(sizeof(*p) == 42);
83 char uuid_str[UUID_STR_LEN];
84 const char *name_PartitionFormat;
85
86 uuid_snprintf(uuid_str, sizeof(uuid_str),
87 &p->PartitionSignature);
88
89 switch (p->PartitionFormat) {
90 case PARTITION_FORMAT_MBR: name_PartitionFormat = "MBR"; break;
91 case PARTITION_FORMAT_GPT: name_PartitionFormat = "GPT"; break;
92 default: name_PartitionFormat = "unknown"; break;
93 }
94
95 path->sz = easprintf(&path->cp, "HD(%u,%s,%s,0x%" PRIx64 ",0x%"
96 PRIx64 ")",
97 p->PartitionNumber,
98 name_PartitionFormat,
99 uuid_str,
100 p->PartitionStart,
101 p->PartitionSize);
102
103 if (dbg != NULL) {
104 const char *name_SignatureType;
105
106 switch (p->SignatureType) {
107 case SIGNATURE_TYPE_NONE: name_SignatureType = "NONE"; break;
108 case SIGNATURE_TYPE_MBR: name_SignatureType = "MBR"; break;
109 case SIGNATURE_TYPE_GUID: name_SignatureType = "GUID"; break;
110 default: name_SignatureType = "unknown"; break;
111 }
112
113 dbg->sz = easprintf(&dbg->cp,
114 DEVPATH_FMT_HDR
115 DEVPATH_FMT(PartitionNumber: %u\n)
116 DEVPATH_FMT(PartitionStart:) " 0x%" PRIx64 "\n"
117 DEVPATH_FMT(PartitionSize:) " 0x%" PRIx64 "\n"
118 DEVPATH_FMT(PartitionSignature: %s\n)
119 DEVPATH_FMT(PartitionFormat: %s(%u)\n)
120 DEVPATH_FMT(SignatureType: %s(%u)\n),
121 DEVPATH_DAT_HDR(dp),
122 p->PartitionNumber,
123 p->PartitionStart,
124 p->PartitionSize,
125 uuid_str,
126 name_PartitionFormat,
127 p->PartitionFormat,
128 name_SignatureType,
129 p->SignatureType);
130 }
131 }
132
133 static void
134 devpath_media_cdrom(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
135 { /* See 10.3.5.2 */
136 struct { /* Sub-Type 2 */
137 devpath_t hdr; /* Length 24 */
138 uint32_t BootEntry;
139 uint64_t PartitionStart;
140 uint64_t PartitionSize;
141 } __packed *p = (void *)dp;
142 __CTASSERT(sizeof(*p) == 24);
143
144 path->sz = easprintf(&path->cp, "CDROM(0x%x,0x%016" PRIx64 ",0x%016"
145 PRIx64 ")", p->BootEntry,
146 p->PartitionStart, p->PartitionSize);
147
148 if (dbg != NULL) {
149 dbg->sz = easprintf(&dbg->cp,
150 DEVPATH_FMT_HDR
151 DEVPATH_FMT(BootEntry: 0x%04x\n)
152 DEVPATH_FMT(PartitionStart:) " 0x%016" PRIx64 "\n"
153 DEVPATH_FMT(PartitionSize:) " 0x%016" PRIx64 "\n",
154 DEVPATH_DAT_HDR(dp),
155 p->BootEntry,
156 p->PartitionStart,
157 p->PartitionSize);
158 }
159 }
160
161 static void
162 devpath_media_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
163 { /* See 10.3.5.3 */
164
165 struct { /* Sub-Type 3 */
166 devpath_t hdr; /* Length = 20 + n */
167 uuid_t VendorGUID;
168 uint8_t vendorData[];
169 } __packed *p = (void *)dp;
170 __CTASSERT(sizeof(*p) == 20);
171 char uuid_str[UUID_STR_LEN];
172
173 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->VendorGUID);
174
175 path->sz = easprintf(&path->cp, "VenMedia(%s)", uuid_str);
176
177 if (dbg != NULL) {
178 dbg->sz = easprintf(&dbg->cp,
179 DEVPATH_FMT_HDR
180 DEVPATH_FMT(VendorGUID: %s\n),
181 DEVPATH_DAT_HDR(dp),
182 uuid_str);
183 }
184 }
185
186 static void
187 devpath_media_filepath(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
188 { /* See 10.3.5.4 */
189 struct { /* Sub-Type 4 */
190 devpath_t hdr; /* Length = 4 + n */
191 uint16_t PathName[];
192 } __packed *p = (void *)dp;
193 __CTASSERT(sizeof(*p) == 4);
194 char *PathName;
195 size_t sz = p->hdr.Length - sizeof(*p);
196
197 PathName = ucs2_to_utf8(p->PathName, sz, NULL, NULL);
198 path->sz = easprintf(&path->cp, "File(%s)", PathName);
199
200 if (dbg != NULL) {
201 dbg->sz = easprintf(&dbg->cp,
202 DEVPATH_FMT_HDR
203 DEVPATH_FMT(PathName: %s\n),
204 DEVPATH_DAT_HDR(dp),
205 PathName);
206 }
207 free(PathName);
208 }
209
210 static void
211 devpath_media_protocol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
212 { /* See 10.3.5.5 */
213 struct { /* Sub-Type 5 */
214 devpath_t hdr; /* Length 20 */
215 uuid_t ProtocolGUID;
216 } __packed *p = (void *)dp;
217 __CTASSERT(sizeof(*p) == 20);
218 char uuid_str[UUID_STR_LEN];
219
220 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->ProtocolGUID);
221 path->sz = easprintf(&path->cp, "Media(%s)", uuid_str);
222
223 if (dbg != NULL) {
224 dbg->sz = easprintf(&dbg->cp,
225 DEVPATH_FMT_HDR
226 DEVPATH_FMT(ProtocolGUID: %s\n),
227 DEVPATH_DAT_HDR(dp),
228 uuid_str);
229 }
230 }
231
232 static void
233 devpath_media_PIWGfwfile(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
234 { /* See 10.3.5.6 */
235 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.3 */
236 struct { /* Sub-Type 6 */
237 devpath_t hdr; /* Length 20 */
238 uuid_t FWFileName;
239 } __packed *p = (void *)dp;
240 __CTASSERT(sizeof(*p) == 20);
241 char uuid_str[UUID_STR_LEN];
242
243 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->FWFileName);
244 path->sz = easprintf(&path->cp, "FvFile(%s)", uuid_str);
245
246 if (dbg != NULL) {
247 dbg->sz = easprintf(&dbg->cp,
248 DEVPATH_FMT_HDR
249 DEVPATH_FMT(FirmwareFileName: %s\n),
250 DEVPATH_DAT_HDR(dp),
251 uuid_str);
252 }
253 }
254
255 static void
256 devpath_media_PIWGfwvol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
257 { /* See 10.3.5.7 */
258 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.2 */
259 struct { /* Sub-Type 7 */
260 devpath_t hdr; /* Length 20 */
261 uuid_t GUID;
262 } __packed *p = (void *)dp;
263 __CTASSERT(sizeof(*p) == 20);
264 char uuid_str[UUID_STR_LEN];
265
266 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
267 path->sz = easprintf(&path->cp, "Fv(%s)", uuid_str);
268
269 if (dbg != NULL) {
270 dbg->sz = easprintf(&dbg->cp,
271 DEVPATH_FMT_HDR
272 DEVPATH_FMT(GUID: %s\n),
273 DEVPATH_DAT_HDR(dp),
274 uuid_str);
275 }
276 }
277
278 static void
279 devpath_media_reloff(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
280 { /* See 10.3.5.8 */
281 struct { /* Sub-Type 8 */
282 devpath_t hdr; /* Length 24 */
283 uint32_t Reserved;
284 uint64_t StartingOffset;
285 uint64_t EndingOffset;
286 } __packed *p = (void *)dp;
287 __CTASSERT(sizeof(*p) == 24);
288
289 path->sz = easprintf(&path->cp, "Offset(0x%016" PRIx64 ",0x%016"
290 PRIx64 ")",
291 p->StartingOffset, p->EndingOffset);
292
293 if (dbg != NULL) {
294 dbg->sz = easprintf(&dbg->cp,
295 DEVPATH_FMT_HDR
296 DEVPATH_FMT(Reserved: 0x%08x\n)
297 DEVPATH_FMT(StartingOffset:) " 0x%016" PRIx64 "\n"
298 DEVPATH_FMT(EndingOffset:) " 0x%016" PRIx64 "\n",
299 DEVPATH_DAT_HDR(dp),
300 p->Reserved,
301 p->StartingOffset,
302 p->EndingOffset);
303 }
304 }
305
306 static const char *
307 devpath_media_ramdisk_type(uuid_t *uuid)
308 {
309 static struct {
310 uuid_t GUID;
311 const char *type;
312 } tbl[] = {
313 { .GUID = EFI_VIRTUAL_DISK_GUID,
314 .type = "VirtualDisk",
315 },
316 { .GUID = EFI_VIRTUAL_CD_GUID,
317 .type = "VirtualCD",
318 },
319 { .GUID = EFI_PERSISTENT_VIRTUAL_DISK_GUID,
320 .type = "PersistentVirtualDisk",
321 },
322 { .GUID =EFI_PERSISTENT_VIRTUAL_CD_GUID,
323 .type = "PersistentVirtualCD",
324 },
325 };
326
327 for (size_t i = 0; i < __arraycount(tbl); i++) {
328 if (memcmp(uuid, &tbl[i].GUID, sizeof(*uuid)) == 0) {
329 return tbl[i].type;
330 }
331 }
332 return NULL;
333 }
334
335 static void
336 devpath_media_ramdisk(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
337 { /* See 10.3.5.9 */
338 struct { /* Sub-Type 9 */
339 devpath_t hdr; /* Length 38 */
340 uint64_t StartingAddress;
341 uint64_t EndingAddress;
342 uuid_t GUID;
343 uint16_t Instance;
344 } __packed *p = (void *)dp;
345 __CTASSERT(sizeof(*p) == 38);
346 char uuid_str[UUID_STR_LEN];
347 const char *type;
348
349 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
350
351 type = devpath_media_ramdisk_type(&p->GUID);
352 if (type != NULL)
353 path->sz = easprintf(&path->cp, "%s(0x%016" PRIx64 ",0x%016"
354 PRIx64 ",%u)", type,
355 p->StartingAddress, p->EndingAddress, p->Instance);
356 else
357 path->sz = easprintf(&path->cp, "RamDisk(0x%016" PRIx64
358 ",0x%016" PRIx64 ",%u,%s)",
359 p->StartingAddress, p->EndingAddress, p->Instance,
360 uuid_str);
361
362 if (dbg != NULL) {
363 dbg->sz = easprintf(&dbg->cp,
364 DEVPATH_FMT_HDR
365 DEVPATH_FMT(StartingAddress:) " 0x%016" PRIx64 "\n"
366 DEVPATH_FMT(EndingAddress:) " 0x%016" PRIx64 "\n"
367 DEVPATH_FMT(Instance: 0x%08x\n)
368 DEVPATH_FMT(GUID: %s\n),
369 DEVPATH_DAT_HDR(dp),
370 p->StartingAddress,
371 p->EndingAddress,
372 p->Instance,
373 uuid_str);
374 }
375 }
376
377 PUBLIC void
378 devpath_media(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
379 {
380
381 switch (dp->SubType) {
382 case 1: devpath_media_harddisk(dp, path, dbg); return;
383 case 2: devpath_media_cdrom(dp, path, dbg); return;
384 case 3: devpath_media_vendor(dp, path, dbg); return;
385 case 4: devpath_media_filepath(dp, path, dbg); return;
386 case 5: devpath_media_protocol(dp, path, dbg); return;
387 case 6: devpath_media_PIWGfwfile(dp, path, dbg); return;
388 case 7: devpath_media_PIWGfwvol(dp, path, dbg); return;
389 case 8: devpath_media_reloff(dp, path, dbg); return;
390 case 9: devpath_media_ramdisk(dp, path, dbg); return;
391 default: devpath_unsupported(dp, path, dbg); return;
392 }
393 }
394