efiblock.c revision 1.14 1 /* $NetBSD: efiblock.c,v 1.14 2021/06/21 21:18:47 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
5 * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #define FSTYPENAMES
31
32 #include <sys/param.h>
33 #include <sys/md5.h>
34 #include <sys/uuid.h>
35
36 #include <fs/cd9660/iso.h>
37
38 #include "efiboot.h"
39 #include "efiblock.h"
40
41 #define EFI_BLOCK_READAHEAD (64 * 1024)
42 #define EFI_BLOCK_TIMEOUT 120
43 #define EFI_BLOCK_TIMEOUT_CODE 0x810c0000
44
45 /*
46 * The raidframe support is basic. Ideally, it should be expanded to
47 * consider raid volumes a first-class citizen like the x86 efiboot does,
48 * but for now, we simply assume each RAID is potentially bootable.
49 */
50 #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */
51
52 static EFI_HANDLE *efi_block;
53 static UINTN efi_nblock;
54 static struct efi_block_part *efi_block_booted = NULL;
55
56 static bool efi_ra_enable = false;
57 static UINT8 *efi_ra_buffer = NULL;
58 static UINT32 efi_ra_media_id;
59 static UINT64 efi_ra_start = 0;
60 static UINT64 efi_ra_length = 0;
61
62 static TAILQ_HEAD(, efi_block_dev) efi_block_devs = TAILQ_HEAD_INITIALIZER(efi_block_devs);
63
64 static int
65 efi_block_parse(const char *fname, struct efi_block_part **pbpart, char **pfile)
66 {
67 struct efi_block_dev *bdev;
68 struct efi_block_part *bpart;
69 char pathbuf[PATH_MAX], *default_device, *ep = NULL;
70 const char *full_path;
71 intmax_t dev;
72 int part;
73
74 default_device = get_default_device();
75 if (strchr(fname, ':') == NULL) {
76 if (strlen(default_device) > 0) {
77 snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
78 full_path = pathbuf;
79 *pfile = __UNCONST(fname);
80 } else {
81 return EINVAL;
82 }
83 } else {
84 full_path = fname;
85 *pfile = strchr(fname, ':') + 1;
86 }
87
88 if (strncasecmp(full_path, "hd", 2) != 0)
89 return EINVAL;
90 dev = strtoimax(full_path + 2, &ep, 10);
91 if (dev < 0 || dev >= efi_nblock)
92 return ENXIO;
93 if (ep[0] < 'a' || ep[0] >= 'a' + MAXPARTITIONS || ep[1] != ':')
94 return EINVAL;
95 part = ep[0] - 'a';
96 TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
97 if (bdev->index == dev) {
98 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
99 if (bpart->index == part) {
100 *pbpart = bpart;
101 return 0;
102 }
103 }
104 }
105 }
106
107 return ENOENT;
108 }
109
110 static void
111 efi_block_generate_hash_mbr(struct efi_block_part *bpart, struct mbr_sector *mbr)
112 {
113 MD5_CTX md5ctx;
114
115 MD5Init(&md5ctx);
116 MD5Update(&md5ctx, (void *)mbr, sizeof(*mbr));
117 MD5Final(bpart->hash, &md5ctx);
118 }
119
120 static EFI_STATUS
121 efi_block_disk_readahead(struct efi_block_dev *bdev, UINT64 off, void *buf,
122 UINTN bufsize)
123 {
124 EFI_STATUS status;
125 UINT64 mediasize, len;
126
127 if (efi_ra_buffer == NULL) {
128 efi_ra_buffer = AllocatePool(EFI_BLOCK_READAHEAD);
129 if (efi_ra_buffer == NULL) {
130 return EFI_OUT_OF_RESOURCES;
131 }
132 }
133
134 if (bdev->media_id != efi_ra_media_id ||
135 off < efi_ra_start ||
136 off + bufsize > efi_ra_start + efi_ra_length) {
137 mediasize = bdev->bio->Media->BlockSize *
138 (bdev->bio->Media->LastBlock + 1);
139 len = EFI_BLOCK_READAHEAD;
140 if (len > mediasize - off) {
141 len = mediasize - off;
142 }
143 status = uefi_call_wrapper(bdev->dio->ReadDisk, 5, bdev->dio,
144 bdev->media_id, off, len, efi_ra_buffer);
145 if (EFI_ERROR(status)) {
146 efi_ra_start = efi_ra_length = 0;
147 return status;
148 }
149 efi_ra_start = off;
150 efi_ra_length = len;
151 efi_ra_media_id = bdev->media_id;
152 }
153
154 memcpy(buf, &efi_ra_buffer[off - efi_ra_start], bufsize);
155 return EFI_SUCCESS;
156 }
157
158 static EFI_STATUS
159 efi_block_disk_read(struct efi_block_dev *bdev, UINT64 off, void *buf,
160 UINTN bufsize)
161 {
162 if (efi_ra_enable) {
163 return efi_block_disk_readahead(bdev, off, buf, bufsize);
164 }
165
166 return uefi_call_wrapper(bdev->dio->ReadDisk, 5, bdev->dio,
167 bdev->media_id, off, bufsize, buf);
168 }
169
170 static int
171 efi_block_find_partitions_cd9660(struct efi_block_dev *bdev)
172 {
173 struct efi_block_part *bpart;
174 struct iso_primary_descriptor vd;
175 EFI_STATUS status;
176 EFI_LBA lba;
177
178 for (lba = 16;; lba++) {
179 status = efi_block_disk_read(bdev,
180 lba * ISO_DEFAULT_BLOCK_SIZE, &vd, sizeof(vd));
181 if (EFI_ERROR(status)) {
182 goto io_error;
183 }
184
185 if (memcmp(vd.id, ISO_STANDARD_ID, sizeof vd.id) != 0) {
186 goto io_error;
187 }
188 if (isonum_711(vd.type) == ISO_VD_END) {
189 goto io_error;
190 }
191 if (isonum_711(vd.type) == ISO_VD_PRIMARY) {
192 break;
193 }
194 }
195
196 if (isonum_723(vd.logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) {
197 goto io_error;
198 }
199
200 bpart = alloc(sizeof(*bpart));
201 bpart->index = 0;
202 bpart->bdev = bdev;
203 bpart->type = EFI_BLOCK_PART_CD9660;
204 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
205
206 return 0;
207
208 io_error:
209 return EIO;
210 }
211
212 static int
213 efi_block_find_partitions_disklabel(struct efi_block_dev *bdev,
214 struct mbr_sector *mbr, uint32_t start, uint32_t size)
215 {
216 struct efi_block_part *bpart;
217 char buf[DEV_BSIZE];
218 struct disklabel d;
219 struct partition *p;
220 EFI_STATUS status;
221 int n;
222
223 status = efi_block_disk_read(bdev,
224 ((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE, buf, sizeof(buf));
225 if (EFI_ERROR(status) || getdisklabel(buf, &d) != NULL) {
226 FreePool(buf);
227 return EIO;
228 }
229
230 if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
231 return EINVAL;
232 if (le16toh(d.d_npartitions) > MAXPARTITIONS)
233 return EINVAL;
234
235 for (n = 0; n < le16toh(d.d_npartitions); n++) {
236 p = &d.d_partitions[n];
237 switch (p->p_fstype) {
238 case FS_BSDFFS:
239 case FS_MSDOS:
240 case FS_BSDLFS:
241 break;
242 case FS_RAID:
243 p->p_size -= RF_PROTECTED_SECTORS;
244 p->p_offset += RF_PROTECTED_SECTORS;
245 break;
246 default:
247 continue;
248 }
249
250 bpart = alloc(sizeof(*bpart));
251 bpart->index = n;
252 bpart->bdev = bdev;
253 bpart->type = EFI_BLOCK_PART_DISKLABEL;
254 bpart->disklabel.secsize = d.d_secsize;
255 bpart->disklabel.part = *p;
256 efi_block_generate_hash_mbr(bpart, mbr);
257 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
258 }
259
260 return 0;
261 }
262
263 static int
264 efi_block_find_partitions_mbr(struct efi_block_dev *bdev)
265 {
266 struct mbr_sector mbr;
267 struct mbr_partition *mbr_part;
268 EFI_STATUS status;
269 int n;
270
271 status = efi_block_disk_read(bdev, 0, &mbr, sizeof(mbr));
272 if (EFI_ERROR(status))
273 return EIO;
274
275 if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
276 return ENOENT;
277
278 for (n = 0; n < MBR_PART_COUNT; n++) {
279 mbr_part = &mbr.mbr_parts[n];
280 if (le32toh(mbr_part->mbrp_size) == 0)
281 continue;
282 if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
283 efi_block_find_partitions_disklabel(bdev, &mbr,
284 le32toh(mbr_part->mbrp_start),
285 le32toh(mbr_part->mbrp_size));
286 break;
287 }
288 }
289
290 return 0;
291 }
292
293 static const struct {
294 struct uuid guid;
295 uint8_t fstype;
296 } gpt_guid_to_str[] = {
297 { GPT_ENT_TYPE_NETBSD_FFS, FS_BSDFFS },
298 { GPT_ENT_TYPE_NETBSD_LFS, FS_BSDLFS },
299 { GPT_ENT_TYPE_NETBSD_RAIDFRAME, FS_RAID },
300 { GPT_ENT_TYPE_NETBSD_CCD, FS_CCD },
301 { GPT_ENT_TYPE_NETBSD_CGD, FS_CGD },
302 { GPT_ENT_TYPE_MS_BASIC_DATA, FS_MSDOS }, /* or NTFS? ambiguous */
303 { GPT_ENT_TYPE_EFI, FS_MSDOS },
304 };
305
306 static int
307 efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev,
308 struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
309 {
310 struct efi_block_part *bpart;
311 uint8_t fstype = FS_UNUSED;
312 struct uuid uuid;
313 int n;
314
315 memcpy(&uuid, ent->ent_type, sizeof(uuid));
316 for (n = 0; n < __arraycount(gpt_guid_to_str); n++)
317 if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid,
318 sizeof(ent->ent_type)) == 0) {
319 fstype = gpt_guid_to_str[n].fstype;
320 break;
321 }
322 if (fstype == FS_UNUSED)
323 return 0;
324
325 bpart = alloc(sizeof(*bpart));
326 bpart->index = index;
327 bpart->bdev = bdev;
328 bpart->type = EFI_BLOCK_PART_GPT;
329 bpart->gpt.fstype = fstype;
330 bpart->gpt.ent = *ent;
331 if (fstype == FS_RAID) {
332 bpart->gpt.ent.ent_lba_start += RF_PROTECTED_SECTORS;
333 bpart->gpt.ent.ent_lba_end -= RF_PROTECTED_SECTORS;
334 }
335 memcpy(bpart->hash, ent->ent_guid, sizeof(bpart->hash));
336 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
337
338 return 0;
339 }
340
341 static int
342 efi_block_find_partitions_gpt(struct efi_block_dev *bdev)
343 {
344 struct gpt_hdr hdr;
345 struct gpt_ent ent;
346 EFI_STATUS status;
347 UINT32 entry;
348 void *buf;
349 UINTN sz;
350
351 status = efi_block_disk_read(bdev, GPT_HDR_BLKNO * DEV_BSIZE, &hdr,
352 sizeof(hdr));
353 if (EFI_ERROR(status)) {
354 return EIO;
355 }
356
357 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0)
358 return ENOENT;
359 if (le32toh(hdr.hdr_entsz) < sizeof(ent))
360 return EINVAL;
361
362 sz = le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries);
363 buf = AllocatePool(sz);
364 if (buf == NULL)
365 return ENOMEM;
366
367 status = efi_block_disk_read(bdev,
368 le64toh(hdr.hdr_lba_table) * DEV_BSIZE, buf, sz);
369 if (EFI_ERROR(status)) {
370 FreePool(buf);
371 return EIO;
372 }
373
374 for (entry = 0; entry < le32toh(hdr.hdr_entries); entry++) {
375 memcpy(&ent, buf + (entry * le32toh(hdr.hdr_entsz)),
376 sizeof(ent));
377 efi_block_find_partitions_gpt_entry(bdev, &hdr, &ent, entry);
378 }
379
380 FreePool(buf);
381
382 return 0;
383 }
384
385 static int
386 efi_block_find_partitions(struct efi_block_dev *bdev)
387 {
388 int error;
389
390 error = efi_block_find_partitions_gpt(bdev);
391 if (error)
392 error = efi_block_find_partitions_mbr(bdev);
393 if (error)
394 error = efi_block_find_partitions_cd9660(bdev);
395
396 return error;
397 }
398
399 void
400 efi_block_probe(void)
401 {
402 struct efi_block_dev *bdev;
403 struct efi_block_part *bpart;
404 EFI_BLOCK_IO *bio;
405 EFI_DISK_IO *dio;
406 EFI_STATUS status;
407 uint16_t devindex = 0;
408 int depth = -1;
409 int n;
410
411 status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &efi_nblock, &efi_block);
412 if (EFI_ERROR(status))
413 return;
414
415 if (efi_bootdp) {
416 depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
417 if (depth == 0)
418 depth = 1;
419 else if (depth == -1)
420 depth = 2;
421 }
422
423 for (n = 0; n < efi_nblock; n++) {
424 status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
425 &BlockIoProtocol, (void **)&bio);
426 if (EFI_ERROR(status) || !bio->Media->MediaPresent)
427 continue;
428
429 if (bio->Media->LogicalPartition)
430 continue;
431
432 status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n],
433 &DiskIoProtocol, (void **)&dio);
434 if (EFI_ERROR(status))
435 continue;
436
437 bdev = alloc(sizeof(*bdev));
438 bdev->index = devindex++;
439 bdev->bio = bio;
440 bdev->dio = dio;
441 bdev->media_id = bio->Media->MediaId;
442 bdev->path = DevicePathFromHandle(efi_block[n]);
443 TAILQ_INIT(&bdev->partitions);
444 TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries);
445
446 efi_block_find_partitions(bdev);
447
448 if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) {
449 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
450 uint8_t fstype = FS_UNUSED;
451 switch (bpart->type) {
452 case EFI_BLOCK_PART_DISKLABEL:
453 fstype = bpart->disklabel.part.p_fstype;
454 break;
455 case EFI_BLOCK_PART_GPT:
456 fstype = bpart->gpt.fstype;
457 break;
458 case EFI_BLOCK_PART_CD9660:
459 fstype = FS_ISO9660;
460 break;
461 }
462 if (fstype == FS_BSDFFS || fstype == FS_ISO9660 || fstype == FS_RAID) {
463 char devname[9];
464 snprintf(devname, sizeof(devname), "hd%u%c", bdev->index, bpart->index + 'a');
465 set_default_device(devname);
466 set_default_fstype(fstype);
467 break;
468 }
469 }
470 }
471 }
472 }
473
474 static void
475 print_guid(const uint8_t *guid)
476 {
477 const int index[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
478 int i;
479
480 for (i = 0; i < 16; i++) {
481 printf("%02x", guid[index[i]]);
482 if (i == 3 || i == 5 || i == 7 || i == 9)
483 printf("-");
484 }
485 }
486
487 void
488 efi_block_show(void)
489 {
490 struct efi_block_dev *bdev;
491 struct efi_block_part *bpart;
492 uint64_t size;
493 CHAR16 *path;
494
495 TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
496 printf("hd%u (", bdev->index);
497
498 /* Size in MB */
499 size = ((bdev->bio->Media->LastBlock + 1) * bdev->bio->Media->BlockSize) / (1024 * 1024);
500 if (size >= 10000)
501 printf("%"PRIu64" GB", size / 1024);
502 else
503 printf("%"PRIu64" MB", size);
504 printf("): ");
505
506 path = DevicePathToStr(bdev->path);
507 Print(L"%s", path);
508 FreePool(path);
509
510 printf("\n");
511
512 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
513 switch (bpart->type) {
514 case EFI_BLOCK_PART_DISKLABEL:
515 printf(" hd%u%c (", bdev->index, bpart->index + 'a');
516
517 /* Size in MB */
518 size = ((uint64_t)bpart->disklabel.secsize * bpart->disklabel.part.p_size) / (1024 * 1024);
519 if (size >= 10000)
520 printf("%"PRIu64" GB", size / 1024);
521 else
522 printf("%"PRIu64" MB", size);
523 printf("): ");
524
525 printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]);
526 break;
527 case EFI_BLOCK_PART_GPT:
528 printf(" hd%u%c ", bdev->index, bpart->index + 'a');
529
530 if (bpart->gpt.ent.ent_name[0] == 0x0000) {
531 printf("\"");
532 print_guid(bpart->gpt.ent.ent_guid);
533 printf("\"");
534 } else {
535 Print(L"\"%s\"", bpart->gpt.ent.ent_name);
536 }
537
538 /* Size in MB */
539 size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize;
540 size /= (1024 * 1024);
541 if (size >= 10000)
542 printf(" (%"PRIu64" GB): ", size / 1024);
543 else
544 printf(" (%"PRIu64" MB): ", size);
545
546 printf("%s\n", fstypenames[bpart->gpt.fstype]);
547 break;
548 case EFI_BLOCK_PART_CD9660:
549 printf(" hd%u%c %s\n", bdev->index, bpart->index + 'a', fstypenames[FS_ISO9660]);
550 break;
551 default:
552 break;
553 }
554 }
555 }
556 }
557
558 struct efi_block_part *
559 efi_block_boot_part(void)
560 {
561 return efi_block_booted;
562 }
563
564 int
565 efi_block_open(struct open_file *f, ...)
566 {
567 struct efi_block_part *bpart;
568 const char *fname;
569 char **file;
570 char *path;
571 va_list ap;
572 int rv, n;
573
574 va_start(ap, f);
575 fname = va_arg(ap, const char *);
576 file = va_arg(ap, char **);
577 va_end(ap);
578
579 rv = efi_block_parse(fname, &bpart, &path);
580 if (rv != 0)
581 return rv;
582
583 for (n = 0; n < ndevs; n++)
584 if (strcmp(DEV_NAME(&devsw[n]), "efiblock") == 0) {
585 f->f_dev = &devsw[n];
586 break;
587 }
588 if (n == ndevs)
589 return ENXIO;
590
591 f->f_devdata = bpart;
592
593 *file = path;
594
595 efi_block_booted = bpart;
596
597 return 0;
598 }
599
600 int
601 efi_block_close(struct open_file *f)
602 {
603 return 0;
604 }
605
606 int
607 efi_block_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
608 {
609 struct efi_block_part *bpart = devdata;
610 EFI_STATUS status;
611 UINT64 off;
612
613 if (rw != F_READ)
614 return EROFS;
615
616 efi_set_watchdog(EFI_BLOCK_TIMEOUT, EFI_BLOCK_TIMEOUT_CODE);
617
618 switch (bpart->type) {
619 case EFI_BLOCK_PART_DISKLABEL:
620 off = (dblk + bpart->disklabel.part.p_offset) * DEV_BSIZE;
621 break;
622 case EFI_BLOCK_PART_GPT:
623 off = (dblk + le64toh(bpart->gpt.ent.ent_lba_start)) * DEV_BSIZE;
624 break;
625 case EFI_BLOCK_PART_CD9660:
626 off = dblk * ISO_DEFAULT_BLOCK_SIZE;
627 break;
628 default:
629 return EINVAL;
630 }
631
632 status = efi_block_disk_read(bpart->bdev, off, buf, size);
633 if (EFI_ERROR(status))
634 return EIO;
635
636 *rsize = size;
637
638 return 0;
639 }
640
641 void
642 efi_block_set_readahead(bool onoff)
643 {
644 efi_ra_enable = onoff;
645 }
646