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