devpath4.c revision 1.3 1 /* $NetBSD: devpath4.c,v 1.3 2025/02/25 22:11:36 christos 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.3 2025/02/25 22:11:36 christos 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, devpath_elm_t *dbg)
230 { /* See 10.3.5.6 */
231 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.3 */
232 struct { /* Sub-Type 6 */
233 devpath_t hdr; /* Length 20 */
234 uuid_t FWFileName;
235 } __packed *p = (void *)dp;
236 __CTASSERT(sizeof(*p) == 20);
237 char uuid_str[UUID_STR_LEN];
238
239 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->FWFileName);
240 path->sz = easprintf(&path->cp, "FvFile(%s)", uuid_str);
241
242 if (dbg != NULL) {
243 dbg->sz = easprintf(&dbg->cp,
244 DEVPATH_FMT_HDR
245 DEVPATH_FMT(FirmwareFileName: %s\n),
246 DEVPATH_DAT_HDR(dp),
247 uuid_str);
248 }
249 }
250
251 static void
252 devpath_media_PIWGfwvol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
253 { /* See 10.3.5.7 */
254 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.2 */
255 struct { /* Sub-Type 7 */
256 devpath_t hdr; /* Length 20 */
257 uuid_t GUID;
258 } __packed *p = (void *)dp;
259 __CTASSERT(sizeof(*p) == 20);
260 char uuid_str[UUID_STR_LEN];
261
262 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
263 path->sz = easprintf(&path->cp, "Fv(%s)", uuid_str);
264
265 if (dbg != NULL) {
266 dbg->sz = easprintf(&dbg->cp,
267 DEVPATH_FMT_HDR
268 DEVPATH_FMT(GUID: %s\n),
269 DEVPATH_DAT_HDR(dp),
270 uuid_str);
271 }
272 }
273
274 static void
275 devpath_media_reloff(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
276 { /* See 10.3.5.8 */
277 struct { /* Sub-Type 8 */
278 devpath_t hdr; /* Length 24 */
279 uint32_t Reserved;
280 uint64_t StartingOffset;
281 uint64_t EndingOffset;
282 } __packed *p = (void *)dp;
283 __CTASSERT(sizeof(*p) == 24);
284
285 path->sz = easprintf(&path->cp, "Offset(0x%016" PRIx64 ",0x%016"
286 PRIx64 ")",
287 p->StartingOffset, p->EndingOffset);
288
289 if (dbg != NULL) {
290 dbg->sz = easprintf(&dbg->cp,
291 DEVPATH_FMT_HDR
292 DEVPATH_FMT(Reserved: 0x%08x\n)
293 DEVPATH_FMT(StartingOffset:) " 0x%016" PRIx64 "\n"
294 DEVPATH_FMT(EndingOffset:) " 0x%016" PRIx64 "\n",
295 DEVPATH_DAT_HDR(dp),
296 p->Reserved,
297 p->StartingOffset,
298 p->EndingOffset);
299 }
300 }
301
302 static const char *
303 devpath_media_ramdisk_type(uuid_t *uuid)
304 {
305 static struct {
306 uuid_t GUID;
307 const char *type;
308 } tbl[] = {
309 { .GUID = EFI_VIRTUAL_DISK_GUID,
310 .type = "VirtualDisk",
311 },
312 { .GUID = EFI_VIRTUAL_CD_GUID,
313 .type = "VirtualCD",
314 },
315 { .GUID = EFI_PERSISTENT_VIRTUAL_DISK_GUID,
316 .type = "PersistentVirtualDisk",
317 },
318 { .GUID =EFI_PERSISTENT_VIRTUAL_CD_GUID,
319 .type = "PersistentVirtualCD",
320 },
321 };
322
323 for (size_t i = 0; i < __arraycount(tbl); i++) {
324 if (memcmp(uuid, &tbl[i].GUID, sizeof(*uuid)) == 0) {
325 return tbl[i].type;
326 }
327 }
328 return NULL;
329 }
330
331 static void
332 devpath_media_ramdisk(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
333 { /* See 10.3.5.9 */
334 struct { /* Sub-Type 9 */
335 devpath_t hdr; /* Length 38 */
336 uint64_t StartingAddress;
337 uint64_t EndingAddress;
338 uuid_t GUID;
339 uint16_t Instance;
340 } __packed *p = (void *)dp;
341 __CTASSERT(sizeof(*p) == 38);
342 char uuid_str[UUID_STR_LEN];
343 const char *type;
344
345 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
346
347 type = devpath_media_ramdisk_type(&p->GUID);
348 if (type != NULL)
349 path->sz = easprintf(&path->cp, "%s(0x%016" PRIx64 ",0x%016"
350 PRIx64 ",%u)", type,
351 p->StartingAddress, p->EndingAddress, p->Instance);
352 else
353 path->sz = easprintf(&path->cp, "RamDisk(0x%016" PRIx64
354 ",0x%016" PRIx64 ",%u,%s)",
355 p->StartingAddress, p->EndingAddress, p->Instance,
356 uuid_str);
357
358 if (dbg != NULL) {
359 dbg->sz = easprintf(&dbg->cp,
360 DEVPATH_FMT_HDR
361 DEVPATH_FMT(StartingAddress:) " 0x%016" PRIx64 "\n"
362 DEVPATH_FMT(EndingAddress:) " 0x%016" PRIx64 "\n"
363 DEVPATH_FMT(Instance: 0x%08x\n)
364 DEVPATH_FMT(GUID: %s\n),
365 DEVPATH_DAT_HDR(dp),
366 p->StartingAddress,
367 p->EndingAddress,
368 p->Instance,
369 uuid_str);
370 }
371 }
372
373 PUBLIC void
374 devpath_media(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
375 {
376
377 switch (dp->SubType) {
378 case 1: devpath_media_harddisk(dp, path, dbg); return;
379 case 2: devpath_media_cdrom(dp, path, dbg); return;
380 case 3: devpath_media_vendor(dp, path, dbg); return;
381 case 4: devpath_media_filepath(dp, path, dbg); return;
382 case 5: devpath_media_protocol(dp, path, dbg); return;
383 case 6: devpath_media_PIWGfwfile(dp, path, dbg); return;
384 case 7: devpath_media_PIWGfwvol(dp, path, dbg); return;
385 case 8: devpath_media_reloff(dp, path, dbg); return;
386 case 9: devpath_media_ramdisk(dp, path, dbg); return;
387 default: devpath_unsupported(dp, path, dbg); return;
388 }
389 }
390