devpath4.c revision 1.1 1 /* $NetBSD: devpath4.c,v 1.1 2025/02/24 13:47:56 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.1 2025/02/24 13:47:56 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 ((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%lx,0x%lx)",
96 p->PartitionNumber,
97 name_PartitionFormat,
98 uuid_str,
99 p->PartitionStart,
100 p->PartitionSize);
101
102 if (dbg != NULL) {
103 const char *name_SignatureType;
104
105 switch (p->SignatureType) {
106 case SIGNATURE_TYPE_NONE: name_SignatureType = "NONE"; break;
107 case SIGNATURE_TYPE_MBR: name_SignatureType = "MBR"; break;
108 case SIGNATURE_TYPE_GUID: name_SignatureType = "GUID"; break;
109 default: name_SignatureType = "unknown"; break;
110 }
111
112 dbg->sz = easprintf(&dbg->cp,
113 DEVPATH_FMT_HDR
114 DEVPATH_FMT(PartitionNumber: %u\n)
115 DEVPATH_FMT(PartitionStart: 0x%lx\n)
116 DEVPATH_FMT(PartitionSize: 0x%lx\n)
117 DEVPATH_FMT(PartitionSignature: %s\n)
118 DEVPATH_FMT(PartitionFormat: %s(%u)\n)
119 DEVPATH_FMT(SignatureType: %s(%u)\n),
120 DEVPATH_DAT_HDR(dp),
121 p->PartitionNumber,
122 p->PartitionStart,
123 p->PartitionSize,
124 uuid_str,
125 name_PartitionFormat,
126 p->PartitionFormat,
127 name_SignatureType,
128 p->SignatureType);
129 }
130 }
131
132 static void
133 devpath_media_cdrom(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
134 { /* See 10.3.5.2 */
135 struct { /* Sub-Type 2 */
136 devpath_t hdr; /* Length 24 */
137 uint32_t BootEntry;
138 uint64_t PartitionStart;
139 uint64_t PartitionSize;
140 } __packed *p = (void *)dp;
141 __CTASSERT(sizeof(*p) == 24);
142
143 path->sz = easprintf(&path->cp, "CDROM(0x%x,0x%016tx,0x%016tx)", p->BootEntry,
144 p->PartitionStart, p->PartitionSize);
145
146 if (dbg != NULL) {
147 dbg->sz = easprintf(&dbg->cp,
148 DEVPATH_FMT_HDR
149 DEVPATH_FMT(BootEntry: 0x%04x\n)
150 DEVPATH_FMT(PartitionStart: 0x%016tx\n)
151 DEVPATH_FMT(PartitionSize: 0x%016tx\n),
152 DEVPATH_DAT_HDR(dp),
153 p->BootEntry,
154 p->PartitionStart,
155 p->PartitionSize);
156 }
157 }
158
159 static void
160 devpath_media_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
161 { /* See 10.3.5.3 */
162
163 struct { /* Sub-Type 3 */
164 devpath_t hdr; /* Length = 20 + n */
165 uuid_t VendorGUID;
166 uint8_t vendorData[];
167 } __packed *p = (void *)dp;
168 __CTASSERT(sizeof(*p) == 20);
169 char uuid_str[UUID_STR_LEN];
170
171 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->VendorGUID);
172
173 path->sz = easprintf(&path->cp, "VenMedia(%s)", uuid_str);
174
175 if (dbg != NULL) {
176 dbg->sz = easprintf(&dbg->cp,
177 DEVPATH_FMT_HDR
178 DEVPATH_FMT(VendorGUID: %s\n),
179 DEVPATH_DAT_HDR(dp),
180 uuid_str);
181 }
182 }
183
184 static void
185 devpath_media_filepath(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
186 { /* See 10.3.5.4 */
187 struct { /* Sub-Type 4 */
188 devpath_t hdr; /* Length = 4 + n */
189 uint16_t PathName[];
190 } __packed *p = (void *)dp;
191 __CTASSERT(sizeof(*p) == 4);
192 char *PathName;
193 size_t sz = p->hdr.Length - sizeof(*p);
194
195 PathName = ucs2_to_utf8(p->PathName, sz, NULL, NULL);
196 path->sz = easprintf(&path->cp, "File(%s)", PathName);
197
198 if (dbg != NULL) {
199 dbg->sz = easprintf(&dbg->cp,
200 DEVPATH_FMT_HDR
201 DEVPATH_FMT(PathName: %s\n),
202 DEVPATH_DAT_HDR(dp),
203 PathName);
204 }
205 free(PathName);
206 }
207
208 static void
209 devpath_media_protocol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
210 { /* See 10.3.5.5 */
211 struct { /* Sub-Type 5 */
212 devpath_t hdr; /* Length 20 */
213 uuid_t ProtocolGUID;
214 } __packed *p = (void *)dp;
215 __CTASSERT(sizeof(*p) == 20);
216 char uuid_str[UUID_STR_LEN];
217
218 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->ProtocolGUID);
219 path->sz = easprintf(&path->cp, "Media(%s)", uuid_str);
220
221 if (dbg != NULL) {
222 dbg->sz = easprintf(&dbg->cp,
223 DEVPATH_FMT_HDR
224 DEVPATH_FMT(ProtocolGUID: %s\n),
225 DEVPATH_DAT_HDR(dp),
226 uuid_str);
227 }
228 }
229
230 static void
231 devpath_media_PIWGfwfile(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
232 { /* See 10.3.5.6 */
233 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.3 */
234 struct { /* Sub-Type 6 */
235 devpath_t hdr; /* Length 20 */
236 uuid_t FWFileName;
237 } __packed *p = (void *)dp;
238 __CTASSERT(sizeof(*p) == 20);
239 char uuid_str[UUID_STR_LEN];
240
241 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->FWFileName);
242 path->sz = easprintf(&path->cp, "FvFile(%s)", uuid_str);
243
244 if (dbg != NULL) {
245 dbg->sz = easprintf(&dbg->cp,
246 DEVPATH_FMT_HDR
247 DEVPATH_FMT(FirmwareFileName: %s\n),
248 DEVPATH_DAT_HDR(dp),
249 uuid_str);
250 }
251 }
252
253 static void
254 devpath_media_PIWGfwvol(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
255 { /* See 10.3.5.7 */
256 /* See UEFI PI Version 1.8 Errata A (March 5, 2024) II-8.2 */
257 struct { /* Sub-Type 7 */
258 devpath_t hdr; /* Length 20 */
259 uuid_t GUID;
260 } __packed *p = (void *)dp;
261 __CTASSERT(sizeof(*p) == 20);
262 char uuid_str[UUID_STR_LEN];
263
264 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
265 path->sz = easprintf(&path->cp, "Fv(%s)", uuid_str);
266
267 if (dbg != NULL) {
268 dbg->sz = easprintf(&dbg->cp,
269 DEVPATH_FMT_HDR
270 DEVPATH_FMT(GUID: %s\n),
271 DEVPATH_DAT_HDR(dp),
272 uuid_str);
273 }
274 }
275
276 static void
277 devpath_media_reloff(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
278 { /* See 10.3.5.8 */
279 struct { /* Sub-Type 8 */
280 devpath_t hdr; /* Length 24 */
281 uint32_t Reserved;
282 uint64_t StartingOffset;
283 uint64_t EndingOffset;
284 } __packed *p = (void *)dp;
285 __CTASSERT(sizeof(*p) == 24);
286
287 path->sz = easprintf(&path->cp, "Offset(0x%016tx,0x%016tx)",
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%016tx\n)
295 DEVPATH_FMT(EndingOffset: 0x%016tx\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%016tx,0x%016tx,%u)",
351 type,
352 p->StartingAddress, p->EndingAddress, p->Instance);
353 else
354 path->sz = easprintf(&path->cp, "RamDisk(0x%016tx,0x%016tx,%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%016tx\n)
362 DEVPATH_FMT(EndingAddress: 0x%016tx\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