Index: sys/boot/Makefile.arm =================================================================== --- sys/boot/Makefile.arm +++ sys/boot/Makefile.arm @@ -4,4 +4,8 @@ SUBDIR+= fdt .endif +.if ${MK_ZFS} != "no" +SUBDIR+= zfs +.endif + SUBDIR+= efi uboot Index: sys/boot/arm/uboot/Makefile =================================================================== --- sys/boot/arm/uboot/Makefile +++ sys/boot/arm/uboot/Makefile @@ -38,6 +38,11 @@ .else LOADER_FDT_SUPPORT= no .endif +.if ${MK_ZFS} != "no" +LOADER_ZFS_SUPPORT= yes +.else +LOADER_ZFS_SUPPORT= no +.endif .if ${LOADER_DISK_SUPPORT} == "yes" CFLAGS+= -DLOADER_DISK_SUPPORT @@ -77,6 +82,14 @@ LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a .endif +.if ${LOADER_ZFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_ZFS_SUPPORT +LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a + +CFLAGS+= -I${.CURDIR}/../../zfs +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +.endif + CFLAGS+= -DNETIF_OPEN_CLOSE_ONCE .if ${MK_FORTH} != "no" @@ -114,8 +127,8 @@ # clang doesn't understand %D as a specifier to printf NO_WERROR.clang= -DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND} -LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} -lstand +DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBZFSBOOT} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBZFSBOOT} -lstand OBJS+= ${SRCS:N*.h:R:S/$/.o/g} Index: sys/boot/arm/uboot/conf.c =================================================================== --- sys/boot/arm/uboot/conf.c +++ sys/boot/arm/uboot/conf.c @@ -31,6 +31,9 @@ #include #include "bootstrap.h" #include "libuboot.h" +#if defined(LOADER_ZFS_SUPPORT) +#include +#endif #if defined(LOADER_NET_SUPPORT) #include "dev_net.h" @@ -43,10 +46,16 @@ #if defined(LOADER_NET_SUPPORT) &netdev, #endif +#if defined(LOADER_ZFS_SUPPORT) + &zfs_dev, +#endif NULL }; struct fs_ops *file_system[] = { +#if defined(LOADER_ZFS_SUPPORT) + &zfs_fsops, +#endif #if defined(LOADER_UFS_SUPPORT) &ufs_fsops, #endif Index: sys/boot/arm/uboot/version =================================================================== --- sys/boot/arm/uboot/version +++ sys/boot/arm/uboot/version @@ -3,6 +3,7 @@ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +1.3: ZFS support added 1.2: Extended with NAND FS support. 1.1: Flattened Device Tree blob support. 1.0: Added storage support. Booting from HDD, USB, etc. is now possible. Index: sys/boot/uboot/common/main.c =================================================================== --- sys/boot/uboot/common/main.c +++ sys/boot/uboot/common/main.c @@ -2,6 +2,7 @@ * Copyright (c) 2000 Benno Rice * Copyright (c) 2000 Stephane Potvin * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski + * Copyright (c) 2016 Vladimir Belian * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,30 +38,39 @@ #include "glue.h" #include "libuboot.h" +#ifdef LOADER_ZFS_SUPPORT +#include +#endif + #ifndef nitems #define nitems(x) (sizeof((x)) / sizeof((x)[0])) #endif -struct uboot_devdesc currdev; +#ifdef DEBUG +#define PRINT_DEBUG_INFO() do { \ + printf("signature:\n"); \ + printf(" version\t= %d\n", sig->version); \ + printf(" checksum\t= 0x%08x\n", sig->checksum); \ + printf(" sc entry\t= 0x%08x\n", sig->syscall); \ + printf("\naddresses info:\n"); \ + printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); \ + printf(" _edata = 0x%08x\n", (uint32_t)_edata); \ + printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); \ + printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); \ + printf(" __bss_start = 0x%08x\n", (uint32_t)__bss_start); \ + printf(" _end = 0x%08x\n", (uint32_t)_end); \ + printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); \ + printf(" uboot_heap_start = 0x%08x\n", (uint32_t)uboot_heap_start); \ + printf(" uboot_heap_end = 0x%08x\n", (uint32_t)uboot_heap_end); } while (0) +#else +#define PRINT_DEBUG_INFO() +#endif + struct arch_switch archsw; /* MI/MD interface boundary */ -int devs_no; uintptr_t uboot_heap_start; uintptr_t uboot_heap_end; -struct device_type { - const char *name; - int type; -} device_types[] = { - { "disk", DEV_TYP_STOR }, - { "ide", DEV_TYP_STOR | DT_STOR_IDE }, - { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, - { "sata", DEV_TYP_STOR | DT_STOR_SATA }, - { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, - { "usb", DEV_TYP_STOR | DT_STOR_USB }, - { "net", DEV_TYP_NET } -}; - extern char end[]; extern char bootprog_name[]; extern char bootprog_rev[]; @@ -78,31 +88,71 @@ extern int command_fdt_internal(int argc, char *argv[]); #endif +#ifdef LOADER_ZFS_SUPPORT +static uint64_t zfs_pools[UB_MAX_DEV]; + static void -dump_sig(struct api_signature *sig) +uboot_zfs_probe(void) { -#ifdef DEBUG - printf("signature:\n"); - printf(" version\t= %d\n", sig->version); - printf(" checksum\t= 0x%08x\n", sig->checksum); - printf(" sc entry\t= 0x%08x\n", sig->syscall); -#endif + char dname[SPECNAMELEN + 1]; + uint64_t id; + int p, n = 0, i = 0, maxp = 0; + + bzero(&zfs_pools, sizeof(zfs_pools)); + + while (ub_dev_get(DEV_TYP_STOR, &i) != NULL) { + snprintf(dname, sizeof(dname), "disk%d:", n++); + id = 0; + if (zfs_probe_dev(dname, &id) == 0) { + if (id == 0) + continue; + + /* skip pool guid duplicates if found */ + for (p = 0; (p < maxp) && (zfs_pools[p] != id); p++) ; + if (p < maxp) + continue; + + zfs_pools[maxp++] = id; + } + } } -static void -dump_addr_info(void) +static const char * +probe_zfs(const char *dstr) { -#ifdef DEBUG - printf("\naddresses info:\n"); - printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); - printf(" _edata = 0x%08x\n", (uint32_t)_edata); - printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); - printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); - printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); - printf(" _end = 0x%08x\n", (uint32_t)_end); - printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); -#endif + struct zfs_devdesc dev; + char *p = NULL, *buf; + int i, l; + + if ((dstr != NULL) && (strncasecmp(dstr, "zfs", 3) != 0)) + return (NULL); + + if ((dstr != NULL) && ((dstr = strchr(dstr, ' ')) != NULL)) + dstr++; + + for (i = 0; zfs_pools[i] != 0; i++) { + bzero(&dev, sizeof(dev)); + dev.d_dev = &zfs_dev; + dev.d_type = dev.d_dev->dv_type; + dev.pool_guid = zfs_pools[i]; + buf = zfs_fmtdev(&dev); + + p = strchr(buf, ':') + 1; + l = strcspn(p, ":/"); + if ((buf != NULL) && ((dstr == NULL) || (*dstr == '\0') || + ((l == strlen(dstr)) && (strncmp(dstr, p, l) == 0)))) + break; + buf = NULL; + } + if (buf != NULL) { + init_zfs_bootenv(buf); + return (zfs_fmtdev(&dev)); + } + printf("could not find %s zfs pool\n", + (((dstr == NULL) || (*dstr == '\0'))) ? "any" : dstr); + return (NULL); } +#endif static uint64_t memsize(struct sys_info *si, int flags) @@ -133,266 +183,204 @@ size = memsize(si, t[i]); if (size > 0) printf("%s: %juMB\n", ub_mem_type(t[i]), - (uintmax_t)(size / 1024 / 1024)); + (uintmax_t)(size / 1024 / 1024)); } } -static const char * -get_device_type(const char *devstr, int *devtype) +static struct devsw * +search_devsw(int type) { int i; - int namelen; - struct device_type *dt; - - if (devstr) { - for (i = 0; i < nitems(device_types); i++) { - dt = &device_types[i]; - namelen = strlen(dt->name); - if (strncmp(dt->name, devstr, namelen) == 0) { - *devtype = dt->type; - return (devstr + namelen); - } - } - printf("Unknown device type '%s'\n", devstr); - } - *devtype = -1; + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_type == type) + return (devsw[i]); return (NULL); } -static const char * -device_typename(int type) -{ - int i; - - for (i = 0; i < nitems(device_types); i++) - if (device_types[i].type == type) - return (device_types[i].name); - - return (""); -} - /* - * Parse a device string into type, unit, slice and partition numbers. A - * returned value of -1 for type indicates a search should be done for the - * first loadable device, otherwise a returned value of -1 for unit - * indicates a search should be done for the first loadable device of the - * given type. + * Parse a device string into unit, slice and partition numbers. * * The returned values for slice and partition are interpreted by * disk_open(). * - * Valid device strings: For device types: + * Valid device strings: * - * DEV_TYP_STOR, DEV_TYP_NET - * DEV_TYP_STOR, DEV_TYP_NET - * : DEV_TYP_STOR, DEV_TYP_NET - * : DEV_TYP_STOR - * :. DEV_TYP_STOR - * :. DEV_TYP_STOR - * - * For valid type names, see the device_types array, above. + * + * : + * : + * :. + * :. * * Slice numbers are 1-based. 0 is a wildcard. */ -static void -get_load_device(int *type, int *unit, int *slice, int *partition) +static int +decode_devstr(const char *dstr, int *unit, int *slice, int *partition) { - char *devstr; const char *p; char *endp; - *type = -1; - *unit = -1; - *slice = 0; - *partition = -1; - - devstr = ub_env_get("loaderdev"); - if (devstr == NULL) { - printf("U-Boot env: loaderdev not set, will probe all devices.\n"); - return; - } - printf("U-Boot env: loaderdev='%s'\n", devstr); - - p = get_device_type(devstr, type); - /* Ignore optional spaces after the device name. */ - while (*p == ' ') - p++; + while (*dstr == ' ') + dstr++; - /* Unknown device name, or a known name without unit number. */ - if ((*type == -1) || (*p == '\0')) { - return; + /* No unit number present. */ + if (*dstr == '\0') { + return (-1); } - /* Malformed unit number. */ - if (!isdigit(*p)) { - *type = -1; - return; - } + if (!isdigit(*dstr)) + return (0); - /* Guaranteed to extract a number from the string, as *p is a digit. */ - *unit = strtol(p, &endp, 10); - p = endp; + /* Guaranteed to extract a number from the string, as *dstr is a digit. */ + *unit = strtol(dstr, &endp, 10); + dstr = endp; - /* Known device name with unit number and nothing else. */ - if (*p == '\0') { - return; - } + /* Unit number and nothing else. */ + if (*dstr == '\0') + return (1); /* Device string is malformed beyond unit number. */ - if (*p != ':') { - *type = -1; - *unit = -1; - return; - } - - p++; + if (*dstr != ':') + return (0); + dstr++; /* No slice and partition specification. */ - if ('\0' == *p ) - return; + if (*dstr == '\0') + return (1); - /* Only DEV_TYP_STOR devices can have a slice specification. */ - if (!(*type & DEV_TYP_STOR)) { - *type = -1; - *unit = -1; - return; - } - - *slice = strtoul(p, &endp, 10); + *slice = strtoul(dstr, &endp, 10); /* Malformed slice number. */ - if (p == endp) { - *type = -1; - *unit = -1; - *slice = 0; - return; - } - - p = endp; + if (dstr == endp) + return (0); + dstr = endp; /* No partition specification. */ - if (*p == '\0') - return; + if (*dstr == '\0') + return (1); /* Device string is malformed beyond slice number. */ - if (*p != '.') { - *type = -1; - *unit = -1; - *slice = 0; - return; - } - - p++; + if (*dstr != '.') + return (0); + dstr++; /* No partition specification. */ - if (*p == '\0') - return; + if (*dstr == '\0') + return (1); - *partition = strtol(p, &endp, 10); - p = endp; + *partition = strtol(dstr, &endp, 10); - /* Full, valid device string. */ + /* Full, valid device string. */ if (*endp == '\0') - return; + return (1); /* Junk beyond partition number. */ - *type = -1; - *unit = -1; - *slice = 0; - *partition = -1; + return (0); } static void -print_disk_probe_info() +print_disk_probe_info(struct uboot_devdesc dev) { - char slice[32]; - char partition[32]; - if (currdev.d_disk.slice > 0) - sprintf(slice, "%d", currdev.d_disk.slice); - else - strcpy(slice, ""); + printf(" Checking unit=%d ", dev.d_unit); - if (currdev.d_disk.partition >= 0) - sprintf(partition, "%d", currdev.d_disk.partition); + if (dev.d_disk.slice > 0) + printf("slice=%d ", dev.d_disk.slice); else - strcpy(partition, ""); - - printf(" Checking unit=%d slice=%s partition=%s...", - currdev.d_unit, slice, partition); - + printf("slice= "); + if (dev.d_disk.partition >= 0) + printf("partition=%d...", dev.d_disk.partition); + else + printf("partition=..."); } -static int -probe_disks(int devidx, int load_type, int load_unit, int load_slice, - int load_partition) +static const char * +probe_disks(const char *dstr) { - int open_result, unit; + struct device_info *di; + struct uboot_devdesc dev; struct open_file f; - - currdev.d_disk.slice = load_slice; - currdev.d_disk.partition = load_partition; - - f.f_devdata = &currdev; - open_result = -1; - - if (load_type == -1) { - printf(" Probing all disk devices...\n"); - /* Try each disk in succession until one works. */ - for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; - currdev.d_unit++) { - print_disk_probe_info(); - open_result = devsw[devidx]->dv_open(&f, &currdev); - if (open_result == 0) { - printf(" good.\n"); - return (0); - } - printf("\n"); - } - return (-1); - } - - if (load_unit == -1) { - printf(" Probing all %s devices...\n", device_typename(load_type)); - /* Try each disk of given type in succession until one works. */ - for (unit = 0; unit < UB_MAX_DEV; unit++) { - currdev.d_unit = uboot_diskgetunit(load_type, unit); - if (currdev.d_unit == -1) + int stlist[] = { + DT_STOR_IDE, DT_STOR_SCSI, DT_STOR_USB, DT_STOR_MMC, + DT_STOR_SATA + }; + int type = DEV_TYP_STOR; + int nunits = 0, res = -1, valid = -1; + int i, v; + char *s; + + bzero(&dev, sizeof(dev)); + + if ((dev.d_dev = search_devsw(DEVT_DISK)) == NULL) + return (NULL); + + /* parse devstr if any */ + if (dstr != NULL) { + for (i = 0; i < nitems(stlist); i++) { + v = strlen(s = ub_stor_type(stlist[i])); + if (strncasecmp(dstr, s, v) == 0) { + type = stlist[i]; break; - print_disk_probe_info(); - open_result = devsw[devidx]->dv_open(&f, &currdev); - if (open_result == 0) { - printf(" good.\n"); - return (0); } - printf("\n"); } - return (-1); + /* if device type is none above may be it's genereal disk type */ + if ((strncasecmp(dstr, "disk", 4) != 0) && (type == DEV_TYP_STOR)) + return (NULL); + if ((res = decode_devstr(&dstr[v], &dev.d_unit, + &dev.d_disk.slice, &dev.d_disk.partition)) == 0) + return (NULL); } - - if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { - print_disk_probe_info(); - open_result = devsw[devidx]->dv_open(&f,&currdev); - if (open_result == 0) { + /* calculate real unit address, offset and number of units */ + for (v = i = 0; (di = ub_dev_get(DEV_TYP_STOR, &i)) != NULL; v++) + if ((di->type & type) && (nunits++ == dev.d_unit)) + valid = dev.d_unit += v; + if (valid == -1) + return (NULL); + + printf("Found U-Boot device: %s\n", dev.d_dev->dv_name); + dev.d_type = dev.d_dev->dv_type; + dev.d_disk.partition = -1; + f.f_devdata = &dev; + + /* probe only one device unit if unit number is specified */ + if (res > 0) + nunits = 1; + while (nunits--) { + print_disk_probe_info(dev); + if ((dev.d_dev)->dv_open(&f, &dev) == 0) { printf(" good.\n"); - return (0); + return (uboot_fmtdev(&dev)); } printf("\n"); + dev.d_unit++; } + return (NULL); +} - printf(" Requested disk type/unit/slice/partition not found\n"); - return (-1); +static const char * +probe_net(const char *dstr) +{ + struct uboot_devdesc dev; + int i; + + bzero(&dev, sizeof(dev)); + + if ((dstr != NULL) && (strncasecmp(dstr, "net", 3) != 0)) + return (NULL); + if ((dev.d_dev = search_devsw(DEVT_NET)) == NULL) + return (NULL); + dev.d_type = dev.d_dev->dv_type; + + return (uboot_fmtdev(&dev)); } int main(int argc, char **argv) { struct api_signature *sig = NULL; - int load_type, load_unit, load_slice, load_partition; - int i; - const char *ldev; + int i, devs_no; + const char *devstr, *ldev; /* * We first check if a command line argument was passed to us containing @@ -422,7 +410,11 @@ * alloc() is usable. The stack is buried inside us, so this is safe. */ uboot_heap_start = round_page((uintptr_t)end); +#ifndef LOADER_ZFS_SUPPORT uboot_heap_end = uboot_heap_start + 512 * 1024; +#else + uboot_heap_end = uboot_heap_start + 2 * 1024 * 1024; +#endif setheap((void *)uboot_heap_start, (void *)uboot_heap_end); /* @@ -436,11 +428,19 @@ printf("(%s, %s)\n", bootprog_maker, bootprog_date); printf("\n"); - dump_sig(sig); - dump_addr_info(); - + PRINT_DEBUG_INFO(); meminfo(); + archsw.arch_loadaddr = uboot_loadaddr; + archsw.arch_getdev = uboot_getdev; + archsw.arch_copyin = uboot_copyin; + archsw.arch_copyout = uboot_copyout; + archsw.arch_readin = uboot_readin; + archsw.arch_autoload = uboot_autoload; +#ifdef LOADER_ZFS_SUPPORT + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = uboot_zfs_probe; +#endif /* * Enumerate U-Boot devices */ @@ -448,74 +448,58 @@ panic("no U-Boot devices found"); printf("Number of U-Boot devices: %d\n", devs_no); - get_load_device(&load_type, &load_unit, &load_slice, &load_partition); + devstr = ub_env_get("loaderdev"); + if (devstr == NULL) + printf("U-Boot env: loaderdev not set, will probe all devices.\n"); + else + printf("U-Boot env: loaderdev='%s'\n", devstr); /* * March through the device switch probing for things. */ - for (i = 0; devsw[i] != NULL; i++) { - - if (devsw[i]->dv_init == NULL) - continue; - if ((devsw[i]->dv_init)() != 0) - continue; - - printf("Found U-Boot device: %s\n", devsw[i]->dv_name); - - currdev.d_dev = devsw[i]; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_unit = 0; + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); - if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && - strcmp(devsw[i]->dv_name, "disk") == 0) { - if (probe_disks(i, load_type, load_unit, load_slice, - load_partition) == 0) - break; - } - - if ((load_type == -1 || (load_type & DEV_TYP_NET)) && - strcmp(devsw[i]->dv_name, "net") == 0) + do { +#ifdef LOADER_ZFS_SUPPORT + if ((ldev = probe_zfs(devstr)) != NULL) + break; +#endif + if ((ldev = probe_disks(devstr)) != NULL) break; - } - /* - * If we couldn't find a boot device, return an error to u-boot. - * U-boot may be running a boot script that can try something different - * so returning an error is better than forcing a reboot. - */ - if (devsw[i] == NULL) { + if ((ldev = probe_net(devstr)) != NULL) + break; + /* + * If we couldn't find a boot device, return an error to u-boot. + * U-boot may be running a boot script that can try something + * different so returning an error is better than forcing a reboot. + */ printf("No boot device found!\n"); return (0xbadef1ce); - } + } while (0); + + printf("Booting from %s\n", ldev); - ldev = uboot_fmtdev(&currdev); env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); - printf("Booting from %s\n", ldev); setenv("LINES", "24", 1); /* optional */ setenv("prompt", "loader>", 1); - archsw.arch_loadaddr = uboot_loadaddr; - archsw.arch_getdev = uboot_getdev; - archsw.arch_copyin = uboot_copyin; - archsw.arch_copyout = uboot_copyout; - archsw.arch_readin = uboot_readin; - archsw.arch_autoload = uboot_autoload; - interact(NULL); /* doesn't return */ return (0); } - COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { printf("heap base at %p, top at %p, used %td\n", end, sbrk(0), - sbrk(0) - end); + sbrk(0) - end); return (CMD_OK); } @@ -536,16 +520,17 @@ static int command_devinfo(int argc, char *argv[]) { - int i; + struct device_info *di; + int i = 0; - if ((devs_no = ub_dev_enum()) == 0) { + if (ub_dev_enum() == 0) { command_errmsg = "no U-Boot devices found!?"; return (CMD_ERROR); } - printf("U-Boot devices:\n"); - for (i = 0; i < devs_no; i++) { - ub_dump_di(i); + while ((di = ub_dev_get(DEV_TYP_NET | DEV_TYP_STOR, &i)) != NULL) { + printf("device info (%d):\n", i - 1); + ub_dump_di(di); printf("\n"); } return (CMD_OK); @@ -561,7 +546,6 @@ command_errmsg = "could not retrieve U-Boot sys info!?"; return (CMD_ERROR); } - printf("U-Boot system info:\n"); ub_dump_si(si); return (CMD_OK); @@ -602,7 +586,6 @@ var = &var[len + 1]; } } - /* * If the user prepended "uboot." (which is how they usually see these * names) strip it off as a convenience. @@ -610,13 +593,11 @@ if (strncmp(var, "uboot.", 6) == 0) { var = &var[6]; } - /* If there is no variable name left, punt. */ if (var[0] == 0) { printf("empty variable name\n"); return; } - val = ub_env_get(var); if (action == UBENV_SHOW) { if (val == NULL) @@ -648,7 +629,6 @@ command_errmsg = "usage: 'ubenv [var ...]"; return (CMD_ERROR); } - if (argc > 2) { for (i = 2; i < argc; i++) handle_uboot_env_var(action, argv[i]); @@ -660,7 +640,6 @@ handle_uboot_env_var(action, var); } } - return (CMD_OK); } COMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); @@ -681,3 +660,54 @@ COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif + +#ifdef LOADER_ZFS_SUPPORT +COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", + command_lszfs); + +static int +command_lszfs(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + err = zfs_list(argv[1]); + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} + +COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", + command_reloadbe); + +static int +command_reloadbe(int argc, char *argv[]) +{ + int err; + char *root; + + if (argc > 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + if (argc == 2) { + err = zfs_bootenv(argv[1]); + } else { + root = getenv("zfs_be_root"); + if (root == NULL) { + return (CMD_OK); + } + err = zfs_bootenv(root); + } + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} +#endif Index: sys/boot/uboot/lib/Makefile =================================================================== --- sys/boot/uboot/lib/Makefile +++ sys/boot/uboot/lib/Makefile @@ -20,6 +20,19 @@ CFLAGS+= -DLOADER_DISK_SUPPORT .endif +.if ${MK_ZFS} != "no" +LOADER_ZFS_SUPPORT= yes + +CFLAGS+= -I${.CURDIR}/../../zfs +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +.else +LOADER_ZFS_SUPPORT= no +.endif + +.if ${LOADER_ZFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_ZFS_SUPPORT +.endif + .if ${MK_FDT} != "no" LOADER_FDT_SUPPORT= yes .else Index: sys/boot/uboot/lib/devicename.c =================================================================== --- sys/boot/uboot/lib/devicename.c +++ sys/boot/uboot/lib/devicename.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1998 Michael Smith + * Copyright (c) 2016 Vladimir Belian * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,13 +30,15 @@ #include #include +#ifdef LOADER_ZFS_SUPPORT +#include +#endif #include "bootstrap.h" #include "disk.h" #include "libuboot.h" -static int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, - const char **path); +static int uboot_parsedev(struct uboot_devdesc **, const char *, const char **); /* * Point (dev) at an allocated device specifier for the device matching the @@ -53,14 +56,13 @@ * device, go with the current device. */ if ((devspec == NULL) || (devspec[0] == '/') || - (strchr(devspec, ':') == NULL)) { + (strchr(devspec, ':') == NULL)) { - if (((rv = uboot_parsedev(dev, getenv("currdev"), NULL)) == 0) - && (path != NULL)) - *path = devspec; + rv = uboot_parsedev(dev, getenv("currdev"), NULL); + if ((rv == 0) && (path != NULL)) + *path = devspec; return(rv); } - /* * Try to parse the device name off the beginning of the devspec. */ @@ -82,101 +84,101 @@ * */ static int -uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, - const char **path) +uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, const char **path) { struct uboot_devdesc *idev; struct devsw *dv; - char *cp; const char *np; - int i, unit, err; + char *cp; + int i, err = 0; /* minimum length check */ if (strlen(devspec) < 2) return(EINVAL); /* look for a device that matches */ - for (i = 0, dv = NULL; devsw[i] != NULL; i++) { - if (!strncmp(devspec, devsw[i]->dv_name, - strlen(devsw[i]->dv_name))) { - dv = devsw[i]; + for (i = 0; devsw[i] != NULL; i++) { + dv = devsw[i]; + if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) break; - } } if (dv == NULL) - return(ENOENT); - idev = malloc(sizeof(struct uboot_devdesc)); - err = 0; - np = (devspec + strlen(dv->dv_name)); + return (ENOENT); + if ((idev = malloc(sizeof(struct uboot_devdesc))) == NULL) + return (ENOMEM); + + np = devspec + strlen(dv->dv_name); switch(dv->dv_type) { - case DEVT_NONE: +#ifdef LOADER_ZFS_SUPPORT + case DEVT_ZFS: + err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); break; - +#endif #ifdef LOADER_DISK_SUPPORT case DEVT_DISK: err = disk_parsedev((struct disk_devdesc *)idev, np, path); - if (err != 0) - goto fail; break; #endif - case DEVT_NET: - unit = 0; - + idev->d_unit = 0; if (*np && (*np != ':')) { - /* get unit number if present */ - unit = strtol(np, &cp, 0); + idev->d_unit = strtol(np, &cp, 0); if (cp == np) { - err = EUNIT; - goto fail; + idev->d_unit = -1; + err = EINVAL; + break; } } + else { + cp = (char *)np; + } if (*cp && (*cp != ':')) { err = EINVAL; - goto fail; + break; } - idev->d_unit = unit; - if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; - + case DEVT_NONE: + free(idev); + return (0); default: err = EINVAL; - goto fail; + } + if (err) { + free(idev); + return (err); } idev->d_dev = dv; idev->d_type = dv->dv_type; - if (dev == NULL) { - free(idev); - } else { + + if (dev != NULL) *dev = idev; - } - return (0); + else + free(idev); -fail: - free(idev); - return (err); + return (0); } - char * uboot_fmtdev(void *vdev) { struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev; - static char buf[128]; + static char buf[UB_MAXNAMELEN]; switch(dev->d_type) { +#ifdef LOADER_ZFS_SUPPORT + case DEVT_ZFS: + return (zfs_fmtdev(vdev)); +#endif case DEVT_NONE: strcpy(buf, "(no device)"); break; - case DEVT_DISK: #ifdef LOADER_DISK_SUPPORT return (disk_fmtdev(vdev)); #endif - case DEVT_NET: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; Index: sys/boot/uboot/lib/disk.c =================================================================== --- sys/boot/uboot/lib/disk.c +++ sys/boot/uboot/lib/disk.c @@ -2,6 +2,7 @@ * Copyright (c) 2008 Semihalf, Rafal Jaworowski * Copyright (c) 2009 Semihalf, Piotr Ziecik * Copyright (c) 2012 Andrey V. Elsukov + * Copyright (c) 2016 Vladimir Belian * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,24 +47,18 @@ #include "libuboot.h" #define stor_printf(fmt, args...) do { \ - printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ - printf(fmt, ##args); \ + printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ + printf(fmt, ##args); \ } while (0) #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ - printf(fmt,##args); } while (0) + printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif -static struct { - int opened; /* device is opened */ - int handle; /* storage device handle */ - int type; /* storage type */ - off_t blocks; /* block count */ - u_int bsize; /* block size */ -} stor_info[UB_MAX_DEV]; +static struct device_info *stor_info[UB_MAX_DEV]; #define SI(dev) (stor_info[(dev)->d_unit]) @@ -95,38 +90,19 @@ static int stor_init(void) { - struct device_info *di; - int i; + int i = 0; - if (devs_no == 0) { + if (ub_dev_enum() == 0) { printf("No U-Boot devices! Really enumerated?\n"); return (-1); } - - for (i = 0; i < devs_no; i++) { - di = ub_dev_get(i); - if ((di != NULL) && (di->type & DEV_TYP_STOR)) { - if (stor_info_no >= UB_MAX_DEV) { - printf("Too many storage devices: %d\n", - stor_info_no); - return (-1); - } - stor_info[stor_info_no].handle = i; - stor_info[stor_info_no].opened = 0; - stor_info[stor_info_no].type = di->type; - stor_info[stor_info_no].blocks = - di->di_stor.block_count; - stor_info[stor_info_no].bsize = - di->di_stor.block_size; - stor_info_no++; - } - } + while ((stor_info[stor_info_no++] = ub_dev_get(DEV_TYP_STOR, &i)) != NULL) ; + stor_info_no--; if (!stor_info_no) { debugf("No storage devices\n"); return (-1); } - debugf("storage devices found: %d\n", stor_info_no); return (0); } @@ -137,8 +113,9 @@ int i; for (i = 0; i < stor_info_no; i++) - if (stor_info[i].opened > 0) - ub_dev_close(stor_info[i].handle); + if (stor_info[i]->state == DEV_STA_OPEN) + ub_dev_close(stor_info[i]); + disk_cleanup(&uboot_storage); } @@ -150,18 +127,20 @@ daddr_t bcount; int err; + if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) + return (EIO); + if (rw != F_READ) { stor_printf("write attempt, operation not supported!\n"); return (EROFS); } - - if (size % SI(dev).bsize) { + if (size % SI(dev)->di_stor.block_size) { stor_printf("size=%zu not multiple of device " - "block size=%d\n", - size, SI(dev).bsize); + "block size=%d\n", + size, (int) SI(dev)->di_stor.block_size); return (EIO); } - bcount = size / SI(dev).bsize; + bcount = size / SI(dev)->di_stor.block_size; if (rsize) *rsize = 0; @@ -193,17 +172,16 @@ if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) return (EIO); - if (SI(dev).opened == 0) { - err = ub_dev_open(SI(dev).handle); + if (SI(dev)->state == DEV_STA_CLOSED) { + err = ub_dev_open(SI(dev)); if (err != 0) { stor_printf("device open failed with error=%d, " - "handle=%d\n", err, SI(dev).handle); + "unit=%d\n", err, dev->d_unit); return (ENXIO); } - SI(dev).opened++; } - return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, - SI(dev).bsize, 0)); + return (disk_open(dev, SI(dev)->di_stor.block_count * SI(dev)->di_stor.block_size, + SI(dev)->di_stor.block_size, 0)); } static int @@ -223,17 +201,15 @@ debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf); - err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size); + err = ub_dev_read(SI(dev), buf, size, blk, &real_size); if (err != 0) { stor_printf("read failed, error=%d\n", err); return (EIO); } - if (real_size != size) { stor_printf("real size != size\n"); err = EIO; } - return (err); } @@ -250,7 +226,7 @@ dev.d_slice = -1; dev.d_partition = -1; sprintf(line, "\tdisk%d (%s)\n", i, - ub_stor_type(SI(&dev).type)); + ub_stor_type(SI(&dev)->type)); pager_output(line); if (stor_opendev(&dev) == 0) { sprintf(line, "\tdisk%d", i); @@ -266,39 +242,19 @@ struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; + if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) + return (EIO); + switch (cmd) { case DIOCGSECTORSIZE: - *(u_int *)data = SI(dev).bsize; + *(u_int *)data = SI(dev)->di_stor.block_size; break; case DIOCGMEDIASIZE: - *(off_t *)data = SI(dev).bsize * SI(dev).blocks; + *(off_t *)data = + SI(dev)->di_stor.block_size * SI(dev)->di_stor.block_count; break; default: return (ENOTTY); } return (0); } - - -/* - * Return the device unit number for the given type and type-relative unit - * number. - */ -int -uboot_diskgetunit(int type, int type_unit) -{ - int local_type_unit; - int i; - - local_type_unit = 0; - for (i = 0; i < stor_info_no; i++) { - if ((stor_info[i].type & type) == type) { - if (local_type_unit == type_unit) { - return (i); - } - local_type_unit++; - } - } - - return (-1); -} Index: sys/boot/uboot/lib/glue.h =================================================================== --- sys/boot/uboot/lib/glue.h +++ sys/boot/uboot/lib/glue.h @@ -92,14 +92,14 @@ /* devices */ int ub_dev_enum(void); -int ub_dev_open(int); -int ub_dev_close(int); -int ub_dev_read(int, void *, lbasize_t, lbastart_t, lbasize_t *); -int ub_dev_send(int, void *, int); -int ub_dev_recv(int, void *, int, int *); -struct device_info *ub_dev_get(int); - -void ub_dump_di(int); +int ub_dev_open(struct device_info *); +int ub_dev_close(struct device_info *); +int ub_dev_read(struct device_info *, void *, lbasize_t, lbastart_t, lbasize_t *); +int ub_dev_send(struct device_info *, void *, int); +int ub_dev_recv(struct device_info *, void *, int, int *); +struct device_info *ub_dev_get(int, int *); + +void ub_dump_di(struct device_info *); void ub_dump_si(struct sys_info *); char *ub_mem_type(int); char *ub_stor_type(int); Index: sys/boot/uboot/lib/glue.c =================================================================== --- sys/boot/uboot/lib/glue.c +++ sys/boot/uboot/lib/glue.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski + * Copyright (c) 2016 Vladimir Belian * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -241,12 +242,20 @@ ***************************************************************************/ static struct device_info devices[UB_MAX_DEV]; +static int devs_num = -1; struct device_info * -ub_dev_get(int i) +ub_dev_get(int type, int *i) { - return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]); + if ((i == NULL) || (*i < 0)) + return (NULL); + + while (*i < devs_num) + if (devices[(*i)++].type & type) + return (&devices[*i - 1]); + + return (NULL); } /* @@ -259,30 +268,24 @@ ub_dev_enum(void) { struct device_info *di; - int n = 0; + + if (devs_num != -1) + return (devs_num); memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV); di = &devices[0]; - if (!syscall(API_DEV_ENUM, NULL, di)) - return (0); - - while (di->cookie != NULL) { - - if (++n >= UB_MAX_DEV) - break; + for (devs_num = 0; syscall(API_DEV_ENUM, NULL, di);) { + if ((di->cookie == NULL) || (++devs_num >= UB_MAX_DEV)) + return (devs_num); /* take another device_info */ di++; /* pass on the previous cookie */ - di->cookie = devices[n - 1].cookie; - - if (!syscall(API_DEV_ENUM, NULL, di)) - return (0); + di->cookie = devices[devs_num - 1].cookie; } - - return (n); + return (devs_num = 0); } /* @@ -291,82 +294,37 @@ * returns: 0 when OK, err otherwise */ int -ub_dev_open(int handle) +ub_dev_open(struct device_info *di) { - struct device_info *di; int err = 0; - if (handle < 0 || handle >= UB_MAX_DEV) - return (API_EINVAL); - - di = &devices[handle]; - if (!syscall(API_DEV_OPEN, &err, di)) - return (-1); - - return (err); + return ((!syscall(API_DEV_OPEN, &err, di)) ? -1 : err); } int -ub_dev_close(int handle) -{ - struct device_info *di; - - if (handle < 0 || handle >= UB_MAX_DEV) - return (API_EINVAL); - - di = &devices[handle]; - if (!syscall(API_DEV_CLOSE, NULL, di)) - return (-1); - - return (0); -} - -/* - * Validates device for read/write, it has to: - * - * - have sane handle - * - be opened - * - * returns: 0/1 accordingly - */ -static int -dev_valid(int handle) +ub_dev_close(struct device_info *di) { - if (handle < 0 || handle >= UB_MAX_DEV) - return (0); - - if (devices[handle].state != DEV_STA_OPEN) - return (0); - - return (1); + return ((!syscall(API_DEV_CLOSE, NULL, di)) ? -1 : 0); } static int -dev_stor_valid(int handle) +dev_valid(struct device_info *di, int type) { - if (!dev_valid(handle)) - return (0); - - if (!(devices[handle].type & DEV_TYP_STOR)) - return (0); - - return (1); + return (((di->state == DEV_STA_OPEN) && (di->type & type)) ? 1 : 0); } int -ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start, - lbasize_t *rlen) +ub_dev_read(struct device_info *di, void *buf, lbasize_t len, + lbastart_t start, lbasize_t *rlen) { - struct device_info *di; lbasize_t act_len; int err = 0; - if (!dev_stor_valid(handle)) + if (!dev_valid(di, DEV_TYP_STOR)) return (API_ENODEV); - di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len)) return (API_ESYSC); @@ -376,29 +334,14 @@ return (err); } -static int -dev_net_valid(int handle) -{ - - if (!dev_valid(handle)) - return (0); - - if (devices[handle].type != DEV_TYP_NET) - return (0); - - return (1); -} - int -ub_dev_recv(int handle, void *buf, int len, int *rlen) +ub_dev_recv(struct device_info *di, void *buf, int len, int *rlen) { - struct device_info *di; int err = 0, act_len; - if (!dev_net_valid(handle)) + if (!dev_valid(di, DEV_TYP_NET)) return (API_ENODEV); - di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len)) return (API_ESYSC); @@ -409,15 +352,13 @@ } int -ub_dev_send(int handle, void *buf, int len) +ub_dev_send(struct device_info *di, void *buf, int len) { - struct device_info *di; int err = 0; - if (!dev_net_valid(handle)) + if (!dev_valid(di, DEV_TYP_NET)) return (API_ENODEV); - di = &devices[handle]; if (!syscall(API_DEV_WRITE, &err, di, buf, &len)) return (API_ESYSC); @@ -463,12 +404,10 @@ } void -ub_dump_di(int handle) +ub_dump_di(struct device_info *di) { - struct device_info *di = ub_dev_get(handle); int i; - printf("device info (%d):\n", handle); printf(" cookie\t= 0x%p\n", di->cookie); printf(" type\t\t= 0x%08x\n", di->type); Index: sys/boot/uboot/lib/libuboot.h =================================================================== --- sys/boot/uboot/lib/libuboot.h +++ sys/boot/uboot/lib/libuboot.h @@ -49,6 +49,8 @@ */ #define PKTALIGN 32 +#define UB_MAXNAMELEN 128 + int uboot_getdev(void **vdev, const char *devspec, const char **path); char *uboot_fmtdev(void *vdev); int uboot_setcurrdev(struct env_var *ev, int flags, const void *value); @@ -72,6 +74,3 @@ extern struct file_format uboot_elf; void reboot(void); - -int uboot_diskgetunit(int type, int type_unit); - Index: sys/boot/uboot/lib/net.c =================================================================== --- sys/boot/uboot/lib/net.c +++ sys/boot/uboot/lib/net.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2000-2001 Benno Rice * Copyright (c) 2007 Semihalf, Rafal Jaworowski + * Copyright (c) 2016 Vladimir Belian * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -80,7 +81,7 @@ uint8_t sc_rxbuf[ETHER_MAX_LEN]; uint8_t sc_txbuf[ETHER_MAX_LEN + PKTALIGN]; uint8_t *sc_txbufp; - int sc_handle; /* device handle for ub_dev_xxx */ + struct device_info *sc_dinfo; /* device handle for ub_dev_xxx */ }; static struct uboot_softc uboot_softc; @@ -210,25 +211,16 @@ static int net_probe(struct netif *nif, void *machdep_hint) { - struct device_info *di; - int i; + int i = 0; - for (i = 0; i < devs_no; i++) - if ((di = ub_dev_get(i)) != NULL) - if (di->type == DEV_TYP_NET) - break; - - if (i == devs_no) { + if ((uboot_softc.sc_dinfo = ub_dev_get(DEV_TYP_NET, &i)) == NULL) printf("net_probe: no network devices found, maybe not" - " enumerated yet..?\n"); + " enumerated yet..?\n"); return (-1); - } #if defined(NETIF_DEBUG) - printf("net_probe: network device found: %d\n", i); + printf("net_probe: network device found: %d\n", i - 1); #endif - uboot_softc.sc_handle = i; - return (0); } @@ -258,7 +250,7 @@ memcpy(sc->sc_txbufp, pkt, len); - rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen); + rv = ub_dev_send(sc->sc_dinfo, sc->sc_txbufp, sendlen); #if defined(NETIF_DEBUG) printf("net_put: ub_send returned %d\n", rv); @@ -284,7 +276,7 @@ #endif t = getsecs(); do { - err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen); + err = ub_dev_recv(sc->sc_dinfo, sc->sc_rxbuf, len, &rlen); if (err != 0) { printf("net_get: ub_dev_recv() failed, error=%d\n", @@ -316,18 +308,16 @@ { struct netif *nif = desc->io_netif; struct uboot_softc *sc; - struct device_info *di; int err; sc = nif->nif_devdata = &uboot_softc; - if ((err = ub_dev_open(sc->sc_handle)) != 0) + if ((err = ub_dev_open(sc->sc_dinfo)) != 0) panic("%s%d: initialisation failed with error %d\n", nif->nif_driver->netif_bname, nif->nif_unit, err); /* Get MAC address */ - di = ub_dev_get(sc->sc_handle); - memcpy(desc->myea, di->di_net.hwaddr, 6); + memcpy(desc->myea, sc->sc_dinfo->di_net.hwaddr, 6); if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) { panic("%s%d: empty ethernet address!", nif->nif_driver->netif_bname, nif->nif_unit); @@ -356,7 +346,7 @@ struct uboot_softc *sc = nif->nif_devdata; int err; - if ((err = ub_dev_close(sc->sc_handle)) != 0) + if ((err = ub_dev_close(sc->sc_dinfo)) != 0) panic("%s%d: net_end failed with error %d\n", nif->nif_driver->netif_bname, nif->nif_unit, err); }