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