1 /* 2 * 3 * ZFS filesystem porting to Uboot by 4 * Jorgen Lundman <lundman at lundman.net> 5 * 6 * zfsfs support 7 * made from existing GRUB Sources by Sun, GNU and others. 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <part.h> 14 #include <config.h> 15 #include <command.h> 16 #include <image.h> 17 #include <linux/ctype.h> 18 #include <asm/byteorder.h> 19 #include <zfs_common.h> 20 #include <linux/stat.h> 21 #include <malloc.h> 22 23 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 24 #include <usb.h> 25 #endif 26 27 #if !CONFIG_IS_ENABLED(DOS_PARTITION) && !CONFIG_IS_ENABLED(EFI_PARTITION) 28 #error DOS or EFI partition support must be selected 29 #endif 30 31 #define DOS_PART_MAGIC_OFFSET 0x1fe 32 #define DOS_FS_TYPE_OFFSET 0x36 33 #define DOS_FS32_TYPE_OFFSET 0x52 34 35 static int do_zfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 36 { 37 char *filename = NULL; 38 int dev; 39 int part; 40 ulong addr = 0; 41 disk_partition_t info; 42 struct blk_desc *dev_desc; 43 char buf[12]; 44 unsigned long count; 45 const char *addr_str; 46 struct zfs_file zfile; 47 struct device_s vdev; 48 49 if (argc < 3) 50 return CMD_RET_USAGE; 51 52 count = 0; 53 addr = simple_strtoul(argv[3], NULL, 16); 54 filename = getenv("bootfile"); 55 switch (argc) { 56 case 3: 57 addr_str = getenv("loadaddr"); 58 if (addr_str != NULL) 59 addr = simple_strtoul(addr_str, NULL, 16); 60 else 61 addr = CONFIG_SYS_LOAD_ADDR; 62 63 break; 64 case 4: 65 break; 66 case 5: 67 filename = argv[4]; 68 break; 69 case 6: 70 filename = argv[4]; 71 count = simple_strtoul(argv[5], NULL, 16); 72 break; 73 74 default: 75 return cmd_usage(cmdtp); 76 } 77 78 if (!filename) { 79 puts("** No boot file defined **\n"); 80 return 1; 81 } 82 83 part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); 84 if (part < 0) 85 return 1; 86 87 dev = dev_desc->devnum; 88 printf("Loading file \"%s\" from %s device %d%c%c\n", 89 filename, argv[1], dev, 90 part ? ':' : ' ', part ? part + '0' : ' '); 91 92 zfs_set_blk_dev(dev_desc, &info); 93 vdev.part_length = info.size; 94 95 memset(&zfile, 0, sizeof(zfile)); 96 zfile.device = &vdev; 97 if (zfs_open(&zfile, filename)) { 98 printf("** File not found %s **\n", filename); 99 return 1; 100 } 101 102 if ((count < zfile.size) && (count != 0)) 103 zfile.size = (uint64_t)count; 104 105 if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) { 106 printf("** Unable to read \"%s\" from %s %d:%d **\n", 107 filename, argv[1], dev, part); 108 zfs_close(&zfile); 109 return 1; 110 } 111 112 zfs_close(&zfile); 113 114 /* Loading ok, update default load address */ 115 load_addr = addr; 116 117 printf("%llu bytes read\n", zfile.size); 118 setenv_hex("filesize", zfile.size); 119 120 return 0; 121 } 122 123 124 int zfs_print(const char *entry, const struct zfs_dirhook_info *data) 125 { 126 printf("%s %s\n", 127 data->dir ? "<DIR> " : " ", 128 entry); 129 return 0; /* 0 continue, 1 stop */ 130 } 131 132 133 134 static int do_zfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 135 { 136 const char *filename = "/"; 137 int part; 138 struct blk_desc *dev_desc; 139 disk_partition_t info; 140 struct device_s vdev; 141 142 if (argc < 2) 143 return cmd_usage(cmdtp); 144 145 if (argc == 4) 146 filename = argv[3]; 147 148 part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); 149 if (part < 0) 150 return 1; 151 152 zfs_set_blk_dev(dev_desc, &info); 153 vdev.part_length = info.size; 154 155 zfs_ls(&vdev, filename, 156 zfs_print); 157 158 return 0; 159 } 160 161 162 U_BOOT_CMD(zfsls, 4, 1, do_zfs_ls, 163 "list files in a directory (default /)", 164 "<interface> <dev[:part]> [directory]\n" 165 " - list files from 'dev' on 'interface' in a '/DATASET/@/$dir/'"); 166 167 U_BOOT_CMD(zfsload, 6, 0, do_zfs_load, 168 "load binary file from a ZFS filesystem", 169 "<interface> <dev[:part]> [addr] [filename] [bytes]\n" 170 " - load binary file '/DATASET/@/$dir/$file' from 'dev' on 'interface'\n" 171 " to address 'addr' from ZFS filesystem"); 172