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