efiblock.c revision 1.10.6.1 1 /* $NetBSD: efiblock.c,v 1.10.6.1 2021/05/31 22:15:22 cjep 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 /*
42 * The raidframe support is basic. Ideally, it should be expanded to
43 * consider raid volumes a first-class citizen like the x86 efiboot does,
44 * but for now, we simply assume each RAID is potentially bootable.
45 */
46 #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */
47
48 static EFI_HANDLE *efi_block;
49 static UINTN efi_nblock;
50 static struct efi_block_part *efi_block_booted = NULL;
51
52 static TAILQ_HEAD(, efi_block_dev) efi_block_devs = TAILQ_HEAD_INITIALIZER(efi_block_devs);
53
54 static int
55 efi_block_parse(const char *fname, struct efi_block_part **pbpart, char **pfile)
56 {
57 struct efi_block_dev *bdev;
58 struct efi_block_part *bpart;
59 char pathbuf[PATH_MAX], *default_device, *ep = NULL;
60 const char *full_path;
61 intmax_t dev;
62 int part;
63
64 default_device = get_default_device();
65 if (strchr(fname, ':') == NULL) {
66 if (strlen(default_device) > 0) {
67 snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
68 full_path = pathbuf;
69 *pfile = __UNCONST(fname);
70 } else {
71 return EINVAL;
72 }
73 } else {
74 full_path = fname;
75 *pfile = strchr(fname, ':') + 1;
76 }
77
78 if (strncasecmp(full_path, "hd", 2) != 0)
79 return EINVAL;
80 dev = strtoimax(full_path + 2, &ep, 10);
81 if (dev < 0 || dev >= efi_nblock)
82 return ENXIO;
83 if (ep[0] < 'a' || ep[0] >= 'a' + MAXPARTITIONS || ep[1] != ':')
84 return EINVAL;
85 part = ep[0] - 'a';
86 TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
87 if (bdev->index == dev) {
88 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
89 if (bpart->index == part) {
90 *pbpart = bpart;
91 return 0;
92 }
93 }
94 }
95 }
96
97 return ENOENT;
98 }
99
100 static void
101 efi_block_generate_hash_mbr(struct efi_block_part *bpart, struct mbr_sector *mbr)
102 {
103 MD5_CTX md5ctx;
104
105 MD5Init(&md5ctx);
106 MD5Update(&md5ctx, (void *)mbr, sizeof(*mbr));
107 MD5Final(bpart->hash, &md5ctx);
108 }
109
110 static void *
111 efi_block_allocate_device_buffer(struct efi_block_dev *bdev, UINTN size,
112 void **buf_start)
113 {
114 void *buf;
115
116 if (bdev->bio->Media->IoAlign <= 1)
117 *buf_start = buf = AllocatePool(size);
118 else {
119 buf = AllocatePool(size + bdev->bio->Media->IoAlign - 1);
120 *buf_start = (buf == NULL) ? NULL :
121 (void *)roundup2((intptr_t)buf, bdev->bio->Media->IoAlign);
122 }
123
124 return buf;
125 }
126
127 static int
128 efi_block_find_partitions_cd9660(struct efi_block_dev *bdev)
129 {
130 struct efi_block_part *bpart;
131 struct iso_primary_descriptor *vd;
132 void *buf, *buf_start;
133 EFI_STATUS status;
134 EFI_LBA lba;
135 UINT32 sz;
136
137 if (bdev->bio->Media->BlockSize != DEV_BSIZE &&
138 bdev->bio->Media->BlockSize != ISO_DEFAULT_BLOCK_SIZE) {
139 return ENXIO;
140 }
141
142 sz = __MAX(sizeof(*vd), bdev->bio->Media->BlockSize);
143 sz = roundup(sz, bdev->bio->Media->BlockSize);
144 if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL) {
145 return ENOMEM;
146 }
147
148 for (lba = 16;; lba++) {
149 status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5,
150 bdev->bio,
151 bdev->media_id,
152 lba * ISO_DEFAULT_BLOCK_SIZE / bdev->bio->Media->BlockSize,
153 sz,
154 buf_start);
155 if (EFI_ERROR(status)) {
156 goto io_error;
157 }
158
159 vd = (struct iso_primary_descriptor *)buf_start;
160 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) {
161 goto io_error;
162 }
163 if (isonum_711(vd->type) == ISO_VD_END) {
164 goto io_error;
165 }
166 if (isonum_711(vd->type) == ISO_VD_PRIMARY) {
167 break;
168 }
169 }
170
171 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) {
172 goto io_error;
173 }
174
175 bpart = alloc(sizeof(*bpart));
176 bpart->index = 0;
177 bpart->bdev = bdev;
178 bpart->type = EFI_BLOCK_PART_CD9660;
179 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
180
181 FreePool(buf);
182 return 0;
183
184 io_error:
185 FreePool(buf);
186 return EIO;
187 }
188
189 static int
190 efi_block_find_partitions_disklabel(struct efi_block_dev *bdev, struct mbr_sector *mbr, uint32_t start, uint32_t size)
191 {
192 struct efi_block_part *bpart;
193 struct disklabel d;
194 struct partition *p;
195 EFI_STATUS status;
196 EFI_LBA lba;
197 void *buf, *buf_start;
198 UINT32 sz;
199 int n;
200
201 sz = __MAX(sizeof(d), bdev->bio->Media->BlockSize);
202 sz = roundup(sz, bdev->bio->Media->BlockSize);
203 if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
204 return ENOMEM;
205
206 lba = (((EFI_LBA)start + LABELSECTOR) * DEV_BSIZE) / bdev->bio->Media->BlockSize;
207 status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
208 lba, sz, buf_start);
209 if (EFI_ERROR(status) || getdisklabel(buf_start, &d) != NULL) {
210 FreePool(buf);
211 return EIO;
212 }
213 FreePool(buf);
214
215 if (le32toh(d.d_magic) != DISKMAGIC || le32toh(d.d_magic2) != DISKMAGIC)
216 return EINVAL;
217 if (le16toh(d.d_npartitions) > MAXPARTITIONS)
218 return EINVAL;
219
220 for (n = 0; n < le16toh(d.d_npartitions); n++) {
221 p = &d.d_partitions[n];
222 switch (p->p_fstype) {
223 case FS_BSDFFS:
224 case FS_MSDOS:
225 case FS_BSDLFS:
226 break;
227 case FS_RAID:
228 p->p_size -= RF_PROTECTED_SECTORS;
229 p->p_offset += RF_PROTECTED_SECTORS;
230 break;
231 default:
232 continue;
233 }
234
235 bpart = alloc(sizeof(*bpart));
236 bpart->index = n;
237 bpart->bdev = bdev;
238 bpart->type = EFI_BLOCK_PART_DISKLABEL;
239 bpart->disklabel.secsize = d.d_secsize;
240 bpart->disklabel.part = *p;
241 efi_block_generate_hash_mbr(bpart, mbr);
242 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
243 }
244
245 return 0;
246 }
247
248 static int
249 efi_block_find_partitions_mbr(struct efi_block_dev *bdev)
250 {
251 struct mbr_sector mbr;
252 struct mbr_partition *mbr_part;
253 EFI_STATUS status;
254 void *buf, *buf_start;
255 UINT32 sz;
256 int n;
257
258 sz = __MAX(sizeof(mbr), bdev->bio->Media->BlockSize);
259 sz = roundup(sz, bdev->bio->Media->BlockSize);
260 if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
261 return ENOMEM;
262
263 status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
264 0, sz, buf_start);
265 if (EFI_ERROR(status)) {
266 FreePool(buf);
267 return EIO;
268 }
269 memcpy(&mbr, buf_start, sizeof(mbr));
270 FreePool(buf);
271
272 if (le32toh(mbr.mbr_magic) != MBR_MAGIC)
273 return ENOENT;
274
275 for (n = 0; n < MBR_PART_COUNT; n++) {
276 mbr_part = &mbr.mbr_parts[n];
277 if (le32toh(mbr_part->mbrp_size) == 0)
278 continue;
279 if (mbr_part->mbrp_type == MBR_PTYPE_NETBSD) {
280 efi_block_find_partitions_disklabel(bdev, &mbr, le32toh(mbr_part->mbrp_start), le32toh(mbr_part->mbrp_size));
281 break;
282 }
283 }
284
285 return 0;
286 }
287
288 static const struct {
289 struct uuid guid;
290 uint8_t fstype;
291 } gpt_guid_to_str[] = {
292 { GPT_ENT_TYPE_NETBSD_FFS, FS_BSDFFS },
293 { GPT_ENT_TYPE_NETBSD_LFS, FS_BSDLFS },
294 { GPT_ENT_TYPE_NETBSD_RAIDFRAME, FS_RAID },
295 { GPT_ENT_TYPE_NETBSD_CCD, FS_CCD },
296 { GPT_ENT_TYPE_NETBSD_CGD, FS_CGD },
297 { GPT_ENT_TYPE_MS_BASIC_DATA, FS_MSDOS }, /* or NTFS? ambiguous */
298 { GPT_ENT_TYPE_EFI, FS_MSDOS },
299 };
300
301 static int
302 efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev, struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index)
303 {
304 struct efi_block_part *bpart;
305 uint8_t fstype = FS_UNUSED;
306 struct uuid uuid;
307 int n;
308
309 memcpy(&uuid, ent->ent_type, sizeof(uuid));
310 for (n = 0; n < __arraycount(gpt_guid_to_str); n++)
311 if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid, sizeof(ent->ent_type)) == 0) {
312 fstype = gpt_guid_to_str[n].fstype;
313 break;
314 }
315 if (fstype == FS_UNUSED)
316 return 0;
317
318 bpart = alloc(sizeof(*bpart));
319 bpart->index = index;
320 bpart->bdev = bdev;
321 bpart->type = EFI_BLOCK_PART_GPT;
322 bpart->gpt.fstype = fstype;
323 bpart->gpt.ent = *ent;
324 if (fstype == FS_RAID) {
325 bpart->gpt.ent.ent_lba_start += RF_PROTECTED_SECTORS;
326 bpart->gpt.ent.ent_lba_end -= RF_PROTECTED_SECTORS;
327 }
328 memcpy(bpart->hash, ent->ent_guid, sizeof(bpart->hash));
329 TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries);
330
331 return 0;
332 }
333
334 static int
335 efi_block_find_partitions_gpt(struct efi_block_dev *bdev)
336 {
337 struct gpt_hdr hdr;
338 struct gpt_ent ent;
339 EFI_STATUS status;
340 void *buf, *buf_start;
341 UINT32 sz, entry;
342
343 sz = __MAX(sizeof(hdr), bdev->bio->Media->BlockSize);
344 sz = roundup(sz, bdev->bio->Media->BlockSize);
345 if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
346 return ENOMEM;
347
348 status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
349 GPT_HDR_BLKNO, sz, buf_start);
350 if (EFI_ERROR(status)) {
351 FreePool(buf);
352 return EIO;
353 }
354 memcpy(&hdr, buf_start, sizeof(hdr));
355 FreePool(buf);
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 = __MAX(le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries), bdev->bio->Media->BlockSize);
363 sz = roundup(sz, bdev->bio->Media->BlockSize);
364 if ((buf = efi_block_allocate_device_buffer(bdev, sz, &buf_start)) == NULL)
365 return ENOMEM;
366
367 status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id,
368 le64toh(hdr.hdr_lba_table), sz, buf_start);
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_start + (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_STATUS status;
406 uint16_t devindex = 0;
407 int depth = -1;
408 int n;
409
410 status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &efi_nblock, &efi_block);
411 if (EFI_ERROR(status))
412 return;
413
414 if (efi_bootdp) {
415 depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
416 if (depth == 0)
417 depth = 1;
418 else if (depth == -1)
419 depth = 2;
420 }
421
422 for (n = 0; n < efi_nblock; n++) {
423 status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_block[n], &BlockIoProtocol, (void **)&bio);
424 if (EFI_ERROR(status) || !bio->Media->MediaPresent)
425 continue;
426
427 if (bio->Media->LogicalPartition)
428 continue;
429
430 bdev = alloc(sizeof(*bdev));
431 bdev->index = devindex++;
432 bdev->bio = bio;
433 bdev->media_id = bio->Media->MediaId;
434 bdev->path = DevicePathFromHandle(efi_block[n]);
435 TAILQ_INIT(&bdev->partitions);
436 TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries);
437
438 efi_block_find_partitions(bdev);
439
440 if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) {
441 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
442 uint8_t fstype = FS_UNUSED;
443 switch (bpart->type) {
444 case EFI_BLOCK_PART_DISKLABEL:
445 fstype = bpart->disklabel.part.p_fstype;
446 break;
447 case EFI_BLOCK_PART_GPT:
448 fstype = bpart->gpt.fstype;
449 break;
450 case EFI_BLOCK_PART_CD9660:
451 fstype = FS_ISO9660;
452 break;
453 }
454 if (fstype == FS_BSDFFS || fstype == FS_ISO9660 || fstype == FS_RAID) {
455 char devname[9];
456 snprintf(devname, sizeof(devname), "hd%u%c", bdev->index, bpart->index + 'a');
457 set_default_device(devname);
458 set_default_fstype(fstype);
459 break;
460 }
461 }
462 }
463 }
464 }
465
466 static void
467 print_guid(const uint8_t *guid)
468 {
469 const int index[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
470 int i;
471
472 for (i = 0; i < 16; i++) {
473 printf("%02x", guid[index[i]]);
474 if (i == 3 || i == 5 || i == 7 || i == 9)
475 printf("-");
476 }
477 }
478
479 void
480 efi_block_show(void)
481 {
482 struct efi_block_dev *bdev;
483 struct efi_block_part *bpart;
484 uint64_t size;
485 CHAR16 *path;
486
487 TAILQ_FOREACH(bdev, &efi_block_devs, entries) {
488 printf("hd%u (", bdev->index);
489
490 /* Size in MB */
491 size = ((bdev->bio->Media->LastBlock + 1) * bdev->bio->Media->BlockSize) / (1024 * 1024);
492 if (size >= 10000)
493 printf("%"PRIu64" GB", size / 1024);
494 else
495 printf("%"PRIu64" MB", size);
496 printf("): ");
497
498 path = DevicePathToStr(bdev->path);
499 Print(L"%s", path);
500 FreePool(path);
501
502 printf("\n");
503
504 TAILQ_FOREACH(bpart, &bdev->partitions, entries) {
505 switch (bpart->type) {
506 case EFI_BLOCK_PART_DISKLABEL:
507 printf(" hd%u%c (", bdev->index, bpart->index + 'a');
508
509 /* Size in MB */
510 size = ((uint64_t)bpart->disklabel.secsize * bpart->disklabel.part.p_size) / (1024 * 1024);
511 if (size >= 10000)
512 printf("%"PRIu64" GB", size / 1024);
513 else
514 printf("%"PRIu64" MB", size);
515 printf("): ");
516
517 printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]);
518 break;
519 case EFI_BLOCK_PART_GPT:
520 printf(" hd%u%c ", bdev->index, bpart->index + 'a');
521
522 if (bpart->gpt.ent.ent_name[0] == 0x0000) {
523 printf("\"");
524 print_guid(bpart->gpt.ent.ent_guid);
525 printf("\"");
526 } else {
527 Print(L"\"%s\"", bpart->gpt.ent.ent_name);
528 }
529
530 /* Size in MB */
531 size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize;
532 size /= (1024 * 1024);
533 if (size >= 10000)
534 printf(" (%"PRIu64" GB): ", size / 1024);
535 else
536 printf(" (%"PRIu64" MB): ", size);
537
538 printf("%s\n", fstypenames[bpart->gpt.fstype]);
539 break;
540 case EFI_BLOCK_PART_CD9660:
541 printf(" hd%u%c %s\n", bdev->index, bpart->index + 'a', fstypenames[FS_ISO9660]);
542 break;
543 default:
544 break;
545 }
546 }
547 }
548 }
549
550 struct efi_block_part *
551 efi_block_boot_part(void)
552 {
553 return efi_block_booted;
554 }
555
556 int
557 efi_block_open(struct open_file *f, ...)
558 {
559 struct efi_block_part *bpart;
560 const char *fname;
561 char **file;
562 char *path;
563 va_list ap;
564 int rv, n;
565
566 va_start(ap, f);
567 fname = va_arg(ap, const char *);
568 file = va_arg(ap, char **);
569 va_end(ap);
570
571 rv = efi_block_parse(fname, &bpart, &path);
572 if (rv != 0)
573 return rv;
574
575 for (n = 0; n < ndevs; n++)
576 if (strcmp(DEV_NAME(&devsw[n]), "efiblock") == 0) {
577 f->f_dev = &devsw[n];
578 break;
579 }
580 if (n == ndevs)
581 return ENXIO;
582
583 f->f_devdata = bpart;
584
585 *file = path;
586
587 efi_block_booted = bpart;
588
589 return 0;
590 }
591
592 int
593 efi_block_close(struct open_file *f)
594 {
595 return 0;
596 }
597
598 int
599 efi_block_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
600 {
601 struct efi_block_part *bpart = devdata;
602 EFI_STATUS status;
603 void *allocated_buf, *aligned_buf;
604
605 if (rw != F_READ)
606 return EROFS;
607
608 switch (bpart->type) {
609 case EFI_BLOCK_PART_DISKLABEL:
610 if (bpart->bdev->bio->Media->BlockSize != bpart->disklabel.secsize) {
611 printf("%s: unsupported block size %d (expected %d)\n", __func__,
612 bpart->bdev->bio->Media->BlockSize, bpart->disklabel.secsize);
613 return EIO;
614 }
615 dblk += bpart->disklabel.part.p_offset;
616 break;
617 case EFI_BLOCK_PART_GPT:
618 if (bpart->bdev->bio->Media->BlockSize != DEV_BSIZE) {
619 printf("%s: unsupported block size %d (expected %d)\n", __func__,
620 bpart->bdev->bio->Media->BlockSize, DEV_BSIZE);
621 return EIO;
622 }
623 dblk += le64toh(bpart->gpt.ent.ent_lba_start);
624 break;
625 case EFI_BLOCK_PART_CD9660:
626 dblk *= ISO_DEFAULT_BLOCK_SIZE / bpart->bdev->bio->Media->BlockSize;
627 break;
628 default:
629 return EINVAL;
630 }
631
632 if ((bpart->bdev->bio->Media->IoAlign <= 1) ||
633 ((intptr_t)buf & (bpart->bdev->bio->Media->IoAlign - 1)) == 0) {
634 allocated_buf = NULL;
635 aligned_buf = buf;
636 } else if ((allocated_buf = efi_block_allocate_device_buffer(bpart->bdev,
637 size, &aligned_buf)) == NULL) {
638 return ENOMEM;
639 }
640
641 status = uefi_call_wrapper(bpart->bdev->bio->ReadBlocks, 5,
642 bpart->bdev->bio, bpart->bdev->media_id, dblk, size, aligned_buf);
643 if (EFI_ERROR(status)) {
644 if (allocated_buf != NULL)
645 FreePool(allocated_buf);
646 return EIO;
647 }
648 if (allocated_buf != NULL) {
649 memcpy(buf, aligned_buf, size);
650 FreePool(allocated_buf);
651 }
652
653 *rsize = size;
654
655 return 0;
656 }
657