From 4d3c95f5ea7c737a21cd6b9c59435ee693b3f127 Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Thu, 19 Jul 2012 20:48:25 +0000 Subject: zfs: Add ZFS filesystem support U-Boot port is based on sources forked from GRUB-0.97 by Sun in 2004, which can be found here: http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/grub/grub-0.97/stage2/zfs-include/zfs.h Released by Sun for GRUB under the license: * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. GRUB official releases include ZFS in version: ftp://alpha.gnu.org/gnu/grub/grub-1.99~rc1.tar.gz And patched against GRUB Bazaar repository for ashift fixes (4KB HDDs) more conveniently found at github: https://github.com/pendor/grub-zfs/commit/e7b6ef3ac3b9685ac4c394c897b1d4221b7381f1 Signed-off-by: Jorgen Lundman --- common/Makefile | 1 + common/cmd_zfs.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 common/cmd_zfs.c (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 483eb4d..3d62775 100644 --- a/common/Makefile +++ b/common/Makefile @@ -162,6 +162,7 @@ endif COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o +COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o # others ifdef CONFIG_DDR_SPD diff --git a/common/cmd_zfs.c b/common/cmd_zfs.c new file mode 100644 index 0000000..a6ea2c07 --- /dev/null +++ b/common/cmd_zfs.c @@ -0,0 +1,236 @@ +/* + * + * ZFS filesystem porting to Uboot by + * Jorgen Lundman + * + * zfsfs support + * made from existing GRUB Sources by Sun, GNU and others. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_FS_TYPE_OFFSET 0x36 +#define DOS_FS32_TYPE_OFFSET 0x52 + +static int do_zfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *filename = NULL; + char *ep; + int dev; + unsigned long part = 1; + ulong addr = 0; + ulong part_length; + disk_partition_t info; + char buf[12]; + unsigned long count; + const char *addr_str; + struct zfs_file zfile; + struct device_s vdev; + + if (argc < 3) + return CMD_RET_USAGE; + + count = 0; + addr = simple_strtoul(argv[3], NULL, 16); + filename = getenv("bootfile"); + switch (argc) { + case 3: + addr_str = getenv("loadaddr"); + if (addr_str != NULL) + addr = simple_strtoul(addr_str, NULL, 16); + else + addr = CONFIG_SYS_LOAD_ADDR; + + break; + case 4: + break; + case 5: + filename = argv[4]; + break; + case 6: + filename = argv[4]; + count = simple_strtoul(argv[5], NULL, 16); + break; + + default: + return cmd_usage(cmdtp); + } + + if (!filename) { + puts("** No boot file defined **\n"); + return 1; + } + + dev = (int)simple_strtoul(argv[2], &ep, 16); + zfs_dev_desc = get_dev(argv[1], dev); + if (zfs_dev_desc == NULL) { + printf("** Block device %s %d not supported\n", argv[1], dev); + return 1; + } + + if (*ep) { + if (*ep != ':') { + puts("** Invalid boot device, use `dev[:part]' **\n"); + return 1; + } + part = simple_strtoul(++ep, NULL, 16); + } + + if (part != 0) { + if (get_partition_info(zfs_dev_desc, part, &info)) { + printf("** Bad partition %lu **\n", part); + return 1; + } + + if (strncmp((char *)info.type, BOOT_PART_TYPE, + strlen(BOOT_PART_TYPE)) != 0) { + printf("** Invalid partition type \"%s\" (expect \"" BOOT_PART_TYPE "\")\n", + info.type); + return 1; + } + printf("Loading file \"%s\" " + "from %s device %d:%lu %s\n", + filename, argv[1], dev, part, info.name); + } else { + printf("Loading file \"%s\" from %s device %d\n", + filename, argv[1], dev); + } + + part_length = zfs_set_blk_dev(zfs_dev_desc, part); + if (part_length == 0) { + printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part); + return 1; + } + + vdev.part_length = part_length; + + memset(&zfile, 0, sizeof(zfile)); + zfile.device = &vdev; + if (zfs_open(&zfile, filename)) { + printf("** File not found %s\n", filename); + return 1; + } + + if ((count < zfile.size) && (count != 0)) + zfile.size = (uint64_t)count; + + if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) { + printf("** Unable to read \"%s\" from %s %d:%lu **\n", + filename, argv[1], dev, part); + zfs_close(&zfile); + return 1; + } + + zfs_close(&zfile); + + /* Loading ok, update default load address */ + load_addr = addr; + + printf("%llu bytes read\n", zfile.size); + sprintf(buf, "%llX", zfile.size); + setenv("filesize", buf); + + return 0; +} + + +int zfs_print(const char *entry, const struct zfs_dirhook_info *data) +{ + printf("%s %s\n", + data->dir ? " " : " ", + entry); + return 0; /* 0 continue, 1 stop */ +} + + + +static int do_zfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + const char *filename = "/"; + int dev; + unsigned long part = 1; + char *ep; + int part_length; + struct device_s vdev; + + if (argc < 3) + return cmd_usage(cmdtp); + + dev = (int)simple_strtoul(argv[2], &ep, 16); + zfs_dev_desc = get_dev(argv[1], dev); + + if (zfs_dev_desc == NULL) { + printf("\n** Block device %s %d not supported\n", argv[1], dev); + return 1; + } + + if (*ep) { + if (*ep != ':') { + puts("\n** Invalid boot device, use `dev[:part]' **\n"); + return 1; + } + part = simple_strtoul(++ep, NULL, 16); + } + + if (argc == 4) + filename = argv[3]; + + part_length = zfs_set_blk_dev(zfs_dev_desc, part); + if (part_length == 0) { + printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part); + return 1; + } + + vdev.part_length = part_length; + + zfs_ls(&vdev, filename, + zfs_print); + + return 0; +} + + +U_BOOT_CMD(zfsls, 4, 1, do_zfs_ls, + "list files in a directory (default /)", + " [directory]\n" + " - list files from 'dev' on 'interface' in a '/DATASET/@/$dir/'"); + +U_BOOT_CMD(zfsload, 6, 0, do_zfs_load, + "load binary file from a ZFS filesystem", + " [addr] [filename] [bytes]\n" + " - load binary file '/DATASET/@/$dir/$file' from 'dev' on 'interface'\n" + " to address 'addr' from ZFS filesystem"); -- cgit v1.1