2 * Copyright (c) 2008 Semihalf, Rafal Jaworowski
3 * Copyright (c) 2009 Semihalf, Piotr Ziecik
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Block storage I/O routines for U-Boot
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/endian.h>
38 #include <sys/queue.h>
39 #include <netinet/in.h>
40 #include <machine/stdarg.h>
45 #include <sys/disklabel.h>
46 #include <sys/diskmbr.h>
49 #include "api_public.h"
50 #include "bootstrap.h"
57 #define stor_printf(fmt, args...) do { \
58 printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \
59 printf(fmt, ##args); \
63 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \
64 printf(fmt,##args); } while (0)
66 #define debugf(fmt, args...)
77 int od_bsize; /* block size */
78 int od_bstart; /* start block offset from beginning of disk */
81 struct disklabel bsdlabel;
84 struct gpt_part *gpt_partitions;
90 #define od_bsdlabel _data._bsd.bsdlabel
91 #define od_nparts _data._gpt.gpt_nparts
92 #define od_partitions _data._gpt.gpt_partitions
94 static uuid_t efi = GPT_ENT_TYPE_EFI;
95 static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
96 static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
97 static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
98 static uuid_t freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
99 static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
101 static int stor_info[UB_MAX_DEV];
102 static int stor_info_no = 0;
103 static int stor_opendev(struct open_dev **, struct uboot_devdesc *);
104 static int stor_closedev(struct uboot_devdesc *);
105 static int stor_readdev(struct uboot_devdesc *, daddr_t, size_t, char *);
106 static int stor_open_count = 0;
109 static int stor_init(void);
110 static int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *);
111 static int stor_open(struct open_file *, ...);
112 static int stor_close(struct open_file *);
113 static void stor_print(int);
115 struct devsw uboot_storage = {
127 uuid_letoh(uuid_t *uuid)
130 uuid->time_low = le32toh(uuid->time_low);
131 uuid->time_mid = le16toh(uuid->time_mid);
132 uuid->time_hi_and_version = le16toh(uuid->time_hi_and_version);
138 struct device_info *di;
142 printf("No U-Boot devices! Really enumerated?\n");
146 for (i = 0; i < devs_no; i++) {
148 if ((di != NULL) && (di->type & DEV_TYP_STOR)) {
149 if (stor_info_no >= UB_MAX_DEV) {
150 printf("Too many storage devices: %d\n",
154 stor_info[stor_info_no++] = i;
160 printf("No storage devices\n");
164 debugf("storage devices found: %d\n", stor_info_no);
169 stor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
172 struct uboot_devdesc *dev = (struct uboot_devdesc *)devdata;
173 struct open_dev *od = (struct open_dev *)dev->d_disk.data;
176 debugf("od=%p, size=%d, bsize=%d\n", od, size, od->od_bsize);
179 stor_printf("write attempt, operation not supported!\n");
183 if (size % od->od_bsize) {
184 stor_printf("size=%d not multiple of device block size=%d\n",
188 bcount = size / od->od_bsize;
193 err = stor_readdev(dev, blk + od->od_bstart, bcount, buf);
201 stor_open(struct open_file *f, ...)
205 struct uboot_devdesc *dev;
209 dev = va_arg(ap, struct uboot_devdesc *);
212 if ((err = stor_opendev(&od, dev)) != 0)
215 ((struct uboot_devdesc *)(f->f_devdata))->d_disk.data = od;
221 stor_close(struct open_file *f)
223 struct uboot_devdesc *dev;
225 dev = (struct uboot_devdesc *)(f->f_devdata);
227 return (stor_closedev(dev));
231 stor_open_gpt(struct open_dev *od, struct uboot_devdesc *dev)
234 struct dos_partition *dp;
237 daddr_t slba, lba, elba;
242 od->od_partitions = NULL;
244 /* Devices with block size smaller than 512 bytes cannot use GPT */
245 if (od->od_bsize < 512)
248 /* Allocate 1 block */
249 buf = malloc(od->od_bsize);
251 stor_printf("could not allocate memory for GPT\n");
256 err = stor_readdev(dev, 0, 1, buf);
258 stor_printf("GPT read error=%d\n", err);
263 /* Check the slice table magic. */
264 if (le16toh(*((uint16_t *)(buf + DOSMAGICOFFSET))) != DOSMAGIC) {
269 /* Check GPT slice */
270 dp = (struct dos_partition *)(buf + DOSPARTOFF);
273 for (i = 0; i < NDOSPART; i++) {
274 if (dp[i].dp_typ == 0xee)
276 else if (dp[i].dp_typ != 0x00) {
287 /* Read primary GPT header */
288 err = stor_readdev(dev, 1, 1, buf);
290 stor_printf("GPT read error=%d\n", err);
295 hdr = (struct gpt_hdr *)buf;
297 /* Check GPT header */
298 if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 ||
299 le64toh(hdr->hdr_lba_self) != 1 ||
300 le32toh(hdr->hdr_revision) < 0x00010000 ||
301 le32toh(hdr->hdr_entsz) < sizeof(*ent) ||
302 od->od_bsize % le32toh(hdr->hdr_entsz) != 0) {
303 debugf("Invalid GPT header!\n");
308 /* Count number of valid partitions */
310 eps = od->od_bsize / le32toh(hdr->hdr_entsz);
311 slba = le64toh(hdr->hdr_lba_table);
312 elba = slba + le32toh(hdr->hdr_entries) / eps;
314 for (lba = slba; lba < elba; lba++) {
315 err = stor_readdev(dev, lba, 1, buf);
317 stor_printf("GPT read error=%d\n", err);
322 ent = (struct gpt_ent *)buf;
324 for (i = 0; i < eps; i++) {
325 if (uuid_is_nil(&ent[i].ent_type, NULL) ||
326 le64toh(ent[i].ent_lba_start) == 0 ||
327 le64toh(ent[i].ent_lba_end) <
328 le64toh(ent[i].ent_lba_start))
335 /* Save information about partitions */
337 od->od_nparts = part;
338 od->od_partitions = malloc(part * sizeof(struct gpt_part));
339 if (!od->od_partitions) {
340 stor_printf("could not allocate memory for GPT\n");
346 for (lba = slba; lba < elba; lba++) {
347 err = stor_readdev(dev, lba, 1, buf);
349 stor_printf("GPT read error=%d\n", err);
354 ent = (struct gpt_ent *)buf;
356 for (i = 0; i < eps; i++) {
357 if (uuid_is_nil(&ent[i].ent_type, NULL) ||
358 le64toh(ent[i].ent_lba_start) == 0 ||
359 le64toh(ent[i].ent_lba_end) <
360 le64toh(ent[i].ent_lba_start))
363 od->od_partitions[part].gp_index = (lba - slba)
365 od->od_partitions[part].gp_type =
367 od->od_partitions[part].gp_start =
368 le64toh(ent[i].ent_lba_start);
369 od->od_partitions[part].gp_end =
370 le64toh(ent[i].ent_lba_end);
372 uuid_letoh(&od->od_partitions[part].gp_type);
378 dev->d_disk.ptype = PTYPE_GPT;
380 * If index of partition to open (dev->d_disk.pnum) is not defined
381 * we set it to the index of the first existing partition. This
382 * handles cases when only a disk device is specified (without full
383 * partition information) by the caller.
385 if ((od->od_nparts > 0) && (dev->d_disk.pnum == 0))
386 dev->d_disk.pnum = od->od_partitions[0].gp_index;
388 for (i = 0; i < od->od_nparts; i++)
389 if (od->od_partitions[i].gp_index == dev->d_disk.pnum)
390 od->od_bstart = od->od_partitions[i].gp_start;
393 if (err && od->od_partitions)
394 free(od->od_partitions);
401 stor_open_bsdlabel(struct open_dev *od, struct uboot_devdesc *dev)
404 struct disklabel *dl;
407 /* Allocate 1 block */
408 buf = malloc(od->od_bsize);
410 stor_printf("could not allocate memory for disklabel\n");
415 err = stor_readdev(dev, LABELSECTOR, 1, buf);
417 stor_printf("disklabel read error=%d\n", err);
421 bcopy(buf + LABELOFFSET, &od->od_bsdlabel, sizeof(struct disklabel));
422 dl = &od->od_bsdlabel;
424 if (dl->d_magic != DISKMAGIC) {
425 stor_printf("no disklabel magic!\n");
430 od->od_bstart = dl->d_partitions[dev->d_disk.pnum].p_offset;
431 dev->d_disk.ptype = PTYPE_BSDLABEL;
433 debugf("bstart=%d\n", od->od_bstart);
441 stor_readdev(struct uboot_devdesc *dev, daddr_t blk, size_t size, char *buf)
446 debugf("reading size=%d @ 0x%08x\n", size, (uint32_t)buf);
448 handle = stor_info[dev->d_unit];
449 err = ub_dev_read(handle, buf, size, blk, &real_size);
451 stor_printf("read failed, error=%d\n", err);
455 if (real_size != size) {
456 stor_printf("real size != size\n");
465 stor_opendev(struct open_dev **odp, struct uboot_devdesc *dev)
467 struct device_info *di;
471 h = stor_info[dev->d_unit];
473 debugf("refcount=%d\n", stor_open_count);
476 * There can be recursive open calls from the infrastructure, but at
477 * U-Boot level open the device only the first time.
479 if (stor_open_count > 0)
481 else if ((err = ub_dev_open(h)) != 0) {
482 stor_printf("device open failed with error=%d, handle=%d\n",
488 if ((di = ub_dev_get(h)) == NULL)
489 panic("could not retrieve U-Boot device_info, handle=%d", h);
491 if ((od = malloc(sizeof(struct open_dev))) == NULL) {
492 stor_printf("could not allocate memory for open_dev\n");
495 od->od_bsize = di->di_stor.block_size;
498 if ((err = stor_open_gpt(od, dev)) != 0)
499 err = stor_open_bsdlabel(od, dev);
512 stor_closedev(struct uboot_devdesc *dev)
517 od = (struct open_dev *)dev->d_disk.data;
518 if (dev->d_disk.ptype == PTYPE_GPT && od->od_nparts != 0)
519 free(od->od_partitions);
522 dev->d_disk.data = NULL;
524 if (--stor_open_count == 0) {
525 h = stor_info[dev->d_unit];
526 if ((err = ub_dev_close(h)) != 0) {
527 stor_printf("device close failed with error=%d, "
528 "handle=%d\n", err, h);
536 /* Given a size in 512 byte sectors, convert it to a human-readable number. */
537 /* XXX stolen from sys/boot/i386/libi386/biosdisk.c, should really be shared */
539 display_size(uint64_t size)
546 if (size >= 10485760000LL) {
549 } else if (size >= 10240000) {
552 } else if (size >= 10000) {
556 sprintf(buf, "%.6ld%cB", (long)size, unit);
561 stor_print_bsdlabel(struct uboot_devdesc *dev, char *prefix, int verbose)
563 char buf[512], line[80];
564 struct disklabel *dl;
569 err = stor_readdev(dev, LABELSECTOR, 1, buf);
571 sprintf(line, "%s%d: disklabel read error=%d\n",
572 dev->d_dev->dv_name, dev->d_unit, err);
576 dl = (struct disklabel *)buf;
578 if (dl->d_magic != DISKMAGIC) {
579 sprintf(line, "%s%d: no disklabel magic!\n",
580 dev->d_dev->dv_name, dev->d_unit);
585 /* Print partitions info */
586 for (i = 0; i < dl->d_npartitions; i++) {
587 if ((t = dl->d_partitions[i].p_fstype) < FSMAXTYPES) {
589 off = dl->d_partitions[i].p_offset;
590 size = dl->d_partitions[i].p_size;
591 if (fstypenames[t] == NULL || size == 0)
594 if ((('a' + i) == 'c') && (!verbose))
597 sprintf(line, " %s%c: %s %s (%d - %d)\n", prefix,
598 'a' + i, fstypenames[t], display_size(size),
607 stor_print_gpt(struct uboot_devdesc *dev, char *prefix, int verbose)
609 struct open_dev *od = (struct open_dev *)dev->d_disk.data;
615 for (i = 0; i < od->od_nparts; i++) {
616 gp = &od->od_partitions[i];
618 if (uuid_equal(&gp->gp_type, &efi, NULL))
620 else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
622 else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL))
624 else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL))
626 else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL))
628 else if (uuid_equal(&gp->gp_type, &freebsd_zfs, NULL))
633 sprintf(line, " %sp%u: %s %s (%lld - %lld)\n", prefix,
635 display_size(gp->gp_end + 1 - gp->gp_start), gp->gp_start,
643 stor_print_one(int i, struct device_info *di, int verbose)
645 struct uboot_devdesc dev;
649 sprintf(line, "\tdisk%d (%s)\n", i, ub_stor_type(di->type));
652 dev.d_dev = &uboot_storage;
654 dev.d_disk.pnum = -1;
655 dev.d_disk.data = NULL;
657 if (stor_opendev(&od, &dev) == 0) {
658 dev.d_disk.data = od;
660 if (dev.d_disk.ptype == PTYPE_GPT) {
661 sprintf(line, "\t\tdisk%d", i);
662 stor_print_gpt(&dev, line, verbose);
663 } else if (dev.d_disk.ptype == PTYPE_BSDLABEL) {
664 sprintf(line, "\t\tdisk%d", i);
665 stor_print_bsdlabel(&dev, line, verbose);
673 stor_print(int verbose)
675 struct device_info *di;
678 for (i = 0; i < stor_info_no; i++) {
679 di = ub_dev_get(stor_info[i]);
681 stor_print_one(i, di, verbose);